• JavaSE基础之(十九)Java内部类



    在 Java 中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类叫做内部类。一般来说,内部类分为成员内部类、局部内部类、匿名内部类和静态内部类。

    内部类是一种实现多继承效果的方式。

    21.1 成员内部类

    成员内部类的位置类似于成员变量,定义在类中方法外:

    /**
     * @author QHJ
     * @date 2022/9/19  13:46
     * @description: 成员内部类
     */
    public class ConstructorInnerClass {
        String name = "外部类";
        
        class ConstructorInnerClass2{
            String name = "成员内部类";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    内部类 ConstructorInnerClass2 就好像 ConstructorInnerClass 的一个成员,成员内部类可以无限制访问外部类的所有成员属性和成员方法(包括私有成员和静态成员)

    /**
     * @author QHJ
     * @date 2022/9/19  13:46
     * @description: 成员内部类
     */
    public class ConstructorInnerClass {
        String name = "外部类";
        boolean flag = true;
        private int age = 22;
        static double money = 100;
    
        class ConstructorInnerClass2{
            String name = "成员内部类";
    
            public void print(){
                System.out.println(flag);
                System.out.println(age);
                System.out.println(money);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    不过需要注意的是,当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果需要访问外部类的同名成员,需要使用 外部类.this.成员变量外部类.this.成员方法进行访问:
    在这里插入图片描述

    内部类可以随心所欲地访问外部类的成员,但外部类想要访问内部类的成员就不那么容易了。必须先创建一个成员内部类的对象,再通过这个对象来访问:

    /**
     * @author QHJ
     * @date 2022/9/19  13:46
     * @description: 成员内部类
     */
    public class ConstructorInnerClass {
        String name = "外部类";
        boolean flag = true;
        private int age = 22;
        static double money = 100;
    
        class ConstructorInnerClass2{
            String name = "成员内部类";
    
            public void print(){
                System.out.println(flag);
                System.out.println(age);
                System.out.println(money);
            }
        }
    
        public static void main(String[] args) {
            ConstructorInnerClass constructorInnerClass = new ConstructorInnerClass();
            // 先创建内部类的对象
            ConstructorInnerClass2 constructorInnerClass2 = constructorInnerClass.new ConstructorInnerClass2();
            // 访问内部类的方法
            constructorInnerClass2.print();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    这也就意味着,如果想要在静态方法中访问成员内部类,就必须先得创建一个外部类的对象,因为内部类是依附于外部类的。

    但是这种创建内部类的方式在实际开发中并不常用,因为内部类和外部类紧紧地绑定在一起,使用起来非常不便。

    内部类可以拥有 private 访问权限、protected 访问权限、public 访问权限及包访问权限。比如上面的例子,如果成员内部类 ConstructorInnerClass2 用 private 修饰,则只能在外部类的内部访问,如果用 public 修饰,则任何地方都能访问;如果用 protected 修饰,则只能在同一个包下或者继承外部类的情况下访问;如果是默认访问权限,则只能在同一个包下访问。这一点和外部类有一点不一样,外部类只能被public 和包访问两种权限修饰。我个人是这么理解的,由于成员内部类看起来像是外部类的一个成员,所以可以像类的成员一样拥有多种权限修饰。

    21.2 局部内部类

    局部内部类是定义在一个方法或者一个作用域里面的类,所有局部内部类的生命周期仅限于作用域内:

    /**
     * @author QHJ
     * @date 2022/9/19  14:09
     * @description: 局部内部类
     */
    public class LocalInnerClass {
    
        public void print() {
    
            class LocalInnerClass2 {
                private int age = 22;
    
                public void print2() {
                    System.out.println(age);
                }
            }
    
            LocalInnerClass2 localInnerClass2 = new LocalInnerClass2();
            localInnerClass2.print2();
        }
    
        public static void main(String[] args) {
            LocalInnerClass localInnerClass = new LocalInnerClass();
            localInnerClass.print();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    局部内部类就好像一个局部变量一样,它是不能被权限修饰符修饰的,比如 publicprotectedprivatestatic等:
    在这里插入图片描述

    21.3 匿名内部类

    匿名内部类是平常用的最多的,尤其是启动多线程的时候会经常用到,并且 IDE 也会帮我们自动生成:

    /**
     * @author QHJ
     * @date 2022/9/19  14:25
     * @description: 匿名内部类
     */
    public class AnonymousInnerClass {
        public static void main(String[] args) {
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
            t.start();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    匿名内部类就好像是一个方法的参数一样,用完就没了,以至于我们都不需要为它专门写一个构造方法,它的名字也是由系统自动命名的。观察一下编译后的字节码文件也可以发现,匿名内部类连名字都没有,而是直接借用的外部类,然后 $1 就搞定了。

    匿名内部类是唯一一种没有构造方法的类,不允许我们为其编写构造方法,因为它就像是直接通过 new 关键字创建出来的一个对象。

    匿名内部类的作用主要是用来继承其他类或者实现接口,并不需要增加额外的方法,方便对继承的方法进行实现或者重写。

    21.4 静态内部类

    静态内部类和成员内部类类似,只是多了一个static关键字:

    /**
     * @author QHJ
     * @date 2022/9/19  14:43
     * @description: 静态内部类
     */
    public class StaticInnerClass {
        static int age = 22;
        double money;
    
        static class StaticInnerClass2 {
            public void print() {
                // 只能访问静态变量
                System.out.println(age);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    由于 static关键字的存在,静态内部类是不允许访问外部类中的非静态变量和方法的:
    在这里插入图片描述
    静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非 static 成员变量或者方法。因为在没有外部类的情况下,可以创建静态内部类的对象,如果允许访问类的非静态成员就会产生矛盾,因为外部类的非静态成员是必须依附于具体的对象的。

    21.5 总结

    为什么要使用内部类?

    在《Think in java》中有这样一句话:

    使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。

    在我们程序设计中有时候会存在一些使用接口很难解决的问题,这个时候我们可以利用内部类提供的、可以继承多个具体的或者抽象的类的能力来解决这些程序设计问题。可以这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。

    使用内部类还能够为我们带来如下特性(摘自《Think in java》):

    1、内部类可以使用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。
    2、在单个外部类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。
    3、创建内部类对象的时刻并不依赖于外部类对象的创建。
    4、内部类并没有令人迷惑的 “is-a” 关系,他就是一个独立的实体。
    5、内部类提供了更好的封装,除了该外围类,其他类都不能访问。

  • 相关阅读:
    论文解读(GSAT)《Interpretable and Generalizable Graph Learning via Stochastic Attention Mechanism》
    mysql 数据去重的三种方式[实战]
    Python快速刷题网站——牛客网 数据分析篇(八)
    nacos配置启动
    什么是代币销毁?如何从流通中移除加密货币?
    LeetCode 每日一题 2023/9/4-2023/9/10
    嵌入式-Linux基础操作
    opencv 提取选中区域内指定hsv颜色的水印
    uniapp、vue实现滑动拼图验证码
    【深度学习环境】windows平台
  • 原文地址:https://blog.csdn.net/qq_50994235/article/details/126930058