美文网首页
javap反编译探寻内部类为何能访问外部私有成员

javap反编译探寻内部类为何能访问外部私有成员

作者: 拾识物者 | 来源:发表于2018-10-05 23:30 被阅读55次

Java语言理论告诉我们内部类对象持有外部类对象的一个引用,这说明内部类与外部类还是独立的两个类,只不过内部类对象通过持有外部类的对象的引用来维持这个关系。

通常任何一个类都不可能访问另一个类的私有成员,那么内部类是如何做到访问外部类的私有成员的呢?

其实“持有外部类对象的一个引用”这句话已经给了我们提示,Java代码中并不需要自己去声明这么一个引用,因此是编译器背着我们创建了这个引用。既然编译器有这个习性,它很可能也给外部类的私有成员创建了getter方法使得内部类可以访问。

下面我们用javap命令反编译class文件来探寻这个猜想是否正确。

javap 用法:javap class文件路径 获得类摘要信息,直接输出到标准输出。

第一步,验证内部类对象持有外部类对象的引用。

先定义一个外部类和一个内部类:

class Outer {
    class Inner {
    }
}

使用 javac 编译出class文件,会生成多个class文件:Outer.class Outer$Inner.class
javap Outer$Inner.class 输出:

class Outer$Inner {
  final Outer this$0; // 外部类对象的引用
  Outer$Inner(Outer); // 还生成了一个构造函数,传入了外部类的引用。
}

一个有趣的问题来了:如果Inner显式定义了构造函数会怎么样?

class Outer {
    class Inner {
        private final String name;
        public Inner(String name) {
            this.name = name;
        }
    }
}

javap Outer$Inner.class 输出:

class Outer$Inner {
  final Outer this$0;
  public Outer$Inner(Outer, java.lang.String); // 改造了显式定义的构造函数

第二步,验证外部类生成了私有成员变量的访问器

先添加一个私有成员变量:

class Outer {
    private final int code;
    public Outer(int code) {
        this.code = code;
    }
    class Inner {
        private final String name;
        public Inner(String name) {
            this.name = name;
        }
    }
}

javap输出:

class Outer {
  public Outer(int);
}

可见,内部类不访问外部类私有成员变量时,并没有隐藏的方法声明。

然后,添加内部类对外部类私有成员变量的访问:

class Outer {
    private final int code;
    public Outer(int code) {
        this.code = code;
    }
    class Inner {
        private final String name;
        public Inner(String name) {
            this.name = name;
        }
        public void hello() {
            System.out.println("Inner: hello: " + code);
        }
    }
}

javap Outer.class 输出:

class Outer {
  public Outer(int);
  static int access$000(Outer); // 多了一个静态方法,返回私有成员。
}

再添加一个私有方法:

class Outer {
    private final int code;
    public Outer(int code) {
        this.code = code;
    }
    private void sayhi(String message) {
        System.out.println("Outer: hi, " + message);
    }
    class Inner {
        private final String name;
        public Inner(String name) {
            this.name = name;
        }
        public void hello() {
            System.out.println("Inner: hello: " + code);
            sayhi("this is from inner");
        }
    }
}

javap Outer.class 输出:

class Outer {
  public Outer(int);
  static int access$000(Outer);
  static void access$100(Outer, java.lang.String);
}

结论:

  1. 内部类创建了一个外部类对象的引用,并通过改造构造函数将其传入内部类。
  2. 内部类如果不访问外部类的私有成员,并不会生成访问方法,而是需要的时候才生成。
  3. 外部类生成的访问方法,是static类型的,并传入外部类对象引用,返回值与参数根据需要访问的变量和函数相对应。

相关文章

  • javap反编译探寻内部类为何能访问外部私有成员

    Java语言理论告诉我们内部类对象持有外部类对象的一个引用,这说明内部类与外部类还是独立的两个类,只不过内部类对象...

  • 从反编译内部类来认识final

    为什么内部类可以无条件访问外部类成员? 我们通过 javap -v Outter$Inner 来反编译代码,最终得...

  • 内部类

    内部类概述 内部类访问特点 内部类可以直接访问外部类的私有成员 外部类要访问内部类的成员,必须创建对象 创建内部类...

  • 内部类

    内部类的访问规则:1,内部类可以直接访问外部类中的成员,包括私有。之所以可以直接访问外部类中的成员,是因为内部类中...

  • Java Util包

    内部类 以前:一个类是不能去访问另一个类的私有成员 现在:内部类的作用:可以直接访问外部类的私有成员1:成员内部类...

  • 内部类可以引用它的包含类(外部类)的成员吗?有没有什么限制?

    一个内部类对象可以访问创建它的外部类对象的成员,包括私有成员。

  • 2020-06-21内部类

    内部类 概述:在一个类内部定义一个类; 格式 内部类的访问特点 内部类可以直接访问外部类的成员,包括私有的。 外部...

  • 内部类

    顾名思义内部类就是创建在类内部的一个类 内部类的特点:1、内部类可以直接访问外部类的成员,包括私有2、外部类要访问...

  • java中的四种内部类

    成员内部类 成员内部类作为外部类的成员,能够无条件访问外部类的变量,即使是private的,但是外部类不能直接访问...

  • Java内部类

    成员内部类 和方法的成员放在一个位置上 在内部类中,可以直接访问外部类的私有成员 Outer.Inner...

网友评论

      本文标题:javap反编译探寻内部类为何能访问外部私有成员

      本文链接:https://www.haomeiwen.com/subject/rrkcaftx.html