JAVA反射機制(及反射調用的性能簡測)

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">我們知道大多數腳本語言都是動態語言,例如Perl、Python、ruby之類的。他們都有用一共同的特點數據類型可在程序運行時動態的改變其類型、結構和屬性。基本都是解釋型語言,而JAVA在程序運行前需要通過編譯器先進行源碼編譯(編譯成字節碼),然後有jvm加載運行。同樣java也引入動態加載的相關機制----反射機制。從而實現動態加載類對象,提高程序設計的靈活性。</span>

1.java的反射機制:

反射機制允許程序在運行狀態中知道類對象的所有方法和屬性。對於任意對象都可以調用其任意方法。

java反射機制相關的API在JDK的java.lang.reflect包中。

Member接口 該接口可以獲取有關類成員(域或者方法)後者構造函數的信息。
AccessibleObject類 該類是域(field)對象、方法(method)對象、構造函數(constructor)對象的基礎類。
它提供了將反射的對象標記爲在使用時取消默認 Java 語言訪問控制檢查的能力。
Array類 該類提供動態地生成和訪問JAVA數組的方法。
Constructor類 提供一個類的構造函數的信息以及訪問類的構造函數的接口。
Field類 提供一個類的域的信息以及訪問類的域的接口。
Method類 提供一個類的方法的信息以及訪問類的方法的接口。
Modifier類 提供了 static 方法和常量,對類和成員訪問修飾符進行解碼。
Proxy類

提供動態地生成代理類和類實例的靜態方法。


2.Class對象的獲取(Class類是一個特殊的類對象,它本身也是一個對象):

1>.通過類對象的.getClass()方法:

Class class1 = [對象].getClass();

2>.通過Class的靜態方法.forName()獲取:

Class class2 = Class.forName();

3>.通過類的.class屬性獲取:

Class class3 = Boolean.class;

3.獲取fields

Java的Class中提供幾個方法來獲取類中聲明的字段。方法如下:

public FieldgetField()、 public Field[] getFields()、 public Field getDeclaredField(String name)、public Field[] getDeclareds().

4.獲取Class的Method

同獲取聲明字段一樣Class同樣提供瞭如下方法:

public Method getMethod(String name, Class<?>, parameterTypes)、getMethods()、public Method getDeclaredMethod(String name, Class<?> ... parameterTypes)、public Method[] getDeclaredMethod().

5.獲取構造函數:

同樣使用 public Constructor getConstructor(Class<T>...parameterTypes ).等方法可以獲取到類的公共構造方法。方法詳情請API中自行查找。

6.程序實例:

1>.user Class Code:

public class User {
	public int age;
	private String fristName;
	private String lastName;
	
	public User(){}
	
	public User(int age, String fristName, String lastName) {
		this.age = age;
		this.fristName = fristName;
		this.lastName = lastName;
	}
	
	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getFristName() {
		return fristName;
	}

	public void setFristName(String fristName) {
		this.fristName = fristName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	

}
2> TestReflest Class Code:

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;


public class TestReflect {
	/**
	 * @param args
	 * @throws NoSuchFieldException 
	 */
	public static void main(String[] args) throws NoSuchFieldException {
		// TODO Auto-generated method stub
		User user = new User();
		//獲取類類型
		Class class1 = User.class;
		Class class2 = user.getClass();
		try {
			Class class3 = Class.forName("User");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//獲取field
		try {
			Field [] fields = class1.getFields();
			System.out.println(fields.length);
			Field ageField = class1.getField("age");
			System.out.println(ageField.toString());
		}  catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println();
		//獲取方法
		Method[] methods = class1.getMethods();
		for (Method m : methods)  
		{  
		    System.out.println(m);  
		}
		System.out.println();
		Constructor[] constructors = class1.getConstructors();
		for(Constructor c: constructors) {
			System.out.println(c);
		}
		System.out.println();
		//創建對象
			try {
				User user2 = (User) class1.newInstance();
				System.out.println(user2);
				System.out.println();
				Constructor constructor = class1.getConstructor();
				User user3 = (User) constructor.newInstance();
				System.out.println(user3);
			} catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NoSuchMethodException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (SecurityException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
			System.out.println();
			//調用方法
			try {
				Method setAge = class1.getMethod("setAge", int.class);
				setAge.invoke(user, 10);
				System.out.println(user.getAge());
			} catch (NoSuchMethodException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (SecurityException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	}

}

代碼寫的比較粗狂簡單,通過調用上述的一些方法完成了class、field、method、constructor等類信息。同時通過調用invoke() 和newInstance()等方法完成方法調用和類對象的創建。

反射調用的性能問題:

反射調用是程序在運行時態下,獲取對象的類信息,包括類屬性,方法。因爲java反射是要解析字節碼,對內存中的對象
對象進行解析操作,尤其是在包括動態類型的屬性時對於jvm來說無法實現編譯狀態下的代碼優化,從而在帶來性能低的問題。
準備了一個簡單實例:
 * Created by cike on 16/6/28.
 */
public class User {
    private String name;
    private int age;

    public User() {}

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String  playing() {
        StringBuffer stringBuffer = new StringBuffer();
        for (int i = 0; i < 1000; i++) {
            stringBuffer.append(i);
        }
        return stringBuffer.toString();
    }
}

測試main方法:
public static void main(String[] args) {
        Class userClass = User.class;
        try {
            Method method = userClass.getMethod("playing", null);
            User user = (User) userClass.newInstance();
            long start = System.currentTimeMillis();
            System.out.println(method.invoke(user,null));
            System.out.println("反射調用方法耗時:" + String.valueOf(System.currentTimeMillis() - start));

            User user1 = new User();
            long start1 = System.currentTimeMillis();
            System.out.println(user1.playing());
            System.out.println("常規調用方法耗時:" + String.valueOf(System.currentTimeMillis() - start1));
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
多次運行代碼測試結果如下:











發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章