昨天上课毕老师讲到了匿名内部类,很多哥们都懵了,一点不奇怪,引用老师的话:“任何人第一次接触匿名内部类都是懵的,因为他没见过这种形式。”我以前刚开始学习java接触到内部类和匿名内部类的时候很惆怅,苦于没有老师,只能上网去查资料、翻书,很长时间才明白个大概。我这里就把我理解的内部类的情况总结了一下,可能不是很全面或者有什么错误的地方,希望大家能补充或指正。
在Java中定义在其他类内部的类叫内部类或者嵌入类。内部类分为成员内部类,静态内部类,局部内部类,匿名内部类。大家可以把静态内部类当做静态属性来看,成员内部类当做成员属性来看,只不过它们同时具备类的特性,而且可以访问外部类的私有成员。
成员内部类:
特点:可以访问外部类所有成员,相比较外部类只有public和默认的修饰符不同,内部类作为一个成员,可以被任意修饰符修饰。
例:
//当我们在外部类,内部类,内部类的方法中定义了相同名称的变量时,如何知道你要访问的是哪个变量?(内部类中的注释部分)
//如何实例化内部类调用内部类的方法 1.(注释部分) 2. 在外部类的外面直接创建内部类的实例然后调用内部类方法,要注意格式(main方法中未注释部分)
class Outer {
private int i = 1;
class Inner {
private int i = 2;
public void show() {
int i = 3;
System.out.println(i); // 得到的是方法内的i
System.out.println(this.i); // 使用this,得到的是内部类的i
System.out.println(Outer.this.i); //使用外部类名.this,得到的是外部类的i
}
}
/*public void innerMethod() { //在外部类中创建内部类对象调用方法,并提供方法供外部调用
Inner in = new Inner();
in.show();
}*/
}
public class Test {
public static void main(String[] args) {
/*Outer out = new Outer(); //创建外部类的实例
out.innerMethod();*/
Outer out = new Outer(); //创建外部类的实例
Outer.Inner in = out.new Inner(); //创建内部类实例
in.show(); //调用内部类方法
}
}
静态内部类:
特点:在定义成员内部类的时候可以在类前面加static将类定义成静态的,静态内部类只能访问外部类的静态成员,只有在静态内部类中才能定义静态的变量和方法,静态内部类实例化的时候不必先实例化外围类,可以直接实例化内部类。拿上面例子来说: 静态内部类的对象可以直接生成:Outer.Inner in = new Outer.Inner();而不需要通过生成外部类对象来生成。
局部内部类(在方法和作用域内的类):
特点:只在局部有效,可以访问外部类的所有成员变量,但是只能访问内部类所在作用域用final修饰的变量。(为什么呢?final修饰的变量在内存中只有一份,生命周期较长,普通的局部变量在代码块执行完毕后就会被当成垃圾回收,而内部类的不会消失)静态方法中的局部内部类只能访问外围类的静态成员,访问不了非静态成员。当我们要解决一个复杂的问题,需要一个类来辅助我们的解决方案,但又不希望这个类是公共可用的时候就用到局部内部类。由于局部内部类只在局部有效,所以不能在外面用局部内部类的引用指向局部内部类的对象,只能用局部内部类实现接口并创建局部内部类对象,在外面用接口引用指向局部内部类对象。
例(From Thinking in java):
public class Test {
public Destination dest(String s){
class PDestination implements Destination{
private String label;
private PDestination(String label){
this.label = label;
}
public String readLabel(){
return label;
}
}
return new PDestination(s);
}
public static void main(String[] args) {
Test t = new Test();
Destination d = t.dest("Tanzania");
}
}
interface Destination{
String readLabel();
}
匿名内部类:
特点:是内部类的一种简化写法,使用匿名内部类的前提是内部类可以继承一个外部类或者实现一个接口,必须实现父类或者接口中的所有抽象方法。可以简单理解为:建立一个带内容的外部类或者接口的匿名对象,目的是是为了方便阅读。
例:
public class Outer {
public static void main(String[] args) {
new Outer().method(new OneClass() {
public void show() {
System.out.println("哈哈");
}
});
}
public void method(OneClass o) {
o.show();
}
}
}
abstract class OneClass {
abstract public void show();
}
另外需要注意的是:
成员内部类编译后生成的.class文件名称格式是<外部类类名>$<内部类类名>。
静态内部类编译后生成的.class文件名称格式是<外部类类名>$<静态内部类类名>。
局部内部类编译后生成的.class文件名称格式是<外部类类名>$<x><内部类类名> x是该局部的第几个内部类
匿名内部类编译后生成的.class文件名称格式是<外部类类名>$<x> x是该类的第几个匿名内部类。