Java中的四种内部类

我发现最近真是越来越没有东西写了。。。不可能天天学习新知识啊,最近在复习阶段了,复习的东西大多数是博客里写过的/(ㄒoㄒ)/

复习Java基础的时候认真看了一下Java的内部类,这东西之前了解过,但是没有写过代码实验一下,今天就来手写代码夯实夯实基础。也懒得写那么多文字了,博客精简一点剩下时间用来复习。

Java中的内部类分为:
+ 普通内部类:也叫成员内部类
+ 局部内部类
+ 静态内部类
+ 匿名内部类

普通内部类

普通内部类就是直接写在宿主类中的(我这篇文章中称为宿主类,和外部类区分开),并且不带static,如下:

public class TestInnerClass {
    private String outerName = "outer";

    //普通内部类
    public class InnerClass1{
        // 普通内部类可以访问宿主类的一切属性
        public String name = outerName+": "+"InnerClass1";
    }

    @Test
    public void testNormal(){
        // 创建一个普通内部类对象
        InnerClass1 innerClass1 = new InnerClass1();
        // 宿主类可以访问其属性
        System.out.println(innerClass1.name);
    }
}

为什么普通内部类可以带public这种访问修饰符呢?外部类可以创建一个它的实例对象吗?

验证如下:

public class TestInnerClass2 {
    @Test
    public void test(){
        // 首先创建一个宿主类的对象
        TestInnerClass t = new TestInnerClass();
        // 通过宿主类的对象new出一个内部类的对象
        TestInnerClass.InnerClass1 innerClass1 = t.new InnerClass1();
        // 可以获取内部类public的属性
        System.out.println(innerClass1.name);
    }
}

普通内部类是依存于宿主类的实例对象存在的,通过宿主类的实例对象才能new出一个内部类的实例,不得不说,这个语法还蛮少见的。

当然,如果普通内部类声明为private的,外部类就不可以访问了。

局部内部类

局部内部类是宿主类的一个方法中的,比较特殊:

public class TestInnerClass3 {
    @Test
    public void test(){
        String methodName = "test";
        // 局部内部类,生效范围为方法内部作用域
        class InnerClass3{
            // 可以获取方法中声明的局部变量
            public String className = methodName+": InnerClass3";
        }
        // 在方法中可以使用
        InnerClass3 innerClass3 = new InnerClass3();
        System.out.println(innerClass3.className);
    }
}

但是局部内部类有一个特点是不能加上访问权限限定符,例如public、private:

public class TestInnerClass3 {
    @Test
    public void test(){
        String methodName = "test";
        // 报错!!!
        public class InnerClass3{
            public String className = methodName+": InnerClass3";
        }
        InnerClass3 innerClass3 = new InnerClass3();
        System.out.println(innerClass3.className);
    }
}

但是可以加上abstract、final这样的修饰符。

静态内部类

静态内部类和普通的类最为相似,唯一的区别可以看作就是要通过一个类来获取。这种内部类平时也是用的比较多的,所以这里也不特别说明。

public class TestInnerClass4 {
    private static String className = "TestInnerClass4";
    public static class InnerClass4{
        // 只能获取宿主类的静态字段
        private String name = className+": InnerClass4";
    }
}

匿名内部类

匿名内部类平时也用的特别多,常见的例子就是new一个Thread:

public class TestInnerClass5 {
    public static void main(String[] args) {
        new Thread(){
            @Override
            public void run() {
                System.out.println("线程启动");
            }
        }.start();
    }
}

这里实际上是创建了一个Thread的子类,并重写了run方法。

会不会生成单独的class文件

经过测试,所有内部类都会产生单独的class文件,并且命名是:

  • 普通内部类和静态内部类都是:(宿主类名)$(内部类名)
  • 局部内部类是:(宿主类名)$(编号)(内部类名)
  • 匿名内部类是:(宿主类名)$(编号)

普通内部类能访问宿主类实例字段的原理

  1. 编译器自动为内部类添加一个成员变量,该成员变量的类型和外部类的类型相同,这个成员变量就是指向外部类对象引用。
  2. 编译器自动为内部类的构造方法添加一个参数,参数的类型是外部类的类型,在构造方法内部使用这个参数为1中添加的成员变量赋值。
  3. 在调用内部类的构造函数初始化内部类对象时,会默认传入外部类的引用。

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/java%e4%b8%ad%e7%9a%84%e5%9b%9b%e7%a7%8d%e5%86%85%e9%83%a8%e7%b1%bb/

发表评论

电子邮件地址不会被公开。