java 經過Unsafe不使用構造器直接建立對象

這裏有一個User沒有無參構造java

public class User {

    static {
        System.out.println("static {}");
    }

    {
        System.out.println("{}");
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    private String username;

    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

如下是建立User的三種方法api

1.直接new一個Useride

User user = new User("zhangsan","123456");

2.使用反射則是工具

Constructor<User> constructor = User.class.getConstructor(String.class, String.class);
User user = constructor.newInstance("zhangsan", "123456");

3.使用Unsafe測試

final Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
final Field theUnsafeField = unsafeClass.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
final Object unsafe = theUnsafeField.get(null);
final Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class);
User user = (User) allocateInstance.invoke(unsafe, User.class);

簡單將Unsafe封裝一個工具類this

public final class UnsafeHelper {

    private UnsafeHelper() {
    }

    private static final Object unsafe;

    private static final Method allocateInstance;

    static {

        final Class<?> unsafeClass;

        final Field theUnsafeField;

        try {
            unsafeClass = Class.forName("sun.misc.Unsafe");
        } catch (ClassNotFoundException e) {
            throw new UnsupportedOperationException("can't find sun.misc.Unsafe. " + e.getMessage(), e);
        }

        try {
            theUnsafeField = unsafeClass.getDeclaredField("theUnsafe");
        } catch (NoSuchFieldException e) {
            throw new UnsupportedOperationException("can't find the field theUnsafe in sun.misc.Unsafe." + e.getMessage(), e);
        }
        theUnsafeField.setAccessible(true);

        try {
            unsafe = theUnsafeField.get(null);
        } catch (IllegalAccessException e) {
            throw new UnsupportedOperationException("get Unsafe instance failed: " + e.getMessage(), e);
        }

        try {
            allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class);
        } catch (NoSuchMethodException e) {
            throw new UnsupportedOperationException("can't find the method allocateInstance in sun.misc.Unsafe : " + e.getMessage(),
                    e);
        }

    }

    public static <T> T newInstance(Class<?> clazz) {
        try {
            return (T) allocateInstance.invoke(unsafe, clazz);
        } catch (Exception e) {
            throw new UnsupportedOperationException("create instance for " + clazz + " failed. " + e.getMessage(), e);
        }
    }
}

測試用例:google

@Test(expected = InstantiationException.class)
    public void newInstanceByReflect1() throws IllegalAccessException,
            InstantiationException {
        try {
            User user = User.class.newInstance();
            Assert.assertNull(user.getUsername());
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }

    }


    @Test
    public void newInstanceByReflect2() throws NoSuchMethodException, IllegalAccessException,
            InvocationTargetException, InstantiationException {
        Constructor<User> constructor = User.class.getConstructor(String.class, String.class);
        User user = constructor.newInstance("zhangsan", "123456");
        System.out.println(user);
        Assert.assertEquals("zhangsan", user.getUsername());
    }


    @Test
    public void newInstanceByUnsafe() {
        User user = UnsafeHelper.newInstance(User.class);
        System.out.println(user);
        Assert.assertNull(user.getUsername());
    }

使用Gson提供的api來調用Unsafecode

pom中添加依賴xml

<dependency>
	<groupId>com.google.code.gson</groupId>
	<artifactId>gson</artifactId>
	<version>2.8.5</version>
</dependency>

InstanceHelperget

import com.google.gson.internal.ConstructorConstructor;
import com.google.gson.internal.ObjectConstructor;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;
import java.util.HashMap;

/**
 * 無需構造器直接根據class建立實例
 *
 * @author Val Song
 * @date 2018/10/17
 * @since 1.0.0
 */
public final class InstanceHelper {

    private InstanceHelper() {
    }

    private static ThreadLocal<ConstructorConstructor> CONSTRUCTOR_CONSTRUCTOR_HOLDER =
            ThreadLocal.withInitial(() -> new ConstructorConstructor(new HashMap<>(0)));

    /**
     * 不須要構造器建立實例,底層經過Unsafe實現
     *
     * @param type
     * @param <T>
     * @return
     */
    public static <T> T newInstance(Type type) {
        TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(type);
        ObjectConstructor<T> objectConstructor = CONSTRUCTOR_CONSTRUCTOR_HOLDER.get().get(typeToken);
        return objectConstructor.construct();
    }

}

InstanceHelper測試用例

@Test
public void newInstanceByGson() {
	User user = InstanceHelper.newInstance(User.class);
	System.out.println(user);
	Assert.assertNull(user.getUsername());
}
相關文章
相關標籤/搜索