Reputation: 978
Consider this code:
public interface IRegistryClass
{
public IRegistryClass get();
}
public abstract class Skill implements IRegistryClass
{
@Override
public Skill get()
{
return new SkillFake();
}
private final class SkillFake extends Skill
{}
}
Would it be possible to call skill#get() when being ONLY supplied with Skill.class?
Regular Java won't allow to class#newInstance() abstract classes. Question is: Is there a way?
Note: I can't have static keyword. I need inheritance on this one.
Edit: I've read about Unsafe - would it help in this case? I know that your everyday java is useless here. Need some extreme stuff.
Upvotes: 0
Views: 326
Reputation: 100189
You cannot do this even with Unsafe
, because Unsafe.allocateInstance
throws java.lang.InstantiationException
for abstract class as well. The only possible solution is to create an anonymous class like this:
new Skill() {}.get();
It's not exactly what you want as anonymous class is still new class which inherits the Skill
class. But this is satisfactory in many cases.
Update: if you really want some extreme stuff, you can spin the anonymous class in runtime. For example, this is how it can be done using ASM library:
// Generate subclass which extends existing Skill.class
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
String superClassName = Skill.class.getName().replace('.', '/');
cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER + Opcodes.ACC_FINAL
+ Opcodes.ACC_SYNTHETIC, "anonymous", null, superClassName, null);
// Create constructor which calls superclass constructor
MethodVisitor ctor = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
ctor.visitCode();
// load this
ctor.visitVarInsn(Opcodes.ALOAD, 0);
// call superclass constructor
ctor.visitMethodInsn(Opcodes.INVOKESPECIAL, superClassName, "<init>", "()V", false);
// return
ctor.visitInsn(Opcodes.RETURN);
ctor.visitMaxs(-1, -1);
ctor.visitEnd();
cw.visitEnd();
// Get the Unsafe object
Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
sun.misc.Unsafe UNSAFE = (sun.misc.Unsafe) field.get(null);
// Create new anonymous class
Class<? extends Skill> clazz = UNSAFE.defineAnonymousClass(Skill.class,
cw.toByteArray(), null).asSubclass(Skill.class);
// instantiate new class and call the `get()` method
clazz.newInstance().get();
This way you can subclass an abstract class in runtime (subclass does not exist in your compiled code). Of course it should be noted that such solution is, ahem, unsafe.
Upvotes: 1