漳州网站建设哪家最正规,医院网站建设公司,江油官方网站建设,高端网站建设必去磐石网络小胖从官网出发#xff0c;研究下为什么我们需要些内部类#xff0c;内部类的区别和联系。思考三个问题#xff1a;(1)为什么需要内部类#xff1f;静态内部类和非静态内部类有什么区别#xff1b;(2)为什么内部类可以无条件访问外部类成员#xff1b;(3)为什么jdk1.8之前…小胖从官网出发研究下为什么我们需要些内部类内部类的区别和联系。思考三个问题(1)为什么需要内部类静态内部类和非静态内部类有什么区别(2)为什么内部类可以无条件访问外部类成员(3)为什么jdk1.8之前局部内部类和匿名内部类访问局部变量或者方法参数需要加final修饰符1. 官网阅读1.1 为什么需要内部类It is a way of logically grouping classes that are only used in one place: If a class is useful to only one other class, then it is logical to embed it in that class and keep the two together. Nesting such helper classes makes their package more streamlined.简化包配置如果一个类只对另一个类有用将他们嵌套在一起是合理的。嵌套一些“有帮助的类”可以使得包更加简化It increases encapsulation: Consider two top-level classes, A and B, where B needs access to members of A that would otherwise be declared private. By hiding class B within class A, As members can be declared private and B can access them. In addition, B itself can be hidden from the outside world.增加了封装两个顶级类A和BB需要访问A中声明为private的成员。It can lead to more readable and maintainable code: Nesting small classes within top-level classes places the code closer to where it is used.易读和可维护在顶级类中嵌套小类会使代码更接近于使用它的位置。1.2 为什么Java内部类设计为静态和非静态Nested classes are divided into two categories: static and non-static. Nested classes that are declared static are called static nested classes. Non-static nested classes are called inner classes.嵌套类一般分为两类静态和非静态。声明static的嵌套类称为静态嵌套类。非静态嵌套类称为内部类。A static nested class interacts with the instance members of its outer class (and other classes) just like any other top-level class. In effect, a static nested class is behaviorally a top-level class that has been nested in another top-level class for packaging convenience.静态嵌套类就像任何顶级类一样 与 其外部类(其他的类)的实例成员交互。事实上静态内部类在行为上就是一个顶级类它嵌套在一个顶级类中以方便打包。As with class methods and variables, a static nested class is associated with its outer class. And like static class methods, a static nested class cannot refer directly to instance variables or methods defined in its enclosing class: it can use them only through an object reference.和静态方法一样静态嵌套类不能直接引用封闭类中定义的实例变量和方法。只能通过对象的引用来使用它们。静态方法引用对象public class TestNest {private String abc;public String getAbc() {return abc;}public static String nestSta() {TestNest testNest new TestNest();return testNest.getAbc();}}As with instance methods and variables, an inner class is associated with an instance of its enclosing class and has direct access to that objects methods and fields. Also, because an inner class is associated with an instance, it cannot define any static members itself.内部类可以直接访问该对象的字段和方法由于内部类和实例相关联因此无法定义任何的静态成员变量。那我们怎么理解呢静态内部类就是一个独立的类。为什么使用静态内部类呢比如AB两个类B有点特殊虽然可以单独存在但只能被A使用。那么此时应该怎么办把B并入到A里面复杂性提高搞的A违反单一职责。如果B独立又可以被其他类依赖不符合设计本意不如将其变成A.B。其他类就不能使用B了。而相比起来非静态的才是真正的内部类对其外部类有一个引用。1.3 序列化Serialization of inner classes, including local and anonymous classes, is strongly discouraged. When the Java compiler compiles certain constructs, such as inner classes, it creates synthetic constructs;.....However, synthetic constructs can vary among different Java compiler implementations, which means that .class files can vary among different implementations as well. Consequently, you may have compatibility issues if you serialize an inner class and then deserialize it with a different JRE implementation.强烈建议不要对内部类进行序列化。java编译器编译某些构造(如内部类)时他会创建“合成构造”。合成构造在不同的java编译器中变化。序列化内部类然后使用不同的JRE实现反序列化则可能存在兼容的问题。2. 实战内部类2.1 成员内部类类的成员 无条件访问外部类 依赖外部类 多种访问权限2.1.1 内部类的特点成员内部类中不能定义静态变量public class Outer {private String name;public Outer(String name) {this.name name;}//外部类使用内部类的方法public void write() {Inner inner new Inner();inner.say();System.out.println(inner.getInnnerName());}//成员内部类class Inner {private String InnnerName;public String getInnnerName() {return InnnerName;}public void setInnnerName(String innnerName) {InnnerName innnerName;}public void say() {System.out.println(name);}}}成员内部类相当于类的成员变量可以无条件访问外部类的成员。但不过要注意的是成员内部类和外部内部类拥有同名的成员方法或者方法时要显式的声明否则默认情况下访问的是内部类成员。外部类.this.成员变量外部类.this.成员方法反编译后的class文件public class Outer {private String name;public Outer(String name) {this.name name;}public void write() {Outer.Inner inner new Outer.Inner();inner.say();System.out.println(inner.getInnnerName());}class Inner {private String InnnerName;Inner() {}public String getInnnerName() {return this.InnnerName;}public void setInnnerName(String innnerName) {this.InnnerName innnerName;}public void say() {System.out.println(Outer.this.name);}}}外部类想访问内部类的成员必须先创建一个内部类的对象再通过指向这个对象的引用来访问。public void wirte() {Inner inner new Inner();inner.say();System.out.println(i : name);}于是外部类就可以访问内部类的所有成员了2.1.2 如何创建内部类我们知道成员内部类是依赖于外部类而存在的。也就是说想要创建成员内部类前提是有一个外部类对象。方式一Outer outer new Outer();Inner inner outer.new Inner();方式二Outter.Inner inner1 outter.getInnerInstance();//getInnerInstance()方法public Inner getInnerInstance() {if(inner null)inner new Inner();return inner;}2.1.3 成员内部类权限问题成员内部类可以拥有public、default、protected、private权限。private只能在外部类中被访问。default同一个包下访问。protected同一个包下或继承外部类的情况下。public任何地方。而外部类只有public和default两种访问权限。2.1.4 小结成员内部类是依附于外部类存在的并且和外部类的一个成员变量有相似之处。内部类可以无条件访问外部类的成员、外部类需要内部类的引用才能访问、四种访问权限。请注意(下面两个内部类)jdk版本是1.8看起来似乎编译器取消了没有声明为final的变量或参数也可以在局部内部类和匿名内部类被访问。但事实上是Java8引入了effectively final概念被默认成为了final类型。2.2 局部内部类方法或作用域内 局部变量注意局部内部类和成员内部类的区别就是局部内部类的访问仅限于方法内或者该作用域内。不能定义静态变量。class Outer {Object method() {int locvar 1;System.out.println(1111);class Inner {void displayLocvar() {System.out.println(locvar locvar);}}Object in new Inner();return in;}}注意局部内部类更像一个局部变量是没有访问修饰符的。2.3 匿名内部类一般来说匿名内部类用于继承其他类或是实现接口并不需要增加额外的方法只是对继承的方法的实现或者重写。匿名类的格式new Thread(new Runnable() {Overridepublic void run() {//TODO}});通过new XXX(){};的方式创建了一个只能使用一次子类。--为什么叫做匿名内部类呢匿名内部类只能使用一次。他通常用来简化代码。但是使用匿名内部类还有一个前提条件必须继承一个父类(抽象类或具体类)或是实现一个接口。对于这个问题首先我们应该明确的一点是对于匿名内部类它可能引用三种外部变量外部类的成员变量(所有的变量)外部方法或作用域内的局部变量外部方法的参数实际上只有第一种变量不需要声明为final。原因首先在这里提出网上的答案基本是局部变量声明周期和局部类的声明周期不同。会导致内部类失去引用造成错误等等一个变量加上final就可以延长生命周期了吗那加上final岂不是会造成内存短暂泄露正解匿名内部类和所有类一样也是有自己的构造函数的只不过这个构造函数是隐式的。加入final修饰符是为了保持内部和外部的数据的一致性。编译前public class Outer {String string ;void outerTest(final char ch){final Integer integer 1;Inner inner new Inner() {void innerTest() {System.out.println(string);System.out.println(ch);System.out.println(integer);}};}public static void main(String[] args) {new Outer().outerTest( );}class Inner {}}编译后class Outer$1extends Outer.Inner{Outer$1(Outer paramOuter, char paramChar, Integer paramInteger){super(paramOuter);}void innerTest(){System.out.println(this.this$0.string);System.out.println(this.val$ch);System.out.println(this.val$integer);}}匿名内部类之所以可以访问局部变量是因为在底层将这个局部变量的值传入了匿名内部类中并且以匿名内部类的成员变量存在这个值的传递过程是通过匿名内部类的构造器完成的。我们可以看到匿名内部类引用的局部变量和方法参数以及外部类的引用都会被当做构造函数的参数。但是外部类的成员变量是通过外部类的引用来访问的。那么为什么匿名内部类访问外部类的成员变量无需final修饰呢因为非静态内部类的对象保存了外部类对象的引用因此内部类对外部类成员变量的修改都会真实的反应到外部类实例本身所以不需要final修饰。需要引入两个知识点值传递和引用传递基本类型作为参数传递时传递的是值的引用无论怎么改变这个拷贝原值是不会改变的当对象作为参数传递时传递是对象引用的拷贝无论怎么改变新引用的指向原引用是不会改变的(当然通过新引用改变对象的内容那么改变就是确确实实发生了)。final作用被final修饰基本类型变量不可更改其值当被final修饰引用变量不可改变其指向只能改变对象的内容。于是假设允许不对局部变量加final当匿名内部类里面尝试改变外部基本类型的值的时候或者改变外部引用变量的指向的时候表面上看起来是成功了但是实际上并不会影响到外部的变量。所以java就一刀切强制加上了final修饰。2.4 静态内部类我们上面知道静态内部类是一个独立的类不需要依赖外部类也能存在的。所以静态内部类不能使用外部类非static成员变量或者方法。因为外部类的非静态成员必须依附于具体的对象。静态内部类静态内部类的创建方法外部类.内部类 引用名new 外部类.内部类();public static void main(String[] args) {//静态内部类的创建方法Outer.Inner in new Outer.Inner();in.say();}3. 问题解答看到这里我相信大家应该心里对问题也有了自己的答案。静态内部类是不依附与外部类存在的。而非静态内部类就是外部类的一个成员是需要依附于外部类。非静态内部类中含有构造函数构造函数中会将外部类的引用传入所以内部类可以无条件访问外部类成员。为什么使用final和生命周期是无关的主要是java为了保持内部和外部变量的统一。4. 内部类常见面试题根据注释填写(1)(2)(3)处的代码public class Test{public static void main(String[] args){// 初始化Bean1(1)bean1.I;// 初始化Bean2(2)bean2.J;//初始化Bean3(3)bean3.k;}class Bean1{public int I 0;}static class Bean2{public int J 0;}}class Bean{class Bean3{public int k 0;}}我们可以知道成员内部类必须先产生外部类的实例化对象才能产生内部类的实例化对象。而静态内部类不需要产生实例化对象即可产生内部类的实例化对象。创建静态内部类外部类类名.内部类类名 xxxnew 外部类类名.内部类类名();创建成员内部类外部类类名.内部类类名 xxx外部类对象名.new 内部类类名();因此(1)(2)(3)处的代码分别为Test test new Test();Test.Bean1 bean1 test.new Bean1();Test.Bean2 b2 new Test.Bean2();Bean bean new Bean();Bean.Bean3 bean3 bean.new Bean3();2.下面这段代码的输出结果是什么public class Test {public static void main(String[] args) {Outter outter new Outter();outter.new Inner().print();}}class Outter{private int a 1;class Inner {private int a 2;public void print() {int a 3;System.out.println(局部变量 a);System.out.println(内部类变量 this.a);System.out.println(外部类变量 Outter.this.a);}}}输出答案3 2 1总结内部类和外部类变量的访问权限问题非静态内部类依赖于外部类对象的创建所以非静态类中不能定义静态变量。非静态内部类的构造方法中含有外部类的引用。可以直接使用所有的外部类成员。外部类不能直接使用非静态内部类的成员。除非创建内部类对象。可以把静态内部类看做一个独立的静态类所以不能直接使用一个类的实例成员。匿名类必须继承一个类(抽象类或具体类)或者实现一个接口。new XXX(){};就是一个内部类。只含有private构造方法的类不能被继承所以可以使用protected修饰类以达到让子类继承的目的此时使用匿名内部类的new XXX(){};的方式就可以创建出一个XXX的子类对象。