一、成员内部类
1、定义
在成员位置上的内部类。
2、用法
public class Outer { private int id; public void out(){ System.out.println("这是外部类方法"); } class Inner{ public void in(){ System.out.println("这是内部类方法"); } } } ---------------------------------------------------------------- public class Test{ public static void main(String[] args) { //实例化成员内部类分两步 //1、实例化外部类 Outer outObject = new Outer(); //2、通过外部类调用内部类 Outer.Inner inObject = outObject.new Inner(); //测试,调用内部类中的方法 inObject.in();//打印:这是内部类方法 } }
能够访问外部类所有的属性和方法,原理就是在通过外部类对象实例化内部类对象时,外部类对象把自己的引用传进了内部类,使内部类可以用通过Outer.this去调用外部类的属性和方法,一般都是隐式调用了,但是当内部类中有属性或者方法名和外部类中的属性或方法名相同的时候,就需要通过显式调用Outer.this了。
3、使用场景
普通内部类可以访问外部类的所有成员和方法,因此当类 A 需要使用类 B ,同时 B 需要访问 A 的成员/方法时,可以将 B 作为 A 的成员内部类。
4、面试题
//要求:使用已知的变量,在控制台输出30,20,10。 class Outer { public int num = 10; class Inner { public int num = 20; public void show() { int num = 30; System.out.println(?); System.out.println(??); System.out.println(???); } } } class InnerClassTest { public static void main(String[] args) { Outer.Inner oi = new Outer().new Inner(); oi.show(); } }
答案:num; this.num; Outer.this.num
由此题的扩展:局部变量可以和成员变量重名,不加“this”修饰时,优先使用最近的变量。
二、局部内部类
1、定义
方法里的内部类。
2、用法
public class Outer { private int id; public void out(){ System.out.println("外部类方法"); } public void method01(){ class Inner{ public void in(){ System.out.println("这是局部内部类"); } } //关键在这里,如需要在method01方法中自己创建内部类实例,然后调用内部类中的方法,等待外部类调用method01方法,就可以执行到内部类中的方法了。 Inner In = new Inner(); In.in(); } }
在局部内部类中,如果要访问局部变量,那么该局部变量要用final修饰。
如果不实用final修饰,当局部内部类被实例化后,方法弹栈,局部变量随着跟着消失,这个时候局部内部类对象在想去调用该局部变量,就会报错,因为该局部变量已经没了,当局部变量用fanal修饰后,就会将其加入常量池中,即使方法弹栈了,该局部变量还在常量池中呆着,局部内部类也就是够调用。所以局部内部类想要调用局部变量时,需要使用final修饰,不使用,编译不能通过。
3、使用场景
局部内部类只用于当前方法或者代码块中创建、使用,一次性产品,使用场景比较少。
三、静态内部类
1、定义
static修饰的内部类。
2、用法
静态内部类能够直接被外部类给实例化,不需要使用外部类对象。
Outer.Inner inner = new Outer.Inner();
3、使用场景
当类 A 需要使用类 B,而 B 不需要直接访问外部类 A 的成员变量和方法时,可以将 B 作为 A 的静态内部类。
如:在基类 A 里持有静态内部类 B 的引用,然后在 A 的子类里创建特定业务的 B 的子类,这样就结合多态和静态内部类的优势,既能拓展,又能限制范围 。
还可以实现单例模式
四、匿名内部类
1、定义
没有名字的内部类,只需要用一次的内部类。其实就是一个匿名子类对象。
2、用法
public class Test { public static void main(String[] args) { //如果我们需要使用接口中的方法,我们只需要走一步,就是使用匿名内部类,直接将其类的对象创建出来。 new Test1(){ public void method(){ System.out.println("实现了Test接口的方法"); } }.method(); } } interface Test1{ public void method(); }
3、使用场景
一个方法的返回值是接口,然后根据不同参数返回不同的实现,我们不需要保存引用,直接 new 一个接口实现即可。
4、面试题
* A:面试题 * 按照要求,补齐代码 interface Inter { void show(); } class Outer { //补齐代码 } class OuterDemo { public static void main(String[] args) { Outer.method().show(); } } 要求在控制台输出”HelloWorld”
public static Inter method(){ return new Inter{ void show(){ System.out.println("HelloWorld") } } }
总结:
使用场景:总的来说,内部类一般用于两个场景:
①需要用一个类来解决一个复杂的问题,但是又不希望这个类是公共的
②需要实现一个接口,但不需要持有它的引用
没有引用外部类的内部类,最好设置为 static 的,那样可以避免非静态内部类的弊端:持有外部引用、导致外部类更大。比如说一般的 Adapter, holder。
拓展阅读:
内部类的字节码学习和实战使用场景:https://blog.csdn.net/u011240877/article/details/78682097
内部类的使用场景:https://blog.csdn.net/xiaoliuliu2050/article/details/62062881
原文:https://www.cnblogs.com/lc4j/p/11066898.html