Java中的内部类

前言: 

        我们都已经学过类和方法了,但是没有讲过什么是内部类,那么这一篇我们就来填上最后一个缺口——内部类。

        当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整结构又只为外部事物提供服务,那么这个内部完整结构最好使用内部类。

        在Java中,可以将一个类定义在另一个类或者一个方法的内部,前者称为内部类,后者称为外部类。

        内部类也是封装的一种体现。

内部类分为:

  1. 实例内部类
  2. 静态内部类
  3. 匿名内部类
  4. 局部内部类。

实例内部类:

        我们先来看实例内部类。实例内部类中不能定义静态常量和静态方法。

        此时我们在OuterClass中定义一个InnerClass实例内部类。之后实例化这个内部类,发现报错。

class OuterClass {
    public int data;
    private int data2;
    public static int data3;

    class InnerClass {
        public int data4 = 4;
        //public static int data5 = 5;//报错

        private int data6 = 6;

        public void test() {
            System.out.println("InnerClass::test()");
        }
    }

    public void test() {
        System.out.println("OutterClass::test()");
    }
}

public class Test2 {
    public static void main(String[] args) {
        InnerClass innerClass = new InnerClass();
        //不能够实例化
    }
}

        也就是说实例内部类不能被直接实例化,但是可以间接实例化。 我们要先实例化外部类,之后通过外部类的对象去初始化外部类中的实例内部类。

OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = outerClass.new InnerClass();

        此时我们就能理解为什么实例内部类不能有静态成员了,因为内部类需要外部类引用调用的,而静态成员不需要实例化,可以直接进行使用,所以互相冲突。

        如果真的需要使用静态,那么可以加上final。

        如果内部类中有和该外部类中相同的名称的变量成员是,在内部类中访问,优先访问内部类中的成员,也就是说遵循就近原则。

        如果因为成员名冲突时,要访问外部类的成员,需要使用 外部类的名字.this.成员名进行访问。

        我们之前说过,一个类就会产生一个字节码文件。那么内部类生成的字节码文件我们执行完代码之后也可以进行查看(在out目录中)。 

        可以发现内部类的字节码文件名是 外部类 $ 内部类。

静态内部类:

        顾名思义,就是前面加上了static关键字的内部类。静态内部类只能去调用其外部类中的静态成员或方法。

class Out {
    public int data1 = 1;
    public static int data2 = 2;
    private int data3 = 3;

    static class InClass {
        public int data4 = 4;
        public static int data5 = 5;
        private int data6 = 6;

        public void test() {
            System.out.println(data1);
            System.out.println(data2);//只能调用外部类的静态成员或方法
            System.out.println(data3);
            System.out.println(data4);
            System.out.println(data5);
            System.out.println("InClass::test()");
        }
    }

    public void test() {
        System.out.println("Out::test()");
    }
}

         静态内部类中如果想调用外部类中的非静态成员,则要先初始化一个外部类,之后通过对象引用调用。

        此时我们就在静态内部类中实例化一其外部类,之后通过外部类的对象去调用里面的非静态成员。

public void test() {
    Out out = new Out();
    System.out.println(out.data1);
    System.out.println(data2);//只能调用外部类的静态成员或方法
    System.out.println(out.data3);
    System.out.println(data4);
    System.out.println(data5);
    System.out.println("InClass::test()");
}

         接下来我们来看如何调用静态内部类:

class Out {
    public int data1 = 1;
    public static int data2 = 2;
    private int data3 = 3;

    static class InClass {
        public int data4 = 4;
        public static int data5 = 5;
        private int data6 = 6;

        public void test() {
            Out out = new Out();
            System.out.println(out.data1);
            System.out.println(data2);//只能调用外部类的静态成员或方法
            System.out.println(out.data3);
            System.out.println(data4);
            System.out.println(data5);
            System.out.println("InClass::test()");
        }
    }

    public void test() {
        System.out.println("Out::test()");
    }
}


public class Test {
    public static void main(String[] args) {
        //Out out = new Out();
        //out.test();
        Out.InClass inClass = new Out.InClass();
        //调用其静态内部类
        inClass.test();
    }
}

         可以发现我们可以不用初始化其外部类,因为是静态的,所以可以直接使用外部类进行实例化。

局部内部类:

        局部内部类:一般在方法中定义,没有什么实际用途。下面代码就是在方法中定义了一个内部类。

public void func() {
    class AA {
        public int a;
    }
    AA aa = new AA();
    System.out.println(aa.a);
}

        也会生成一个字节码文件。

        生成了一个Test2$1AA.class字节码文件,命名规则我们不去讨论。

匿名内部类: 

        匿名内部类一般要使用接口。我们先看代码:

interface IA {
    void test();
}

public class Test2 {
    public static void main(String[] args) {

        new IA() {
            @Override
            public void test() {
                System.out.println("这是重写了接口的方法!");
            }
        };

        IA ia = new IA() {
            @Override
            public void test() {
                System.out.println("这是重写了接口的方法!");
            }
        };
        ia.test();
    }
}

 

        这里先写了一个接口,之后通过Test2直接定义了一个匿名内部类(我也不知道名字别问我),之后重写接口中的方法,最后通过向上转型动态绑定调用重写方法。 

        博主无能,不清楚内部类的作用,希望大佬能说一下。 

        时隔多日,我使用Java的频率又加频繁,我把自己的见解分享给大家:

        匿名内部类说白了,还是类,但是匿名就说明了没有名字,我们如果直接在主函数中定义一个接口,就需要去重写里面所有的方法, 此时没有定义类,但是写完以后竟然发现可以通过变量名去调用里面的方法(就像上面)。

        也就说明我们已经定义了一个类,但这个类没有名字(像我们平时写的public class Test,其中Test就是类名),但此时我们没有想这样定义,所以就没有了类名。

        还是会有用到的时候,希望对大家有帮助,有不同见解评论区见。 

        之前的话不会删除,当以后大家往下面学习,就会使用匿名内部类,特别是Java的集合框架里面会经常使用。

  • 19
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值