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

内部类通过持有外部类对象的引用实现访问其私有成员。在编译过程中,Java为外部类的私有成员生成了访问器方法,这些方法在内部类中以静态方式存在,允许内部类访问外部类的私有属性和方法。只有在内部类实际访问外部类私有成员时,才会生成相应的访问方法。
摘要由CSDN通过智能技术生成

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);

}

结论:

内部类创建了一个外部类对象的引用,并通过改造构造函数将其传入内部类。

内部类如果不访问外部类的私有成员,并不会生成访问方法,而是需要的时候才生成。

外部类生成的访问方法,是static类型的,并传入外部类对象引用,返回值与参数根据需要访问的变量和函数相对应。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值