看了很多源码,都是对内部类有用的,但是之前在生产环境用的很少,用过也很少,所以我打算今天好好利用它们。它从头到尾贯穿始终。定义可以把一个类的定义放在另一个类里面,这就是内部类。所谓内部类的概念只出现在编译阶段,对于jvm层是没有内部类的概念的。我们可以使用内部类来解决类的单继承问题。外部类不能继承的类,可以交给内部类继承。我们可以通过定义一个内部类来实现一个类私有属于一个类,从而实现更好的封装代码优化:需要更少的代码分类内部类可以分为:静态内部类。非静态内部类。非静态内部类又可以分为:成员内部类。方法内部类。匿名内部类。我认为静态内部类是最常用的。比如Redis的key设计,因为我们需要在中间拼接:数字,所以用staticinnerclasses来组成不同的key是非常好的,这样同一个类型的staticinnerclasses的定义在同一个文件目录与普通静态变量或静态方法相同。使用了static关键字,不过这次是在类上修饰static。一般来说,只有static内部类才可以使用static关键字进行修饰。普通类的定义不能用static关键字修饰。这点需要注意。一个静态内部类定义如下:.println("myageis:"+age);}}}上面代码中,In类是静态内部类。我们说内部类可以访问外部类的私有字段和私有方法。对于静态内部类,遵循同样的原则,只能访问外部类的静态成员。上面代码中,外部类的非静态私有字段age在静态内部类中是不允许访问的,但是静态字段名是可以访问的。让我们看看如何创建静态内部类的实例对象。publicstaticvoidmain(String[]args){Out.IninnerClass=newOut.In();innerClass.sayHello();}使用场景,一般来说,针对与外部类关系密切但不依赖于外部类实例的情况,它可以被认为是一个静态内部类。我们来看稍微复杂一点的成员内部类。成员内部类我们说过四种不同类型的内部类各有自己的使用场景,而静态内部类适用于与外部类关系密切但又不依赖于外部类实例的情况。但是对于需要关联外部类实例的情况,可以选择将内部类定义为成员内部类。下面的代码定义了一个简单的成员内部类:publicclassOut{privateStringname;publicvoidshowName(){System.out.println("mynameis:"+name);}publicclassIn{publicvoidsayHello(){System.out.println(name);Out。this.showName();}}}上面定义了一个简单的内部类中,我们的成员内部类可以直接访问外部类的成员字段和成员方法,因为它关联了一个外部类实例。我们来看看如何在外部创建内部类的实例。publicstaticvoidmain(String[]args){Outout=newOut();out.setName("六脉神剑")Out.Inin=out.newIn();in.sayHello();}因为成员内部类关联的是a一个特定的外部类实例,所以它的实例创建必须由外部类实例创建。对于实例的创建,我们只需要记住,成员内部类实例的创建需要关联外部类实例对象,静态内部类实例的创建比较简单。下面我们主要看看编译器在编译阶段是如何保持内部类可以被外部类成员信息访问的。在使用场景中,对于高度依赖外部类实例的情况,定义一个成员内部类是比较明智??的。方法内部类方法内部类,顾名思义,就是定义在方法内部的类。方法的内部类相对要复杂一些。下面定义了该方法的一个内部类:);}}我们定义了一个类,在这个类中我们定义了一个方法sayHello,但是在这个方法中我们定义了一个内部类,classIn是一个方法内部类。我们的方法内部类的生命周期不超过包含它的方法的生命周期,即方法内部类只能在方法中使用。所以在声明的时候,任何访问修饰符都是没有意义的,所以Java根本就不允许任何访问修饰符去修饰方法的内部类。还需要注意的一件事是,定义和使用是两件不同的事情。不要看定义类的一长串代码。如果你真的想使用这个类,你必须有一个新的对象。对于方法的内部类,只能在方法内部使用。新对象。这是对方法内部类的简单介绍。我们来看看它的实现原理。方法内部类的实现原理其实和成员内部类没有太大区别。外部类实例在初始化时也会传入内部类。有什么不同?原因是方法的内部类是在具体的方法内部定义的,所以这个类不仅可以通过传入的外部实例访问外部类中的字段和方法,还可以访问包含它的方法中传入的参数会跟外部实例类实例一起初始化为内部类。毫无疑问,方法内部类的封装比前面介绍的两个更加完善。所以一般只有在需要高度封装的情况下才会将类定义为方法内部类。匿名内部类可能是所有内部类分类中名字最大的,也是最常用的。它们在函数式编程、lambda表达式等中比较常见。我们来关注一下这个匿名内部类。匿名内部类是没有名字的内部类。当定义完成时,实例也被创建,它通常与new关键字紧密结合。当然,不限于类,它也可以是接口,它可以出现在任何地方。下面我们定义了一个匿名内部类:如果您必须重写类或接口的方法,则应使用它。Java匿名内部类的创建有两种方式//首先定义一个普通类publicclassOut{privateStringname;publicvoidsayHello(){System.out.println("mynameis:"+name);}}~//定义并使用一个匿名内部类类类publicstaticvoidmain(String[]args){Outout=newOut(){@OverridepublicvoidsayHello(){System.out.println("mynameiscyy");}publicvoidshowName(){System.out.println("hellosingle");}};out.sayHello();}从上面的代码中,我们可以清楚的看出,我们的匿名内部类必须依赖一个父类,因为它没有名字,不能用具体的类型来表示。因此,匿名内部类往往通过继承父类,重写或重新声明一些成员来实现匿名内部类的定义。其实还是沿用了李式转换原理。其实看了上面三个内部类的原理,感觉匿名内部类的实现还是比较简单的。主要思想是抽取内部类,通过初始化外部类的实例来访问外部类的所有成员。只不过在匿名内部类中,依赖的父类不是他的外部类。匿名内部类的主要特点是没有名字,对象只能使用一次,可以出现在任何地方。因此,它的使用场景也层出不穷。对于一些需要简洁代码的情况,可以首选匿名内部类。小结以上四个内部类的简单介绍已经完成,同时也介绍了它们各自的实现原理。其实大体上是一样的。由于jvm要求每个类都有一个单独的源代码文件,所以分离操作在编译阶段完成,但是在分离过程中必须保持内部类和外部类之间的联系,所以编译器增加了一些接口来维护这个信息共享结构。使用内部类可以大大增加程序的封装性,使得代码整体的简洁性更高。说完这背后的功能接口引用,就容易聊一聊了。最后,内部类就这么多了。希望大家以后阅读源码会更轻松,哈哈
