Nested Classes(内部类,嵌套类)

/ 默认分类 / 0 条评论 / 1063浏览

内部类(嵌套类)

内部类属于基础知识点,但是之前的确没有总结一下内部类,只是想当然的使用,很多框架的源码也经常使用内部类(比如最近看的MQ),今天在工作中使用mybatis的时候遇到一个问题,所以记录一下,顺便总结下:

public class AMQImpl implements AMQP {

    public static class Connection {
        public static final int INDEX = 10;

        public static class Start
            extends Method
            implements com.rabbitmq.client.AMQP.Connection.Start

1. 介绍

oracle官方文档

在java中你可以在一个类中嵌套另一个类,嵌套的这个类叫做内部类,内部类分为两种,一种是就叫内部类,另一种叫做静态内部类

下面我写了一例子,其实静态内部类就是使用static修饰的类

@Data
public class Outer {

    String outerCommonVar;

    private String outerPrivateVar;

    static String outerStaticVar;

    static private String outerPrivateStaticVar;

    class Inner{
        String innerVar = outerCommonVar = outerPrivateVar = outerStaticVar = outerPrivateStaticVar;
    }

    static class StaticInner{
        String staticInnerVar = outerCommonVar = outerPrivateVar = outerStaticVar = outerPrivateStaticVar;
    }

}

编辑器中显示:

上面的代码,就可以看出,静态内部类和内部类的区别: 首先,内部类可以访问外部类的所有访问级别的属性,包括私有属性

  1. 静态内部类可以想象成类中的静态方法,所以不能访问外部类的非静态属性
  2. 内部类可以访问外部类的所有属性

2.那么怎样创建内部类和静态内部类呢?

在来看下面的代码:

public class TestInner {

    public void test1(){
        Outer outer = new Outer();
        Outer.StaticInner staticInner = new Outer.StaticInner();
        Outer.Inner inner = outer.new Inner();
    }

}

可以看出,静态内部类可以认为是一个独立的类,不受外部类的约束,你可以在任何地方直接new出来
但是内部类相当于属于父类的一个成员变量,它的创建必须是在外部类已经已经实例化之后,使用外部类才能创建

ps:其实这不难理解,就是static变量的理解就可以了,static是静态资源修饰符,static属性会在字节码加载到jvm 时就赋值完毕,不需要等到对象创建到堆内存,所以static属性我们都是可以直接使用类名直接访问,不需要使用对象来访问 所以静态内部类也是一样的道理,使用外部类的类名直接标明你需要创建的是谁就可以了:

Outer.StaticInner staticInner = new Outer.StaticInner();

这里的Outer.可以理解为和包名是类似的,只是指明需要创建的是哪一个类,这个类在哪里

3.为什么要有内部类

下面的几点摘录自oracle官方翻译后:

4. 补充说明


public class ShadowTest {

    public int x = 0;

    class FirstLevel {

        public int x = 1;

        void methodInFirstLevel(int x) {
            System.out.println("x = " + x);
            System.out.println("this.x = " + this.x);
            System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);
        }
    }

    public static void main(String... args) {
        ShadowTest st = new ShadowTest();
        ShadowTest.FirstLevel fl = st.new FirstLevel();
        fl.methodInFirstLevel(23);
    }
}

结果:  
x = 23
this.x = 1
ShadowTest.this.x = 0

5. MyBatis中使用内部类作为查询result

    @Select("query sql")
    List<Outer.Inner> testQuery();

如果这样使用查询,那么Inner必须是静态内部类,否则会报错无法找到Inner的构造方法;这是因为非静态内部类的实例化一定需要实例化的外部类, 但是mybatis这里的查询使用的是反射直接生成封装类,父类是没有创建的;只要把Inner修改为静态内部类即可