大家好,我是tin,这是我的第23篇原创文章
之前写过一篇文章,是关于cglib为什么不能代理私有方法的,详细可阅读这里:面试官:cglib为什么不能代理private方法?
文章核心观点就是cglib代理是通过a**字节码技术生成了目标类的子类,并重写了目标类的方法。因为子类不能访问父类私有方法,cglib没有重写私有方法,所以也就不能代理私有方法。
有个读者提出来我的说法不对,子类可以通过反射调用父类私有方法:
这是个好问题,我们确实可以通过反射访问父类的私用方法。
比如这样:
package com.tin.example.cglib.cglib;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* title: AClass
* <p>
* description:
*
* @author tin @【看点代码再上班】 on 2022/1/16 下午6:13
*/
public class AClass {
private void print() {
System.out.println("A");
}
private String doSomething() {
return "i am tin @【看点代码再上班】";
}
public static void main(String[] args)
throws NoSuchMethodException,
IllegalAccessException,
InstantiationException,
InvocationTargetException {
//通过反射访问父类的private方法
Class<?> clazz = BClass.class;
Class<?> superClazz = clazz.getSuperclass();
Method method = superClazz.getDeclaredMethod("doSomething");
Object res = method.invoke(superClazz.newInstance());
System.out.println(res);
}
}
class BClass extends AClass {
public void print() {
System.out.println("B");
}
}
Object res = method.invoke(superClazz.newInstance());也能实现子类调用父类的private方法,从输出结果看确实也是:
既然如此,为什么cglib不通过反射机制,在动态生成字节码的时候生成实现代理私有方法?
比如,在遇到private方法时,生成一个同名的方法,并在方法中通过反射实现调用业务类的private方法。比如以下是当前cglib重写的public方法:
这个好问题我先是去咨询了chatgpt,不过,它的回答过程让我大吃一惊。
第一问:cglib为什么不通过反射支持代理私有方法?
gpt的回答是不严谨的,就在图中我划线的地方,“反射只能访问公共方法和属性”是错误的,Java可以通过getDeclaredMethod访问私有方法。
❝小贴士:
getDeclaredMethod:获取当前类的所有声明的方法,包括public、protected和private修饰的方法。需要注意的是,这些方法一定是在当前类中声明的,从父类中继承的不算,实现接口的方法由于有声明所以包括在内。
getMethod:获取当前类和父类的所有public的方法。这里的父类,指的是继承层次中的所有父类。比如说,A继承B,B继承C,那么B和C都属于A的父类。
❞
第二问:getDeclaredMethod不是可以访问私有方法么,为什么说反射只能访问公共方法和属性
gpt承认错误倒是很快哈哈,很明显是错误的说法。
第三问:cglib为什么不通过反射支持代理私有方法
gpt这里回答就真不知道害羞啦,说cglib通过直接修改类的字节码实现了代理私有方法的功能,而且,这样生成的类可以更好地遵守Java语言规范
我再声明一次,现在的cglib不能代理private方法,gpt的说法是错误的。
第四问:你错了,你说cglib实现了代理私有方法的功能,其实并没有
gpt承认错误是真的快,不过它的回答不够严谨,“字节码技术并不能让cglib破坏Java的访问权限”是不对的,字节码技术只是一个工具,至于你要生成什么样的代码是使用者决定的。
第五问:我觉得你说话不够严谨,你说字节码技术不能让cglib破坏Java的访问控制权限,但cglib可以在通过字节码添加的代理逻辑方法中通过反射实现代理私有方法,只是cglib没有这么做,字节码自己本身是可以破坏Java的访问权限的
到这里才是一个比较严谨的最终答案,确实可以通过反射实现代理私有方案,cglib没有这么做,是出于Java类库设计的目的,为了不破坏类的封装和安全性,遵循Java开发规范,所以没有做。
第六问:我指正了你这么多错误,你能告诉我下周哪个股票会涨么
哈哈跟gpt皮了一下,这回答给我的感觉是它毕竟还是个机器人!
其实gpt也不是完美的,也有很多漏洞,但是,gpt让我感到敬畏,学习能力之强令人敬畏,我相信通过大量的训练,以后的gpt强大得更让人无法想象。
结语
我是tin,一个在努力让自己变得更优秀的普通工程师。自己阅历有限、学识浅薄,如有发现文章不妥之处,非常欢迎加我提出,我一定细心推敲并加以修改。
看到这里请安排个(点赞、分享)再走吧,坚持创作不容易,你的正反馈是我坚持输出的最强大动力,谢谢!
本文首发于公众号【看点代码再上班】