This is the 19th day of my participation in the Gwen Challenge in November. Check out the details: The last Gwen Challenge in 2021
preface
In Java, the most common way to create an instance of an object is to call the corresponding constructor with new. When the constructor is not public, but private, how can we create an instance of an object? Create a class whose constructor is private as follows:
@Setter
@Getter
public class Girlfriend {
private String name;
private intThe age;private Girlfriend(String name) {
this.name = name; }}Copy the code
Let me new one last time……
Reflection create instance
In addition to new, I have reflection. Through reflection, you can get the fields and methods of a class, and you can also get the constructor of a class to create an object. For private modified fields, methods, and class constructors, we must disable security checking to obtain them.
No security inspection is prohibited
Security checking is enabled by default, and methods, classes, and constructors that are private are denied access.Running results:
Prohibition of security inspection
Turn off the security check by setAccessible(true) and access the constructor of the private modifier.
Running results:This is it? This is it? Unsafe, a class that can manipulate memory directly and create objects without a constructor.
sun.mics.Unsafe
With the advent of the JVM, Java no longer has the trouble of C language memory management, but also lost the ability to manipulate memory like Pointers. Unsafe stepped in to fill the gap. But as the name suggests, operating directly on memory is considered unsafe and poses many security issues. Therefore, Unsafe cannot be instantiated by new, and its only constructor is also private. Let’s look at the fields and methods associated with the Unsafe instance in the source code.
The source code is as follows:
public final class Unsafe {
private static final Unsafe theUnsafe;
private Unsafe(a) {}@CallerSensitive
public static Unsafe getUnsafe(a) {
Class var0 = Reflection.getCallerClass();
// Check whether the loader calling the class is Bootstrap or null
if(! VM.isSystemDomainLoader(var0.getClassLoader())) {throw new SecurityException("Unsafe");
} else {
returntheUnsafe; }}}Copy the code
It’s not hard to see that getUnsafe() is a public method, but it checks to see if the loader that calls getUsafe() is a Bootstrap loader, but the default loader that defines the class is AppClassLoader, so it throws an exception directly.
Check the class loader code as follows:
// The bootstrap loader is responsible for loading rt.jar, not written in Java, so null
public static boolean isSystemDomainLoader(ClassLoader var0) {
return var0 == null;
}
Copy the code
Therefore, we can only create instances from the theUnsafe field and constructor by reflection.
The code is as follows:
public class Boy {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
Class<Unsafe> unsafeClass = Unsafe.class;
// The first way: get the Unsafe instance through the constructor
Constructor<Unsafe> declaredConstructor = unsafeClass.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Unsafe unsafe1 = declaredConstructor.newInstance();
// The second method: get the Unsafe instance from the field
Field theUnsafe = unsafeClass.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe2 = (Unsafe)theUnsafe.get(null); }}Copy the code
There are two ways to get to the Unsafe instance object, and now let’s look at how to build the instance.
AllocateInstance () : Build the instance
With unsafe instances, you can use this method to create instance objects directly without using a constructor.
// Parsing parsing parsing parsing; // parsing parsing parsing parsing parsing parsing
Girlfriend girlfriend1 = (Girlfriend) unsafe1.allocateInstance(Girlfriend.class);
Girlfriend girlfriend2 = (Girlfriend) unsafe2.allocateInstance(Girlfriend.class);
girlfriend1.setName("Small fang 1");
girlfriend2.setName("Small fang 2");
System.out.println(girlfriend1.getName());
System.out.println(girlfriend2.getName());
Copy the code
Running results:As you can see from the results, the unsafe object obtained in both ways can be used to create instance objects. So what else does Unsafe do? Unsafe now offers more than 100 methods, so here are a few to put to the test.
PutObject () : Modifies object member variables
Field nameField = Girlfriend.class.getDeclaredField("name");
System.out.println(girlfriend1.getName());
// Get the offset of the name member variable's memory address relative to the object's memory address
long l = unsafe1.objectFieldOffset(nameField);
// Modify the value of the member variable name
unsafe1.putObject(girlfriend1, l, "Little red");
System.out.println(girlfriend1.getName());
Copy the code
Running results:
CompareAndSwapInt () : Atom modifies the int property value
Those interested can learn about the CAS principle inside the lock
Field ageField = Girlfriend.class.getDeclaredField("age");
long l1 = unsafe1.objectFieldOffset(ageField);
girlfriend1.setAge(20);
System.out.println("Initial age:" + girlfriend1.getAge());
// cas operation, the third parameter must be the old value, that is, 20, otherwise the modification fails.
unsafe1.compareAndSwapInt(girlfriend1, l1, 20.18);
System.out.println("Modified age:" +girlfriend1.getAge());
// Get the int value from the offset
int i = unsafe1.getInt(girlfriend1, l1);
System.out.println("Offset gets int value:" + i);
Copy the code
Running results:
AllocateMemory () : Allocates memory
// Allocate an 8byte memory and return the entry address
long address = unsafe1.allocateMemory(8L);
// initialize 8 bytes from the entry address with 0000 0000 representing a byte
unsafe1.setMemory(address, 8L, (byte) 0);
/ / aLong to 0
long aLong1 = unsafe1.getLong(address);
// Change address to long (8byte)
unsafe1.putLong(address,100L);
/ / aLong2 for 100
long aLong2 = unsafe1.getLong(address);
Copy the code
Netty application scenarios
PlatformDependent0 allocates memory and retrievals variables over Unsafe, since the Netty framework defines its own memory allocation management system.
conclusion
Unsafe also wants to explore other approaches, too. Its core method is mainly around the memory address entry, address offset to launch, please use carefully in the development.