1. 内部类结束
内部类具有封装型,隐藏程序细节。主要有非静态内部类,静态内部类,匿名内部类几种。
2. 非静态内部类
可用把内部类当作外部类的成员变量/方法来使用,需要依赖外部类对象来使用
public class OutClass { private String outStr; public void display(){ System.out.println(outStr); } //内部类 public class InnerClass{ private String innerStr; public InnerClass() { innerStr = "innner class"; } public void display(){ System.out.println("Inner class"); System.out.println(innerStr); } } public static void main(String[] args) { OutClass outClass = new OutClass(); outClass.display(); OutClass.InnerClass innerClass = outClass.new InnerClass(); //创建内部类需要外部类对象调用 innerClass.display(); } }
非静态内部类还可以定义在方法内
public class OutClass02 { private String outStr; public void display(){ class InnerClass{ private String innerStr; public InnerClass() { innerStr = "innner class"; } public void display(){ System.out.println("Inner class"); System.out.println(innerStr); } } InnerClass innerClass = new InnerClass(); //可以直接创建内部类 innerClass.display(); } public static void main(String[] args) { OutClass02 outClass02 = new OutClass02(); outClass02.display(); } }
2. 静态内部类
静态内部类使用不需要依赖外部对象
public class OutClass03 { private String outStr; public void display(){ System.out.println(outStr); } public static class InnerClass03{ private String innerStr; public InnerClass03() { innerStr = "innner class"; } public void display03(){ System.out.println("Inner class"); System.out.println(innerStr); } } public static void main(String[] args) { OutClass03 outClass03 = new OutClass03(); outClass03.display(); InnerClass03 innerClass03 = new InnerClass03(); //创建内部类不需要外部类对象调用 innerClass03.display03(); } }
3. 匿名内部类
可用直接实现接口创建对象,还可以直接"new 接口名“,重写接口中方法
public interface InnerInterface { void inner(); }
public class InnerInterfaceImpl implements InnerInterface { @Override public void inner() { System.out.println("test"); } }
public class MyApp { public static void main(String[] args) { //(1)创建对象 InnerInterface innerInterface = new InnerInterfaceImpl(); innerInterface.inner(); //(2)匿名内部类 InnerInterface innerInterface1 = new InnerInterface() { @Override public void inner() { System.out.println("test1"); } }; innerInterface1.inner(); } }
还可用把接口的实现放在类里面,这样就相当于一个内部类,所以调用就需要依赖外部类对象来调用
public class MyApp2 { public class InnerInterfaceImpl implements InnerInterface{ @Override public void inner() { System.out.println("test2"); } } public static void main(String[] args) { MyApp2 myApp2 = new MyApp2(); MyApp2.InnerInterfaceImpl innerInterface = myApp2.new InnerInterfaceImpl(); innerInterface.inner(); } }
3. 局部内部类和匿名内部类访问局部变量
(1)局部内部类访问局部变量
public class Test01 { public static void main(String[] args) { new Test01().test(6); } public void test(int b){ int a = 10; new Thread(new Runnable() { @Override public void run() { System.out.println(a); System.out.println(b); // System.out.println(a++); 提示错误,变量被final修饰 // System.out.println(b++); } }).start(); } }
(2)匿名内部类访问局部变量
public class Test03 { private int age = 12; public static void main(String[] args) { new Test03().test(20); } public void test(int x){ class InnerClass{ public void InPrint(){ // System.out.println(x++); 提示错误,变量被final修饰 System.out.println(x); System.out.println(age++); //可以访问成员变量 } } new InnerClass().InPrint(); } }
总结:
在Java 1.8后虽然在类中不用直接在变量前使用final修饰,但是也不能修改变量的值,对变量进行++会有编译报错。通过反编译.class文件后,也能看到变量会被final修饰
所以局部内部类和匿名内部类访问局部变量时会被final修饰。
内部类和外部类是处于同一级别的,内部类不会因为定义在方法中就会随着方法的执行完毕被销毁。
所以当外部类的方法结束后,局部变量就应该被销毁了,但是内部类可能还会存在,这样内部类就会引用了不存在的变量。此时就需要将局部变量复制一份作为内部类的成员变量,这样局部变量死亡后,内部类依然可以访问它,实际访问的是局部变量的“copy”,相当于延长了局部变量的生命周期。
将局部变量复制作为内部类的成员变量时,就必须要保证两个变量是一致的,如果在内部类修改了成员变量,方法中也就要改变,所以可以把局部变量设置为final,对它初始化后,就不再改变这个变量了,就可以保证内部类的成员变量和方法的局部变量的一致性了,这实际上也是一种妥协,使得局部变量和内部类的建立的拷贝保持一致。