Java内部类的使用小结
1. 成员内部类
public class Outer { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public Outer(String name) { super(); this.name = name; } // 个人推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 public Inner getInner() { return new Inner(); } // 内部类 public class Inner { public void print(String str) { System.out.println(str); } // 通过outer.this获取到外部对象类 public String getOuterName() { System.out.println(name);// 直接获取外部类的成员属性 System.out.println(getName());// 直接获取外部类的方法 return Outer.this.name; } } public static void main(String[] args) { Outer outer = new Outer("张三"); Outer.Inner inner = outer.new Inner(); inner.print("Outer.new"); System.out.println(inner.getOuterName()); inner = outer.getInner(); inner.print("Outer.get"); } }
将上面的类放到桌面进行编译之后:(可以看出创建内部类的时候实际是将外部类对象作为参数传入内部类中)
Outer$Inner.class
import java.io.PrintStream; public class Outer$Inner { public Outer$Inner(Outer paramOuter) {} public void print(String paramString) { System.out.println(paramString); } public String getOuterName() { System.out.println(Outer.access$000(this.this$0)); System.out.println(this.this$0.getName()); return Outer.access$000(this.this$0); } }
Outer.class
import java.io.PrintStream; public class Outer { private String name; public String getName() { return this.name; } public void setName(String paramString) { this.name = paramString; } public Outer(String paramString) { this.name = paramString; } public Outer.Inner getInner() { return new Outer.Inner(); } public class Inner { public Inner() {} public void print(String paramString) { System.out.println(paramString); } public String getOuterName() { System.out.println(Outer.this.name); System.out.println(Outer.this.getName()); return Outer.this.name; } } public static void main(String[] paramArrayOfString) { Outer localOuter = new Outer("张三"); Outer tmp15_14 = localOuter;tmp15_14.getClass();Outer.Inner localInner = new Outer.Inner(tmp15_14); localInner.print("Outer.new"); System.out.println(localInner.getOuterName()); localInner = localOuter.getInner(); localInner.print("Outer.get"); } }
2. 局部内部类
局部内部类,是指内部类定义在方法和作用域内。
定义在方法内:
public class Parcel4 { public Destination destination(String s) { class PDestination implements Destination { private String label; private PDestination(String whereTo) { label = whereTo; } public String readLabel() { return label; } } return new PDestination(s); } public static void main(String[] args) { Parcel4 p = new Parcel4(); Destination d = p.destination("Tasmania"); } }
定义在作用域里:
public class Parcel5 { private void internalTracking(boolean b) { if (b) { class TrackingSlip { private String id; TrackingSlip(String s) { id = s; } String getSlip() { return id; } } TrackingSlip ts = new TrackingSlip("slip"); String s = ts.getSlip(); } } public void track() { internalTracking(true); } public static void main(String[] args) { Parcel5 p = new Parcel5(); p.track(); } }
局部内部类也像别的类一样进行编译,但只是作用域不同而已,只在该方法或条件的作用域内才能使用,退出这些作用域后无法引用的。
3. 嵌套内部类(静态成员内部类)---相当于两个独立的类
嵌套内部类,就是修饰为static的内部类。声明为static的内部类,不需要内部类对象和外部类对象之间的联系,就是说我们可以直接引用outer.inner,即不需要创建外部类,也不需要创建内部类。
嵌套类和普通的内部类还有一个区别:普通内部类不能有static数据和static属性,也不能包含嵌套类,但嵌套类可以。而嵌套类不能声明为private,一般声明为public,方便调用。
创建静态内部类的时候不需要创建外部类,类似于一个普通的内部类的创建即可。
public class Outer { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public Outer(String name) { super(); this.name = name; } // 个人推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 public Inner getInner() { return new Inner(); } // 静态内部类(不能访问外部类的属性,因为相当于两个单独的类) public static class Inner { public void print(String str) { System.out.println(str); } } public static void main(String[] args) { Outer outer = new Outer("张三"); Inner inner = new Inner(); } }
编译之后是两个单独的类,而且内部类的构造方法没有传入外部类的实例,所以静态内部类不能访问外部类的成员属性和方法。
import java.io.PrintStream; public class Outer { private String name; public String getName() { return this.name; } public void setName(String paramString) { this.name = paramString; } public Outer(String paramString) { this.name = paramString; } public Outer.Inner getInner() { return new Outer.Inner(); } public static class Inner { public void print(String paramString) { System.out.println(paramString); } } public static void main(String[] paramArrayOfString) { Outer localOuter = new Outer("张三"); Outer.Inner localInner = new Outer.Inner(); } }
import java.io.PrintStream; public class Outer$Inner { public void print(String paramString) { System.out.println(paramString); } }
4. 匿名内部类
((Button) findViewById(R.id.start)).setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View v) { new Thread() { @Override public void run() { // TODO Auto-generated method stub } }.start(); } });
匿名内部类是不能加访问修饰符的。要注意的是,new 匿名类,这个类是要先定义的,看下面例子:
public class Outer { public static void main(String[] args) { Outer outer = new Outer(); Inner inner = outer.getInner("Inner", "gz"); System.out.println(inner.getName()); } public Inner getInner(final String name, String city) { return new Inner() { private String nameStr = name; public String getName() { return nameStr; } }; } } //注释后,编译时提示类Inner找不到 /* interface Inner { String getName(); } */
内部类里面使用外部类的局部变量时,其实就是内部类的对象在使用它,内部类对象生命周期中都可能调用它,而内部类试图访问外部方法中的局部变量时,外部方法的局部变量很可能已经不存在了,那么就得延续其生命,拷贝到内部类中,而拷贝会带来不一致性,从而需要使用final声明保证一致性。说白了,内部类会自动拷贝外部变量的引用,为了避免:1. 外部方法修改引用,而导致内部类得到的引用值不一致 2.内部类修改引用,而导致外部方法的参数值在修改前和修改后不一致。于是就用 final 来让该引用不可改变
Java为了避免数据不同步的问题,做出了匿名内部类只可以访问final的局部变量的限制。
5.内部类的继承
public class InheritInner extends WithInner.Inner { // InheritInner() 是不能通过编译的,一定要加上形参 InheritInner(WithInner wi) { wi.super(); } public static void main(String[] args) { WithInner wi = new WithInner(); InheritInner obj = new InheritInner(wi); } } class WithInner { class Inner { } }
public interface Interface1 { void ope1(); }
public interface Interface2 { void ope2(); }
public class Class1 implements Interface2 { private class InnerClass1 implements Interface1 { @Override public void ope1() { System.out.println("ope1"); } } @Override public void ope2() { System.out.println("ope2"); } public Interface1 getInterface1() { return new InnerClass1(); } }
public class Client { public static void main(String[] args) { Class1 class1 = new Class1(); class1.ope2(); class1.getInterface1().ope1(); } }
结果:
ope2
ope1