• Java中的四种内部类


    目录

    局部内部类

    匿名内部类(重点!!!!!)

    成员内部类

    静态内部类

    总结


    在学习Java中的内部类之前,需要先搞清楚:外部其它类,外部类,内部类之间的关 系:

      内部类就是定义在类的内部的类;外部类指包含有内部类的类;外部其它类是针对包含InnerClass类的OuterClass之外的类。

    内部类可以分为两大类,四小类:

    • 定义在外部类的局部位置上的:局部内部类、匿名内部类
    • 定义在外部类的成员位置上的:成员内部类和静态内部类

    局部内部类

    局部内部类是指定义在外部类的局部位置(通常是方法,还包括代码块)内的有名称的类。

    局部内部类的使用需要注意:

    • 局部内部类可以直接访问外部类的所有属性和方法,包括私有的。局部内部类本质上一个类
    • 局部内部类不能添加访问修饰符,因为它的地位就是一个局部变量,但是可以使用final修饰符
    • 局部内部类的作用域只在方法内或者代码块内
    • 外部类在包含该内部类的方法中,可以创建局部内部类对象,然后调用该局部内部类的方法
    • 外部类和局部内部类重名时,访问遵循就近原则。如果在局部内部类中访问外部类中的变量,可以使用"外部类名.this.属性"(外部类名.this指的是外部类对象)

    局部内部类的实例:

    1. //外部类
    2. class Outer {
    3. private int money = 14000;
    4. private void m1() {
    5. System.out.println("Outer m1()");
    6. }
    7. public void m2() {
    8. //局部内部类
    9. final class Inner {
    10. private int money = 12000;
    11. public void m3() {
    12. System.out.println("Inner m3()");
    13. System.out.println("Outer" + Outer.this.money + " Inner" + money);
    14. m1();
    15. }
    16. }
    17. Inner in = new Inner();//在方法中创建了一个Inner对象
    18. in.m3();
    19. }
    20. }
    21. //外部其它类
    22. public class InnerClassOfPart {
    23. public static void main(String[] args) {
    24. /*
    25. 创建一个Outer对象,访问m2方法,在m2方法的颞部创建了一个局部
    26. 内部类,调用该局部内类的m3()方法,该局部内部类的m3()方法中又调用了外部类中的私有成员变量
    27. money和成员方法m1
    28. */
    29. Outer out = new Outer();
    30. out.m2();
    31. }
    32. }

    匿名内部类(重点!!!!!)

    匿名内部类和局部内部类类似,使用匿名内部类需要注意:

    • 不能添加访问修饰限定符,因为他是一个局部变量
    • 匿名内部类的作用域为定义它的方法内部或者代码块内部
    • 外部其它类不能访问匿名内部类,因为匿名内部类的地位是一个局部变量
    • 在匿名内部类中可以直接访问外部类的所有成员,访问方法使用"外部类名.this.成员"
    • 匿名内部类的使用应该注意语法,匿名内部类既是一个类的定义,同时本身也是一个对对象的引用;因此既有定义类的特征,也有创建对象的特征

    假设现在有一个接口IBell,在接口的内部有一个ring()方法,在开发的过程中需要用这个接口中的ring方法在屏幕中输出"该上课了",那么传统的方法是再定义一个类来实现这个接口,然后覆写该抽象方法。这种做法当然可行,但是如果每次输出的内容都不同,就需要每次都使用不同的类来实现接口,覆写方法吗?匿名内部类的出现就解决了这个问题。

    基于接口的匿名内部类定义和使用:

    1. interface IBell {
    2. void ring();//默认为public abstract void ring()
    3. }
    4. class Cellphone {
    5. public void alarmclock(IBell bell) {
    6. bell.ring();
    7. }
    8. }
    9. public class InnerClassExercise02 {
    10. public static void main(String[] args) {
    11. Cellphone cellphone = new Cellphone();
    12. //使用基于接口的匿名内部类
    13. cellphone.alarmclock(new IBell() {
    14. @Override
    15. public void ring() {
    16. System.out.println("懒猪起床了");
    17. }
    18. });
    19. cellphone.alarmclock(new IBell() {
    20. @Override
    21. public void ring() {
    22. System.out.println("小伙伴上课了");
    23. }
    24. });
    25. }
    26. }

    在上述基于接口的匿名对象类的使用过程中,调用Cellphone类中的alarmclock方法传入的实参即为匿名内部类,对于该种使用方法,在底层其实创建了一个名为InnerClassExercise02$1的实体类,并且在该类实现了接口,覆写了接口中的ring()方法。

    1. class InnerClassExercise02$1 implements IRing {
    2. @Override
    3. public void ring() {
    4. System.out.println("上课了!");
    5. }
    6. }

    在这个过程中发生的调用关系为:

    基于类的匿名内部类定义和使用:

    假如说现在有一个Stu类和一个Certificate类,Stu类的内部含有一个属性male默认为male,有一个f2方法。Certificate类里的含有一个输出证书奖项名称的print方法。但是这时候学生的群体中有一个学生获得了省级一等奖,另一个学生获得了省级二等奖,而其他同学获得的都是省级三等奖。这个时候需要输出获得省级一等奖、二等奖的这两个学生的奖项,按照传统的方法,就是在分别定义两个类继承Cretificate并且覆写print()方法,这样会显得很繁琐。使用基于类的匿名内部类可以解决这个问题,如下:

    1. class Stu {
    2. private String male = "male";
    3. public void f1() {
    4. System.out.println("我是f1");
    5. }
    6. public void f2() {
    7. //anonymous类的使用
    8. new Certificate() {
    9. @Override
    10. public void print() {
    11. System.out.println("XXX省级二等奖");
    12. // System.out.println(Stu.this.male);匿名内部类中可以直接访问外部类中的所有成员
    13. }
    14. }.print();
    15. //匿名类的使用
    16. Certificate certificate = new Certificate() {
    17. @Override
    18. public void print() {
    19. System.out.println("XXX省级一等奖");
    20. }
    21. };
    22. certificate.print();//调用的是匿名类中覆写过的方法
    23. }
    24. }
    25. class Certificate {
    26. public void print() {
    27. System.out.println("XXX省级三等奖");
    28. }
    29. }
    30. public class AnonymousInnerClass {
    31. public static void main(String[] args) {
    32. Stu stu = new Stu();
    33. stu.f2();
    34. }
    35. }
    36. //输出:
    37. //XXX省级二等奖
    38. //XXX省级一等奖

    在上述基于类的匿名对象类的使用过程中,实际上在底层创建了一个名为Stu$2的继承自Certificate的类并且覆写了父类中的print方法:

    1. class Stu$2 extends Certificate {
    2. @Override
    3. public void print() {
    4. System.out.println("XXX省级X等奖");
    5. }
    6. }

    在这个过程中发生的调用关系为:

    成员内部类

    成员内部类是指定义在外部类的成员位置山的类。本质上是一个成员,具有成员的属性,因此使用成员内部类需要注意:

    • 成员内部类可以直接访问内部类的所有成员
    • 成员内部类的作用域为外部类内
    • 成员内部类可以添加任意一种访问修饰限定符,因为它本质上是作为一个成员存在
    • 外部类实例化成员内部类有两种方法:
      ①先实例化外部类成员变量,再实例化成员内部类
      ②在外部类中提供getInstance返回成员内部类的实例
    1. class Dog {
    2. private int age = 6;
    3. private String name = "huahua";
    4. //定义成员内部类
    5. public class DogOfJack {
    6. int gg;
    7. public void print() {
    8. System.out.println("Jack's Dog " + Dog.this.name +" 的内部类");
    9. }
    10. }
    11. public void f1() {
    12. new DogOfJack().print();
    13. }
    14. public DogOfJack getInstance() {
    15. return new DogOfJack();
    16. }
    17. }
    18. public class MemberInnerClass {
    19. public static void main(String[] args) {
    20. Dog dog = new Dog();
    21. Dog.DogOfJack dogOfJack1 = new Dog().new DogOfJack();
    22. dogOfJack1.print();
    23. Dog.DogOfJack dogOfJack2 = dog.getInstance();
    24. dogOfJack2.print();
    25. }
    26. }

    静态内部类

    静态内部类与成员内部类相似,不过被static关键字修饰。但是其本质还是作为一个成员存在,使用静态内部类的注意事项:

    • 在静态内部类中只能访问外部类中的静态变量,因为其本身被static关键字修饰
    • 作为成员,静态内部类可以添加任意的访问修饰限定符
    • 外部其它类实例化静态内部类:使用类名.属性实例化静态内部类
    1. class Dog {
    2. private static int age = 6;
    3. private String name = "huahua";
    4. //定义成员内部类
    5. static public class DogOfJack {
    6. int gg;
    7. public void print() {
    8. System.out.println("Jack's Dog " + Dog.age +" 的内部类");
    9. }
    10. }
    11. public void f1() {
    12. new DogOfJack().print();
    13. }
    14. public DogOfJack getInstance() {
    15. return new DogOfJack();
    16. }
    17. }
    18. public class MemberInnerClass {
    19. public static void main(String[] args) {
    20. Dog dog = new Dog();
    21. Dog.DogOfJack dogOfJack = new Dog.DogOfJack();
    22. dogOfJack.print();
    23. }
    24. }
    25. //输出:Jack's Dog 6 的内部类

    总结

    Java中的内部类有四种,可以根据其分别定义在外部类的局部位置上、成员位置上将内部类分为局部内部内、匿名内部类和成员内部类、静态内部类,其中使用最多的为匿名内部类。

    • 局部内部类:定义在外部类的方法或者代码块中,作为类存在。作用域为方法或者代码块内部。局部内部类可以直接访问外部类的所有成员,通过外部类名.this.属性的方法访问外部类中的属性。
    • 匿名内部类:定义在外部类的方法或者代码块中。匿名内部类分为基于接口的匿名内部类和基于对象的匿名内部类,在使用匿名内部类时要注意继承、多态和动态绑定。匿名内部类的作用域和局部内部类相同,注意匿名内部类具有类的特征也具有对象的特征,外部类无法访问。匿名内部类可以直接访问外部类的所有属性,通过外部类名.this.属性访问。
    • 成员内部类:定义在外部类的成员位置上,作为一个成员存在,作用域为外部类内。可以访问外部类中的所有属性,通过外部类名.this.属性访问。
    • 静态内部类:与成员内部类类似,位于外部类的成员位置上,在类内不能使用this关键字,同时在类的内部只能通过类名.属性访问外部类中的静态变量
  • 相关阅读:
    注意力机制 -自注意力和位置编码
    消灭空指针,Java 8 给我们更好的解决方案
    第12期 | GPTSecurity周报
    SQL 改写系列十:半连接转内连接
    面试经典150题——Day19
    <一>Qt斗地主游戏开发:开发环境搭建--VS2019+Qt5.15.2
    记go语言椭圆曲线算法公私钥验证补充
    课程思政案例
    拉线位移传感器的输出信号分为几种,小编让大家明白
    deepin-anything 源码刨析
  • 原文地址:https://blog.csdn.net/weixin_64450588/article/details/127802764