可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。
广泛意义上的内部类一般来说包括这四种:
成员内部类是最普通的内部类,它的定义为位于另一个类的内部,形如下面的形式:
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 父类构造器(参数列表)| 要实现的接口 () { //匿名内部类的类体部分 //.... }
匿名内部类是在抽象类和接口的基础上发展而来的,其最大的好处是帮助减少了类的定义。
在使用匿名内部类的过程中,我们需要注意如下几点:
示例:
//接口 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》中有这样一句话:使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
在我们程序设计中有时候会存在一些使用接口很难解决的问题,这个时候我们可以利用内部类提供的、可以继承多个具体的或者抽象的类的能力来解决这些程序设计问题。可以这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。内部类最大的优点就在于它能够非常好的解决多重继承的问题.
内部类还能够为我们带来如下特性: