乐趣区

7. java 内部类

基本概念
可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。
广泛意义上的内部类一般来说包括这四种:

成员内部类
局部内部类
静态内部类
匿名内部类

成员内部类
成员内部类是最普通的内部类,它的定义为位于另一个类的内部,形如下面的形式:
public class testDemo {
public static void main(String[] args ) {
Outer t = new Outer();
Outer.Inner in = t.new Inner(); // 必须先有外部类对象,才能创建内部类
t.fun();
in.print();
}
}

class Outer {// 外部类
private String msg = “hello world”;

public void fun(){
Inner in = new Inner();
System.out.println(in.info); // 外部类直接访问内部类的私有属性
}

class Inner{// 定义了一个成员内部类
private String info = “ 世界,你好!”;
public void print(){
System.out.println(msg); // 内部类直接访问外部类的 private 属性
}
}

}
成员内部类可以无条件访问外部类的所有属性和方法(包括 private 成员和静态成员)。外部类也可以直接访问内部类的所有属性和方法。
成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象
在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问。
不过要注意的是,当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类.this. 成员变量
外部类.this. 成员方法
局部内部类
局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的作用域仅限于方法内或者该作用域内。
public class testDemo {
public static void main(String[] args ) {
new Outer().fun();
}
}
class Outer {// 外部类
private String msg = “hello world”;
public void fun(){
class Inner{// 在方法中定义了一个局部内部类
public void print(){
System.out.println(Outer.this.msg); // 直接访问外部类的 private 属性
}
}
new Inner().print();
}
}
注意: 局部内部类就像是方法里面的一个局部变量一样。
在 jdk1.7 或之前的版本,如果局部内部类要访问方法中定义的参数、局部变量,那么参数和变量前一定要加上 ”final” 修饰符。jdk1.8 以及更新的版本则没有这个限制。
public class testDemo {
public static void main(String[] args ) {
new Outer().fun(100);
}
}

class Outer {// 外部类

private String msg = “hello world”;

public void fun(final int num){
final double score = 99.9;
class Inner{// 在方法中定义了一个局部内部类
public void print(){
System.out.println(“ 属性:”+Outer.this.msg); // 直接访问外部类的 private 属性
System.out.println(“ 方法参数 ”+ num);
System.out.println(“ 方法局部变量 ”+ score);
}
}
new Inner().print();
}

}
静态内部类
使用 static 修饰的成员内部类叫静态内部类。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能访问外部类的非 static 成员变量或者方法。
public class testDemo {
public static void main(String[] args ) {
Outer.Inner in = new Outer.Inner(); // 静态内部类可以使用 ” 外部类. 内部类 ” 的方式使用
in.print();
}
}

class Outer {// 外部类

static class Inner{// 定义了一个静态内部类
private String info = “ 世界,你好!”;
public void print(){
System.out.println(info);
}
}

}
匿名内部类
当某个子类只使用唯一一次的时候,没有必要单独定义出来,可以使用匿名内部类的方法简化代码。
匿名内部类就是没有名字的局部内部类。创建格式如下:
new 父类构造器(参数列表)| 要实现的接口 () {
// 匿名内部类的类体部分
//….
}
匿名内部类是在抽象类和接口的基础上发展而来的,其最大的好处是帮助减少了类的定义。
在使用匿名内部类的过程中,我们需要注意如下几点:

使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口。
匿名内部类中是不能定义构造函数的。
匿名内部类中不能存在任何的静态成员变量和静态方法。
匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。
匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
当所在的方法的形参需要被内部类里面使用时,该形参必须为 final(jdk1.8 之后可省略)。

示例:
// 接口
interface Inner {
public String say();
}
// 抽象类
abstract class Inner1 implements Inner{

}
// 普通类
class Inner2 implements Inner{
public String say(){
return “this is Inner2”;
}
}

class Outer {
public void method1(Inner inner) {
System.out.println(inner.say());
}
}

public class testDemo {
public static void main(String[] args) {

Outer outer = new Outer();
// 测试 1,Inner 为接口
outer.method1(new Inner() {
String s1 = “this is s1 in Inner”;

public String say() {
// 外部类和匿名函数类中有同名变量 s1
return s1;
}
});

// 测试 2,Inner1 为抽象类
outer.method1(new Inner1() {
String s2 = “this is s2 in Inner1”;

public String say() {
// 外部类和匿名函数类中有同名变量 s2
return s2;
}
});

// 测试 3,Inner2 为普通类
outer.method1(new Inner2() {
public String say() {
return “this is inner2 overrite”;
}
});

}
}
输出结果:
this is s1 in Inner
this is s2 in Inner1
this is inner2 overrite
内部类的作用
为什么要使用内部类?在《Think in java》中有这样一句话:使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
在我们程序设计中有时候会存在一些使用接口很难解决的问题,这个时候我们可以利用内部类提供的、可以继承多个具体的或者抽象的类的能力来解决这些程序设计问题。可以这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。内部类最大的优点就在于它能够非常好的解决多重继承的问题.
内部类还能够为我们带来如下特性:

内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。
在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。
创建内部类对象的时刻并不依赖于外围类对象的创建。
内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。

退出移动版