Recently see Kryo source found that using a Java library called Objenesis, mainly used to create objects, it can not call the constructor to create the object. Since not all Java classes have parameterless constructors, and the constructors of some classes are private, some of them are third parties, and we can't modify the source code, so this library is still very useful. Http://objenesis.org/details.html
Objenisis contains a lot of platform and JVM implementations, where we only care about the implementation of Instantiator in the Sun's JVM. There are about three implementations: Sunreflectionfactoryinstantiator: Using Sun.reflect.ReflectionFactory to create objects Sunreflectionfactoryserializationinstantiator: You also use Sun.reflect.ReflectionFactory to create objects, but to be compatible with serialization, you need to find the first one that does not implement the serializable interface. Parent class, performance has a certain loss. Unsafefactoryinstantiator: Using Sun.misc.Unsafe.allocateInstance to create objects
There is another kind of magicinstantiator that doesn't seem to work. Sunreflectionfactoryinstantiator
Let's take a look at the implementation of Sunreflectionfactoryinstantiator, the code is very short.
public sunreflectionfactoryinstantiator (class<t> type) {//Get object CONSTRUCTOR&L
t;object> javalangobjectconstructor = Getjavalangobjectconstructor (); This function is the key, primarily for this class to create a new constractor Mungedconstructor =
Sunreflectionfactoryhelper.newconstructorforserialization (type, javalangobjectconstructor);
Mungedconstructor.setaccessible (TRUE);
//Create object, everyone read understand public T newinstance () {try {return mungedconstructor.newinstance ((object[)) null);
catch (Exception e) {throw new Objenesisexception (e); }///Get Object private static Constructor<object> Getjavalangobjectconstructor () {try {ret
Urn Object.class.getConstructor ((class[]) null);
catch (Nosuchmethodexception e) {throw new Objenesisexception (e); }
}
From the above code can see the Sunreflectionfactoryhelper.newconstructorforserialization function is the key, let's take a look at this source:
public static <T> constructor<t> newconstructorforserialization (class<t> type, CONSTRUCTOR<?&G T constructor) {//The following two lines here is mainly to get Sun.reflect.ReflectionFactory object class<?> reflectionfactoryclass = Getrefle
Ctionfactoryclass ();
Object reflectionfactory = createreflectionfactory (Reflectionfactoryclass); Method object for obtaining newconstructorforserialization methods Newconstructorforserializationmethod =
Getnewconstructorforserializationmethod (Reflectionfactoryclass); Using reflection to invoke the Newconstructorforserialization method to get a new constructor object try {return (constructor<t>) newconstructo
Rforserializationmethod.invoke (Reflectionfactory, type, constructor);
catch (IllegalArgumentException e) {throw new Objenesisexception (e);
catch (Illegalaccessexception e) {throw new Objenesisexception (e); catch (InvocationTargetException e) {throw new Objenesisexception (e); }
}
The notes are written very clearly, The key is in the Newconstructorforserialization method of sun.reflect.ReflectionFactory, in fact this method returns a parameterless constructor object, but never conflicts with the original constructor , which is called the Munged constructor. Sunreflectionfactoryserializationinstantiator
Let's take a look at the implementation
public class Sunreflectionfactoryserializationinstantiator<t> implements objectinstantiator<t> {private
Final constructor<t> Mungedconstructor;
Public Sunreflectionfactoryserializationinstantiator (class<t> type) {//Gets the class object of the first class in the parent class that does not implement the Serializable interface class<?
Super t> Nonserializableancestor = serializationinstantiatorhelper. Getnonserializablesuperclass (type); Get the parameterless constructor constructor<?
Super T> Nonserializableancestorconstructor;
try {nonserializableancestorconstructor = Nonserializableancestor. GetConstructor ((class[)) null); catch (Nosuchmethodexception e) {throw new Objenesisexception (new Notserializableexception (type+) ha
s no suitable superclass constructor ")); //Get the Munged constructor object, which will call nonserializableancestorconstructor Mungedconstructor = Sunreflectionfactoryhelp Er.newconstructorforserialization (Type, nonseriAlizableancestorconstructor);
Mungedconstructor.setaccessible (TRUE);
Public T newinstance () {try {return mungedconstructor.newinstance ((object[)) null);
catch (Exception e) {throw new Objenesisexception (e); }
}
}
The code is simple, the only question is serializationinstantiatorhelper.getnonserializablesuperclass (type); Let's look at the implementation.
public static <T> class<? Super t> Getnonserializablesuperclass (class<t> type) {
class<? Super t> result = type;
while (the Serializable.class.isAssignableFrom (result)) {result
= Result.getsuperclass ();
if (result = = null) {
throw new Error ("Bad class Hierarchy:no non-serializable parents")
;
}
return result;
}
It's actually a loop to find the first class object that does not have a parent class that implements the Serializable interface. Unsafefactoryinstantiator
Implementation code:
private static Unsafe Unsafe;
Private final class<t> type;
Public Unsafefactoryinstantiator (class<t> type) {
//Initialize unsafe object, otherwise cannot be used.
if (unsafe = = null) {
Field F;
try {
f = Unsafe.class.getDeclaredField ("Theunsafe");
} catch (Nosuchfieldexception e) {
throw new Objenesisexception (e);
}
F.setaccessible (true);
try {
unsafe = (unsafe) f.get (null);
} catch (Illegalaccessexception e) {
throw new Objenesisexception (e) ;
}
}
This.type = type;
}
Creates an object using the Unsafe.allocateinstance method, and then casts it. Public
T newinstance () {
try {return
type.cast (unsafe.allocateinstance (type));
} catch ( Instantiationexception e) {
throw new objenesisexception (e);
}
}
The code is simple. Performance Test
Objenesis has benchmark, I ran on my Windows computer:
Environment: 12GB Memory Oracle JDK 64-bit 1.8 i5 Windows 8
Results
Createobject.createobjectwithconstructor (new) AVGT 20 6.122±1.672 ns/op Createo Bject.createobjectwithconstructor (newinstance) avgt 20 7.614±1.672 ns/op Createobject.createo Bjectwithmungedconstructor avgt 20 8.415±0.252 ns/op Createobject.createobjectwithmungedconst Ructorraw avgt 20 10.413±1.187 ns/op createobject.createobjectwithmungedconstructorrawandcast av
GT 20 10.644±0.186 ns/op Createobject.createobjectwithunsafe AVGT 20 29.813 ±1.885 ns/op Createobject.createobjectwithunsaferaw avgt 20 26.572±0.261 ns/o P createobject.createobjectwithunsaferawandcast avgt 20 27.153±1.336 ns/op createobject.creat Eobjectwithunsaferawexception avgt 20 27.390±1.090 ns/op
Mungedconstructor is the fastest, 2ns slower than the new, 1ns slower than the newinstance. Unsafe is very slow, it takes about 3.5 times times the Mungedconstructor, is 5 times Times New, and 4 times times the newinstance.