什么是合成类
合成类, 指的是不能通过源代码看到的类, 而是由编译器自动生成的类, 依据Spring的描述, 合成类指的是不是通过应用程序创建出来的
类, 其实这个合成类应该算是Java语言知识中的一部分
演示合成类
public class UserService {
public void test1 () {
new UserServiceInner();
}
public static class UserServiceInner {
public UserServiceInner () {
}
}
}
分析:
可以看到, 我们在UserService中有一个静态内部类UserSerivceInner, 我们显示的指定了其默认构造方法, 注意, 这里我们显示指定
成了pulic修饰, 然后我们在test1方法中创建了内部类的实例, 此时我们编译这个文件会发现, 在编译后的class文件夹下, 出现了
两个class文件, 分别是UserService$UserServiceInner.class以及UserService.class
public class UserService {
public void test1 () {
new UserServiceInner();
}
public static class UserServiceInner {
private UserServiceInner () {
}
}
}
分析:
此时我们将这个静态内部类的构造方法设置成了私有的访问权限, 但是我们可以看到在test1方法中还是能够对该类进行实例化的,
在Java中, 被private修饰的方法, 仅仅只能被当前类访问, 但是此时却出现了private修饰的方法被其他类访问了, 在Java中是通
过编译器额外生成一个构造方法来实现的, 并且这个额外的构造方法还必须有参数, 那么这个参数应该是什么呢?其实可以是一个额外
生成的类就好了, 换句话说, 编译器会做如下的事情
<1> 创建一个额外的类, 比如UserServiceInner$1, 即在UserService中创建一个额外的静态类, 此时代码会变成
public class UserService {
public void test1 () {
new UserServiceInner();
}
public static class UserServiceInner {
private UserServiceInner () {
}
}
public static class UserService$1 {}
}
<2> 在UserServiceInner中额外的增加一个构造方法, 该构造方法接收一个UserService$1类型的参数, 因为这个类是由编译器创建的,
所以放入一个该类的实例也是很简单的, 此时代码变成:
public class UserService {
public void test1 () {
new UserServiceInner();
}
public static class UserServiceInner {
private UserServiceInner () {
}
public UserServiceInner (UserService$1 obj) {
}
}
public static class UserService$1 {}
}
<3> 将test1方法中调用的构造方法改成编译器生成的构造方法, 并手动生成一个UserService$1类的实例, 此时代码变为
public class UserService {
public void test1 () {
new UserServiceInner( new UserService$1() );
}
public static class UserServiceInner {
private UserServiceInner () {
}
public UserServiceInner (UserService$1 obj) {
}
}
public static class UserService$1 {}
}
分析: 由上述过程, 就成功的创建了默认构造方法为private的UserServiceInner的类的实例, 实际上, Java中也确实是这样来实现的,
如果想要看到上面的效果, 可以试着编写一个测试用例来看看, 需要注意的是, 如果要看到这个$1结尾的类, 需要去编译生成的
class文件夹中才能看到, 更需要注意的是, 如果要看到实际的内部代码的情况, 需要通过javap -cv xxx来看到
总结
在上述的例子中, UserService$1这个类就是一个合成类, 它不能通过源代码来看到, 是由编译器生成的类, 不是通过应用程序生成的类,
之所以对合成类进行解释, 是因为在Spring中, 对于一个合成类, 是不会扫描进来的, 并且在AOP进行动态代理的时候, 对于合成类是不会
进行代理的, 因为这个是由编译器优化生成的类, 不是程序员希望出现的, 所以在Spring中很多操作都会在非合成类的情况下才能继续进
行下去, 并且在Java中也有代码来确定一个类是否为合成类, 即: Class对象的isSynthetic方法, 当我们调用一个合成类的该方法时会
返回true, 大家可以通过ClassLoader的loadClass方法手动加载合成类并判断来证明这个结论
文章永久链接:https://tech.souyunku.com/36527