Ernio
Ernio

Reputation: 978

Call non-abstract method of abstract class without its instance

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

Answers (1)

Tagir Valeev
Tagir Valeev

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

Related Questions