search
這種Java反射機制,87%的程序員不知道?

這種Java反射機制,87%的程序員不知道?

Class對象

虛擬機在class文件的載入階段,把類信息保存在方法區數據結構中,並在Java堆中生成一個Class對象,作為類信息的入口。

聲明兩個類,Cat.java 和 Dog.java

class Cat {

private String name;

private int age;

static {

System.out.println("Cat is load");

}

}

class Dog {

private String name;

private int age;

static {

System.out.println("Dog is load");

}

}

獲取Class對象一般有三種方式:

通過實例變數方式

public class test {

public static void main(String args) {

Dog dog = new Dog;

Class clazz = dog.getClass;

}

}

public class test {

public static void main(String args) {

Dog dog = new Dog;

Class clazz = dog.getClass;

}

}

通過類名方式

public class test {

public static void main(String args) {

Class clazz = Dog.class;

}

}

public class test {

public static void main(String args) {

Class clazz = Dog.class;

}

}

通過這種方式時,只會載入Dog類,並不會觸發其類構造器的初始化。

通過Class.forName(String classname)方式

public class ClassTest {

public static void main(String args) {

try {

Class clazz = Class.forName("zzzzzz.Dog");

} catch (ClassNotFoundException e) {}

}

}

public class ClassTest {

public static void main(String args) {

try {

Class clazz = Class.forName("zzzzzz.Dog");

} catch (ClassNotFoundException e) {}

}

}

在JDK源碼實現中,forName方法會調用Native方法forName0,它在JVM中調用findClassFromClassLoader載入Dog類,其原理和ClassLoader一樣,將會觸發Dog類的類構造器初始化,forName0方法聲明如下:

private static native Class<?> forName0(String name, boolean initialize, ClassLoader loader, Class> caller)

1

private static native Class<?> forName0(String name, boolean initialize, ClassLoader loader, Class> caller)

其中initialize參數,用來告訴虛擬機是否需要對載入的類進行初始化,如果initialize為false,則不會進行初始化Dog類。

Class clazz = Class.forName("zzzzzz.Dog", false, Dog.class.getClassLoader);

1

Class clazz = Class.forName("zzzzzz.Dog", false, Dog.class.getClassLoader);

反射機制

反射機制reflect可以在運行期間獲取類的欄位、方法、父類和介面等信息。

1、獲取類欄位

Class class_dog = Dog.class;

Field fields = class_dog.getDeclaredFields;

for (Field field : fields) {

System.out.println(field.getName);

}

1 Class class_dog = Dog.class;

2 Field fields = class_dog.getDeclaredFields;

3 for (Field field : fields) {

4 System.out.println(field.getName);

5 }

2、獲取類方法

Class class_dog = Dog.class;

Method methods = class_dog.getDeclaredMethods;

for (Method method : methods) {

System.out.println(method);

}

Class class_dog = Dog.class;

Method methods = class_dog.getDeclaredMethods;

for (Method method : methods) {

System.out.println(method);

}

通過method.invoke(obj, ...args)可以調用obj實例的method方法。

3、獲取對應的實例構造器,並生成類實例

public class ClassTest {

public static void main(String args) throws NoSuchMethodException {

Class class_dog = Dog.class;

Constructor constructor = class_dog.getConstructor(String.class, int.class);

constructor.newInstance("Tom", 10);

}

}

class Dog {

private String name;

private int age;

public Dog(String name, int age) {

this.name = name;

this.age = age;

}

}

public class ClassTest {

public static void main(String args) throws NoSuchMethodException {

Class class_dog = Dog.class;

Constructor constructor = class_dog.getConstructor(String.class, int.class);

constructor.newInstance("Tom", 10);

}

}

class Dog {

private String name;

private int age;

public Dog(String name, int age) {

this.name = name;

this.age = age;

}

}

如果沒有顯示的聲明默認構造器,class_dog.getConstructor會拋出NoSuchMethodException異常。

4、通過newInstance方法生成類實例

Class class_dog = Dog.class;

Dog dog = class_dog.newInstance;

Class class_dog = Dog.class;

Dog dog = class_dog.newInstance;

5、設置私有變數

Class class_dog = Dog.class;

Field name = class_dog.getDeclaredField("name");

name.setAccessible(true);

Dog dog = (Dog) class_dog.newInstance;

name.set(dog, "Tom");

Class class_dog = Dog.class;

Field name = class_dog.getDeclaredField("name");

name.setAccessible(true);

Dog dog = (Dog) class_dog.newInstance;

name.set(dog, "Tom");

6、獲取私有變數

Field f = Unsafe.class.getDeclaredField("theUnsafe");

f.setAccessible(true);

return (Unsafe)f.get(null);

Field f = Unsafe.class.getDeclaredField("theUnsafe");

f.setAccessible(true);

return (Unsafe)f.get(null);

這種方式在使用Unsafe類進行黑魔法時經常用到。

反射的性能問題

Stackoverflow上,很多人覺得使用反射reflect會影響系統性能,主要有以下幾點看法:

1、代碼的驗證防禦邏輯過於複雜,本來這塊驗證時在鏈接階段實現的,使用反射reflect時需要在運行時進行;

2、產生過多的臨時對象,影響GC的消耗;

3、由於缺少上下文,導致不能進行更多的優化,如JIT;

不過現代JVM已經運行的足夠快,我們應該把主要重心放在複雜的代碼邏輯上,而不是一開始就進行各種性能優化。

小編團隊開發群,你想要的都在這裡哦!學習,交流,源碼,開發工具 616 959 444
應有盡有!小編先在這裡代表團隊謝過各位,歡迎學習Java各個階段的小夥伴們加入我們!


熱門推薦

本文由 一點資訊 提供 原文連結

一點資訊
寫了5860316篇文章,獲得23293次喜歡
留言回覆
回覆
精彩推薦