java中内部类的使用
1.定义
内部类是指在一个外部类的内部在定义一个类.内部类作为外部类的一个成员,并且依附于外部类而存在的.内部类可为静态,可用protected和private修饰(外部类只能是public和缺省的包访问权限).内部类主要有以下几种:成员内部类,局部内部类,静态内部类,匿名内部类.
2.为什么需要内部类
典型情况是:内部类继承自某个类或实现某个接口,内部类的代码操作创建其外部类的对象.所以你可以认为内部类提供了某种进入其外部类的窗口.使用内部类最吸引人的原因是:每个内部类都能独立的继承自接口的一个实现,无论外部类是否已经继承了这个实现对于内部类都没有影响.如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题很难解决.从这个角度看,内部类是的多重继承的解决方案变得完整:接口解决了部分问题,内部类有效的实现了"多继承".
3.成员内部类
作为外部类的一个成员存在,与外部类的属性和方法并列:
>>在外部类访问内部类时,需创建一个内部类的对象.
>>每一个内部类的对象都会链接到一个外部类的对象(除非是一个静态内部类,下面会说到).
>>在内部类中,可以访问所有外部类的成员,但自身不能定义静态成员.
>>在内部类中,可以定义与外部类相同名称的实例变量,在内部类访问自己的变量和与外部类的非同名变量可以直接使用;访问外部类的同名变量时,通过"外部类名.this.变量名"使用.
>>内部类是一个编译时的概念,一旦编译成功,会成为完全不同的两类.本例中编译完成后会出现Outer3.class和Outer3$Inner3.class两个文件.
例:
public class Outer3 { private static int i = 10; private int j = 20; private int k = 30; public static void outer_method1() { } public void outer_method2() { } class Inner3 { // static int inner_i; private int inner_j = 200; private int k = 300; public void inner_method() { System.out.println(inner_j); System.out.println(this.k); System.out.println(Outer3.this.k); System.out.println(j); outer_method1(); outer_method2(); } } public void outer_method3() { this.new Inner3().inner_method(); } public static void outer_method4() { Outer3 outer = new Outer3(); Inner3 inner = outer.new Inner3(); inner.inner_method(); } public static void main(String[] args) { outer_method4(); } }
4.局部内部类
在方法中定义的内部类,与局部变量类似.除了有和成员内部类一样的特性外:
>>局部内部类不能有访问修饰符,因为它不是外部类的一部分.
>>可以访问作用域内的变量,但是在访问时隐式的将变量当做final处理.
例:
public class Outer4 { public void outer_method() { int i = 10; // i++; class Inner4 { void inner_method() { System.out.println(i); } } } }
5.静态内部类
如果不需要内部来的对象与外部类的对象之间有联系,可以将内部类声明为static.非静态内部类对象都隐含的保存了一个引用,指向外部类的对象,但是静态内部类就不是这样了:
>>可以直接通过外部类创建内部类的对象.
>>不能在内部类的对象中访问非静态的外部类对象.
>>内部类可以定义静态和非静态成员.
>>内部类无法访问外部类的非静态成员.
例:
public class Outer5 { private static int i = 10; private int j = 20; private int k = 30; public static void outer_method1() { } public void outer_method2() { } static class Inner5 { private static int inner_i; private int inner_j = 200; private int k = 300; public void inner_method() { System.out.println(inner_j); System.out.println(k); // System.out.println(j); outer_method1(); // outer_method2(); } } public void outer_method3() { System.out.println(new Inner5().inner_j); } public static void outer_method4() { new Inner5().inner_method(); } public static void main(String[] args) { outer_method4(); } }
6.匿名内部类
匿名内部类就是没有类名的内部类,一般适用的条件有:
>>只用到类的一个实例.
>>类在定义后马上用到.
>>类非常的小(推荐是4行代码以下).
>>给类命名并不会使你的代码更容易理解.
在使用匿名内部类时,需要记住的原则:
>>匿名类不能有构造方法.
>>匿名类内部不能定义任何静态成员(属性,方法,类).
>>匿名类不能是public,protected,private,static.
>>只能创建一个实例.
>>一定是在new关键字的后面,用其隐含实现一个接口或类.
>>其他内部类的特性.
例:
import java.util.List; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; public class Outer6 { public static void main(String[] args) { List<String> name = Arrays.asList("James", "Kobe", "Yao"); Collections.sort(name, new Comparator<String>() { public int compare(String s1, String s2) { return s1.compareTo(s2); } }); } }
静态方法Collections.sort接收一个list和一个Comparator作为输入参数,实现对输入的list中的元素进行比较并排序. 看上去我们直接new了一个Comparator,实际上是定义了一个实现Comparator的匿名类,通过new创建了这个匿名类的一个对象.在本例中编译成功后会出现Outer6$1.class文件,代表匿名类通过编译.
7.多层嵌套类
在多层嵌套类中,一个内部类被嵌套多少层并不重要,它能访问所有他所嵌入的外部类的成员(即使是private的).例:
public class Outer7 { private int i = 10; private void outer_method() { } class A { int j = 20; void a() { } class B { void b() { outer_method(); a(); System.out.println(i); System.out.println(j); } } } public static void main(String[] args) { new Outer7().new A().new B().b(); } }
8.内部类重载
如果创建了一个类,继承了外部类并重新定义了次内部类时,是否内部类会被重载呢?但是"重载"内部类好像它是外部类的一个方法,并不起什么作用.例:
public class Outer8 { private Inner inner; class Inner { public Inner() { System.out.println("Outer8.Inner()"); } } public Outer8() { System.out.println("new Outer8()"); inner = new Inner(); } }
public class SubOuter8 extends Outer8 { private Inner subinner; class Inner { public Inner() { System.out.println("SubOuter8.Inner()"); } } public SubOuter8() { System.out.println("new SubOuter8()"); subinner = new Inner(); } public static void main(String[] args) { new SubOuter8(); } }
运行结果:
new Outer8()
Outer8.Inner()
new SubOuter8()
SubOuter8.Inner()
由此可见,当继承外部类的时候,内部类并没有什么特别的变化,这两个内部类完全是相对独立的两个实体,各自在自己的命名空间内.当然也可以明确的继承某个内部类.例:
public class Outer8 { private Inner inner; class Inner { public Inner() { System.out.println("Outer8.Inner()"); } } public Outer8() { System.out.println("new Outer8()"); inner = new Inner(); } }
public class SubOuter8 extends Outer8 { private Inner subinner; class Inner extends Outer8.Inner { public Inner() { System.out.println("SubOuter8.Inner()"); } } public SubOuter8() { System.out.println("new SubOuter8()"); subinner = new Inner(); } public static void main(String[] args) { new SubOuter8(); } }
运行结果:
new Outer8()
Outer8.Inner()
new SubOuter8()
Outer8.Inner()
SubOuter8.Inner()
和前面的结果相比多输出了一个"Outer8.Inner()",说明子类的内部类在实例化时先创建了父类内部类的对象.
小结:不同环境下的内部类有着不同的特性,成员内部类与类的其他成员特性相似;局部内部类与局部变量特性相似;静态内部类与静态变量特性相似;匿名内部类经常在为了某个功能而实现某个接口时使用.同时内部类也是类的一种表现形式.