2

In Java, given

Class c = ...

We can make an object of this class by first obtaining a constructor. For example, if we want to use the default (no parameters) constructor,

c.getConstructor().newInstance()

This seems straightforward, and seems to match how things are done in Java source code.

But, curiously, it is not how things are done in JVM byte code. There, creating an object is done in two steps: new to actually create the object, then invokespecial to call an appropriate constructor.

Is there a way to bypass the constructor when what you have is a Class (with the actual class to be determined at runtime)? If not, was the rationale for the difference between how this works, and how the byte code works, ever documented?

rwallace
  • 31,405
  • 40
  • 123
  • 242

1 Answers1

2

You wanna allocate an uninitialized object.

You can try the library named Objenesis.

Otherwise, you can create an object by serialization. This is a widely used method to create a uninitialized object.

public class Serialization {

    static class TestSerialization  implements Serializable {
        int val = 0;
        public TestSerialization() {
            System.out.println("constructor");
            val = 1;
        }

        @Override
        public String toString() {
            return "val is " + val;
        }
    }


    public static void main(String[] args) throws IOException, ClassNotFoundException {
        TestSerialization testSerialization = new TestSerialization();

        // constructor
        // val is 1
        System.out.println(testSerialization);

        ByteArrayOutputStream bos = new ByteArrayOutputStream();

        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(testSerialization);
        oos.close();

        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
        Object obj = ois.readObject();
        // val is 1
        System.out.println(obj);
    }
}

One step closer, you can use ReflectionFactory to create an empty uninitialized object.

public class Main {

    static class TestClass {
        public int val = 0;

        public TestClass() {
            val = 1;
        }

        @Override
        public String toString() {
            return "value is " + val;
        }
    }

    public static void main(String[] args) throws Exception {

        // by constructor
        TestClass obj = new TestClass();
        // value is 1
        System.out.println(obj);

        // by reflect
        Constructor<TestClass> constructor = TestClass.class.getConstructor();
        obj = constructor.newInstance();
        // value is 1
        System.out.println(obj);

        // by ReflectionFactory
        ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
        Constructor<Object> objectConstructor = Object.class.getDeclaredConstructor();
        Constructor<?> targetConstructor = reflectionFactory.newConstructorForSerialization(TestClass.class, objectConstructor);
        obj = (TestClass) targetConstructor.newInstance();
        // value is 0
        System.out.println(obj);
    }
}