在 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/(default)
内部类: public/protected/(default)/private
局部内部类: 什么都不能写
为什么要被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(); } }
每种内部类均有各自的使用场景,因此对于内部类的使用也要根据自己的业务需求进行选择。尤其也要注意内部类使用的细节问题,以及使用规则。
最后以上均是自主学习总结,如有不适之处还请留言指教。
感谢阅读!