一,前言 ​ 在 Java 中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。 ​ 作用: ​ 1,间接性实现Java多继承,每个内部类都能独立的继承一个接口的实现,因此对于外部类来说就算继承了某个父类,在内部类中是不会有任何影响的。 ​ 2,可以将复杂的逻辑代码组合在一起,且对外是隐藏的。 ​ 3,内部多线程的使用。 二,成员内部类 ​ 成员内部类是最普通的内部类,它的定义为位于另一个类的内部。 ​ 访问规则: ​ 1,内部类可以不受权限符的限制,直接访问外部类的成员变量。 ​ 2,实例化内部类之前,必须先创建外部类对象,才能访问内部类属性。 ​ 直接创建内部类公式为: ​ 外部类名称.内部类名称 对象名 = new 外部类名称.new 内部类名称(); ​ 3,外部类不能直接访问内部类的变量和方法,需要通过内部类对象进行访问。 public class Outer { private Inner inner = null; int num = 10; public Inner getInner() { if (inner == null) inner = new Inner(); return inner; } public class Inner { int num = 20; public void heart() { int num = 30; System.out.println("就近原则:" + num); // 结果:30 System.out.println("本类中;" + this.num); // 结果:20 System.out.println("外部类中:" + Outer.this.num); // 结果:10 } } } ​ 成员内部类是最为普通的一种,但上述代码有个细节就是在外部类中,内部类及内部类方法中存在变量名称相同的问题。在这种情况下访问规则是: ​ 1,就近原则,先访问本方法中的变量值。 ​ 2,如果访问本类中可使用this关键字。 ​ 3,如果访问外部类变量值(方法),使用方式为:外部类名称.this.变量名称(外部类.this.成员方法)。 ​ 创建方法有两种: //第一种方式:直接创建 Outer outer = new Outer(); Outer.Inner inner = outer.new Inner(); //必须通过Outer对象来创建 inner.heart(); //第二种方式:间接创建 Outer.Inner inner1 = outer.getInner(); inner1.heart(); 三,局部内部类 ​ 如果一个类是定义在方法内部的,那就是一个局部内部类。 ​ "局部":出了这个方法,其他地方都不能调用局部内部类。 public class LocalCLass { public void localInner(){ // 局部内部类 class Inner{ int num = 10; public void methodInner(){ System.out.println("局部内部类:"+num); // 结果:10 } } // 在方法内部,调用局部内部类 Inner inner = new Inner(); inner.methodInner(); } } ​ 注意: ​ 1,关于类的权限修饰符: ​ public>protected>(default)>private ​ 外部类:public/(default) ​ 内部类:public/protected/(default)/private ​ 局部内部类:什么都不能写 ​ 2,局部类访问局部成员方法: 如果要访问这个局部类所在方法的局部变量,那么必须是有效的final修饰的。 从jdk8+开始,只要局部变量实际上不会改变,则可以省略final关键字。 ​ 为什么要被final关键字修饰,这个和对象的生命周期有关系。 ​ 1,new出来的对象是在内存的堆中的。 ​ 2,局部变量是跟着方法走的,在栈内存中。 ​ 3,当方法结束后,便会即可出栈,局部变量消失。 ​ 4,而new出来的对象还在堆内存中,直到GC回收消失。 ​ 因此,当局部内部类还在堆内存中时,如果再次使用局部变量时,而方法中的局部变量已经出栈消失了。因此必须使用final修饰为常量,使局部内部类可以去常量池中复制一份。另一个原因就是,如果不是final修饰为常量,后期该局部变量值被修改了,那么便会造成局部内部类读取的数据不一致的情况。 四,匿名内部类 ​ 匿名内部类简单理解就是没有类名称的类。 ​ 一般在实际开发中匿名类是使用最多的,在编写事件监听的代码时使用匿名内部类不但方便,而且使代码更加容易维护。 ​ 那么一般在什么情况下会使用到匿名内部类。 ​ 如果接口的实现类(父类的子类)只需要唯一的一次。那么这种情况下就可以省略对该类的实现,直接使用匿名内部类。 ​ 请看如下代码,先来定义一个接口。 public interface IAnonymous { void anonymousMethod(); } // 匿名内部类的创建方式 // 第一种方法 IAnonymous anonymous = new IAnonymous() { @Override public void anonymousMethod() { System.out.println("使用匿名内部类实现接口!"); } }; anonymous.anonymousMethod(); // 第二种方式,匿名对象 new IAnonymous(){ @Override public void anonymousMethod() { System.out.println("使用匿名对象实现接口!"); } }.anonymousMethod(); 匿名内部类注意事项: ​ 1,匿名内部类在创建对象的时候,只能使用唯一的一次,如果要多次创建同一个对象时, 并且内容是相同的,那必须单独定义实现类或者子类。 ​ 2,匿名对象,在调用方法的时候,只能调用唯一的一次。如果同一个对象要调用多个方法, 则需要给对象定义对象名称。 ​ 3,匿名内部类是省略了实现类或者子类,而匿名对象是省略了对象名称。两者并不是一回事。 五,静态内部类 ​ 静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。 public class StaticInnerClass { // 外部类静态成员属性 private static int num = 10; public static class staticInner{ public void staticMethod(){ System.out.println("静态内部类!"); System.out.println("外部静态成员变量:"+num); } } } class StaticMain{ public static void main(String[] args) { StaticInnerClass.staticInner innerClass = new StaticInnerClass.staticInner(); innerClass.staticMethod(); } } 六,总结 ​ 每种内部类均有各自的使用场景,因此对于内部类的使用也要根据自己的业务需求进行选择。尤其也要注意内部类使用的细节问题,以及使用规则。 ​ 最后以上均是自主学习总结,如有不适之处还请留言指教。https://www.cnblogs.com/fenjyang/p/11467018.html