我想以编程方式创建一个子类。 我想我有几个选择 - Javassist,CGLib,BCEL或ASM。
用例是一个应用程序的内部是面向类的,扩展是基于类的。因此,我不能将单个类作为外部化脚本驱动的多个扩展的基础。
现在 - 我该怎么做?我找到了拦截方法调用,字段访问,初始化等的例子。但没有关于子类化的例子。
我想结束一个课程:
super(...)
)我知道这是可能的,因为各种动态语言集成,例如GroovyClassLoader
,可以做到这一点。
答案 0 :(得分:7)
我特别喜欢的一个图书馆可以在这里使用; Bytebuddy
直接从着陆页获取的示例:
Class<?> dynamicType = new ByteBuddy()
.subclass(Object.class)
.method(ElementMatchers.named("toString"))
.intercept(FixedValue.value("Hello World!"))
.make()
.load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
它非常灵活,绝对值得一试,如果你想保留你的头发,我个人发现大量使用javassist有时会变得非常丑陋和混乱,bytebuddy感觉像是一个很好的需要呼吸新鲜空气!
Rafael Winterhalter在StackOverflow上也处于活动状态,可以找到任何你不确定的东西。
编辑:我对尸检的道歉。当朋友将问题联系起来并忘记查看日期时,登陆这里。
答案 1 :(得分:6)
使用Javassist很容易:
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;
static Class<? extends DefinitionBasedMigrator> createClass( String fullName )
throws NotFoundException, CannotCompileException
{
ClassPool pool = ClassPool.getDefault();
// Create the class.
CtClass subClass = pool.makeClass( fullName );
final CtClass superClass = pool.get( DefinitionBasedMigrator.class.getName() );
subClass.setSuperclass( superClass );
subClass.setModifiers( Modifier.PUBLIC );
// Add a constructor which will call super( ... );
CtClass[] params = new CtClass[]{
pool.get( MigratorDefinition.class.getName() ),
pool.get( GlobalConfiguration.class.getName())
};
final CtConstructor ctor = CtNewConstructor.make( params, null, CtNewConstructor.PASS_PARAMS, null, null, subClass );
subClass.addConstructor( ctor );
return subClass.toClass();
}
Maven依赖:
<!-- https://mvnrepository.com/artifact/org.javassist/javassist -->
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.22.0-GA</version>
</dependency>
答案 2 :(得分:3)
Java代理可能能够满足您的需求 - 它们本质上允许您在对象之上动态分层功能,因为您可以拦截对该对象的任何方法调用,并自行处理它们或将方法调用分派给基础类。根据您的目的,您可以获得与动态创建子类相同的结果
Oracle在他们的网站上有一个decent introduction(该URL引用Java版本1.4.2,但我不认为这种行为在最新版本中有所改变)。这是一个more concise example,可以为代理代码提供良好的风格。
也可以使用直接字节码操作(由ASM framework支持)来做事情,但我想使用代理将是一种更简单的方法。