故乡魂

网友投稿 207 2022-10-23


故乡魂

https://bbs.pku.edu.cn/v2/post-read.php?bid=459&threadid=17733059 package com.example.nestedclassdemo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * 嵌套类 Nested classes * - 静态嵌套类: Static nested classes,即类前面有static修饰符 * - 非静态嵌套类: Non-static nested classes,又名内部类,Inner classes * - 普通内部类(亦翻译为:成员内部类) * - 局部内部类(Local classes) * - 匿名内部类(Anonymous classes) * * 为什么需要嵌套类 * - 不同的访问权限要求,更细粒度的访问控制 * - 简洁,避免过多的类定义 * - 语言设计过于复杂,较难学习和使用 * * 匿名内部类:Anonymous classes * - 没有类名的内部类,必须继承一个父类/实现一个父接口 * - 在实例化以后,迅速转型为父类/父接口 * - 这种类型的对象,只能new一个对象,之后以对象名字操作 * - 可在普通语句和成员变量赋值时使用内部类 * * 局部内部类:Local classes * - 定义在代码块中的非静态的类,如方法,for循环,if语句等 * - 定义后,即可创建对象使用 * - 只能活在这个代码块中,代码块结束后,外界无法使用该类 * * 了解匿名内部类和局部内部类 * - 两者几乎相似 * - 局部内部类可以重用,匿名内部类不能重用 * - 匿名内部类更简洁 * * 普通内部类 * - 非static的类,定义在某个类的成员变量位置 * - 定义后,在类里面均可以使用 * * 静态嵌套类 * - 层级和包围类(enclosing class)的成员变量/方法一样 * - 第三方需要通过外部包围类才可以访问到静态嵌套类 * * 了解普通内部类和静态嵌套类 * - 两者都定义在外围类中的成员级别 * - 静态嵌套类不依赖于外围类对象,但是只能访问外围类的静态成员 * - 普通内部类必须依赖于外围类对象,不能单独存在,但是可以访问外围类的所有成员 * * 四种类对比(1) * Oracle官方文档比较 * - 匿名内部类:应用它,如果需要定义额外的变量和方法 * - 局部内部类:在一个方法内,需要创建一个新的类型,并重复使用 * - 普通内部类:和局部内部类相似,在一个类中定义,可重复使用,可以访问外部类成员,但不需要访问外部类方法的形参和内部变量 * - 静态嵌套类:在一个类中定义,可重复使用,并需要访问外部类的静态成员 * * 外部访问规则 * 外部访问和修饰符关系 * - 普通内部类和静态嵌套类可以被外部访问 * - 外部访问普通内部类和静态嵌套类,和普通类之间访问规则一样 * * 变量遮蔽 Shadowing * - 嵌套类变量和外部包围类的变量重名 * - 以离得近作为优先原则 * - 优先级高的变量会遮蔽优先级低的变量 * - 外部包围类.this.变量名,可以访问到外部包围类的成员变量 * - 静态嵌套类不能访问非静态变量 * - Java7及以前,匿名内部类和局部内部类只能访问外部包围类的final成员变量 * - Java8及以后,匿名内部类和局部内部类可访问外部包围类的final成员变量和事实意义上的final变量 * * * * * * * * */ @SpringBootApplication public class NestedclassDemoApplication { public static void main(String[] args) { SpringApplication.run(NestedclassDemoApplication.class, args); } } package com.example.nestedclassdemo; /** * 匿名内部类 * - 没有正式类名的内部类 * - 编译器产生内部名字: 类名+$+数字编号 * - 没有类名,没有构造函数,能用父类/父接口的构造函数(可带参数) * - 可以继承,改写,补充父类/父接口的方法 * - 内部不可以新定义静态成员(变量+方法),常量除外 * - final static int a = 5; * - 可以访问外部包围类的成员变量和方法(包括private) * - 如果定义在静态方法中,也只能访问外部包围类的静态成员 * - 没有类名,外部包围类和其他类也无法访问到匿名内部类 */ public class Outer1 { private String name = "abc"; public void f1(){ String name = "def"; Runnable r = new Runnable() { //匿名内部类不能定义静态变量,除非是常量 public final static int a = 5; //public static int b = 3; String name = "ghi"; @Override public void run() { System.out.println("hello "+name); } //静态方法不能在匿名内部类定义 //public static void f2(){} }; new Thread(r).start(); System.out.println(r.getClass().getName()); //编译后会产生第二个class匿名内部类 Runnable r2 = new Runnable() { @Override public void run() { System.out.println("hello "+Outer1.this.name); } }; new Thread(r2).start(); System.out.println(r2.getClass().getName()); } } package com.example.nestedclassdemo; import java.io.Serializable; /** * 局部内部类: Local classes * - 编译后名称: 外部类名+$+序号+内部类名 * - 可以继承其他类,或者实现其他接口 * - 非静态的类,不能包含静态成员(变量和方法),除了常量 * - 可以访问外部包围类的成员 * - 如果定义在静态方法中,只能访问包围类的静态成员 * - 局部内部类不能是一个接口,即接口不能定义在代码块中 */ public class Outer2 { String name = "abc"; //局部内部类 public void f1(){ String name = "def"; class Inner2 extends Outer1 implements Runnable, Serializable { final static int a = 1; //不允许定义静态普通类成员 //static int b = 2; String name = "ghi"; public void f2(){ System.out.println(name); System.out.println(Outer2.this.name); } @Override public void run() { System.out.println(name); } } Inner2 obj1 = new Inner2(); obj1.f2(); System.out.println(obj1.getClass().getName()); } //局部内部类 public static void f2(){ final String name = "def"; class Inner2{ public String f2(){ return "this is f2()"; } } Inner2 inner2 = new Inner2(); String s = inner2.f2(); System.out.println(s); System.out.println(inner2.getClass().getName()); } } package com.example.nestedclassdemo.shadow; public class ShadowTest { public int x = 0; class FirstLevel{ public int x = 1; void methodInFirstLevel(int x){ System.out.println("x = "+x); //line 10 x System.out.println("this.x = "+this.x); //line 8 x System.out.println("ShadowTest.this.x = "+ShadowTest.this.x); //line 5 x } } public static void main(String... args){ ShadowTest st = new ShadowTest(); ShadowTest.FirstLevel f1 = st.new FirstLevel(); f1.methodInFirstLevel(20); } } package com.example.nestedclassdemo.shadow; public class ShadowTest2 { public int x = 0; public void f1(){ //局部内部类无法访问得到! int x = 20; class FirstLevel{ public int x = 1; void methodInFirstLevel(int x){ System.out.println("x = "+x); //line 14 x System.out.println("this.x = "+this.x); //line 12 x System.out.println("ShadowTest.this.x = "+ShadowTest2.this.x); //line 5 x } } FirstLevel obj = new FirstLevel(); obj.methodInFirstLevel(10); } public static void main(String... args) { ShadowTest2 st = new ShadowTest2(); st.f1(); } } package com.example.nestedclassdemo.shadow; public class ShadowTest3 { public int x = 0; public void f1(){ //可以访问得到,没有被遮蔽! int x = 20; class FirstLevel{ void methodInFirstLevel(){ System.out.println("x = "+x);//line 9 x System.out.println("ShadowTest3.this.x = "+ShadowTest3.this.x); //line 5 x } } //x=30; FirstLevel obj = new FirstLevel(); obj.methodInFirstLevel(); } public static void main(String... args) { ShadowTest3 st = new ShadowTest3(); st.f1(); } } package com.example.nestedclassdemo.outer3; public class Animal { String name; } package com.example.nestedclassdemo.outer3; public interface Flyable { void fly(); } package com.example.nestedclassdemo.outer3; /** * 普通内部类 * - 编译后名称: 外部类名+$+内部类名 * - 可以继承其他类,或者实现其他接口 * - 可以用private/package private(不写)/protected/public控制外界访问 * - 非静态的类,不能包含静态变量/方法,除了常量 * - 和外部包围类的实例相关,一个普通内部类实例肯定是在一个外部包围类的实例中, * 且可以访问外部包围类的所有成员 * - 在第三方类中,需要先创建外部包围类实例,才能创建普通内部类的实例, * 不允许单独的普通内部类对象存在!!! */ public class Outer3 { String name = "aaaaaa"; public class Bird extends Animal implements Flyable{ //常量OK public static final int a = 3; //不能定义非常量的static变量 //public static int b = 4; @Override public void fly() { System.out.println(Outer3.this.name+" can fly"); } } public Bird b1 = new Bird(); public void f1(){ b1.fly(); System.out.println(b1.getClass().getName()); this.name = "bbbbbb"; b1.fly(); } public Bird getBird(){ return this.b1; } } package com.example.nestedclassdemo.outer3; public class Outer3Test { public static void main(String[] args) { Outer3 foo1 = new Outer3(); foo1.f1(); Outer3.Bird foo2 = foo1.new Bird(); foo2.fly(); System.out.println(foo2 == foo1.getBird()); //foo1对象下,有2个内部类对象和它关联 //不允许没有关联的单独的普通内部类对象 //Outer3.Bird foo3 = new Outer3().Bird(); } } package com.example.nestedclassdemo.outer4; /** * 静态嵌套类的语法总结 * - 需要加修饰符static * - 可以定义静态成员和非静态成员 * - 不能直接访问包围类的非静态成员,可直接访问包围类的静态成员 * = 可通过包围类的对象进行访问非静态成员 * - 外界可以通过静态嵌套类名访问其静态成员,通过对象访问其非静态成员 * - 外界需要通过包围类才可以访问到静态嵌套类,并创建其对象,不需要外部包围类的实例 */ public class Outer4 { private String outField1 = "outer 111"; private static String outStaticField2 = "outer static 222"; /** * 静态嵌套类 */ public static class Inner4{ //静态嵌套类可以定义静态和非静态成员 private String innField1 = "inner 333"; static String innStaticField2 = "inner static 444"; public void innFun1(){ //静态嵌套类可以直接访问包围类的静态成员 System.out.println(innField1); //System.out.println(Outer4.outField1); System.out.println(Outer4.outStaticField2); System.out.println(outStaticField2); //静态嵌套类可以通过对象访问包围类的非静态成员 Outer4 outObj = new Outer4(); System.out.println(outObj.getOutField1()); } public String getInnField1(){ return this.innField1; } public static String getInnStaticField2(){ hello(); return innStaticField2; } public static void hello(){ System.out.println("inner hello"); } } public String getOutField1(){ return this.outField1; } public static void outFun2(){ Inner4 obj1 = new Inner4(); Inner4 obj2 = new Inner4(); System.out.println(obj1==obj2);//false System.out.println(obj1.getInnField1()); System.out.println(Inner4.getInnStaticField2()); } public static void hello(){ System.out.println("outer hello"); } } package com.example.nestedclassdemo.outer4; public class Outer4Test { public static void main(String[] args) { //第三方类访问静态嵌套类 Outer4.Inner4 obj1 = new Outer4.Inner4(); String innField1 = obj1.getInnField1(); System.out.println("innField1:"+innField1); Outer4.Inner4 obj2 = new Outer4.Inner4(); System.out.println(obj1==obj2); System.out.println("===================="); Outer4 obj3 = new Outer4(); Outer4.outFun2(); } }


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:如何为SUSE配置IP地址,网关和DNS
下一篇:教你利用springboot集成swagger并生成接口文档
相关文章

 发表评论

暂时没有评论,来抢沙发吧~