天天看點

JSE深入探究——反射初步

       Java程式中的各個Java類屬于同一類事物,描述這類事物的Java類名就是Class。

       反射就是把Java類中的各種成分映射成相應的java類。例如,一個Java類中用一個Class類的對象來表示,一個類中的組成部分:成員變量,方法,構造方法,包等等資訊也用一個個的Java類來表示,就像汽車是一個類,汽車中的發動機,變速箱等等也是一個個的類。表示java類的Class類顯然要提供一系列的方法,來獲得其中的變量,方法,構造方法,修飾符,包等資訊,這些資訊就是用相應類的執行個體對象來表示,它們是Field、Method、Contructor、Package等等。 

      一個類中的每個成員都可以用相應的反射API類的一個執行個體對象來表示,通過調用Class類的方法可以得到這些執行個體對象後,得到這些執行個體對象後有什麼用呢?怎麼用呢?這正是學習和應用反射的要點。

對比提問:

衆多的人用一個什麼類表示?衆多的Java類用一個什麼類表示?

人     Person

Java類Class

對比提問:

Person類代表人,它的執行個體對象就是張三,李四這樣一個個具體的人,Class類代表Java類,它的各個執行個體對象又分别對應什麼呢?

對應各個類在記憶體中的位元組碼,例如,Person類的位元組碼,ArrayList類的位元組碼,等等。

一個類被類加載器加載到記憶體中,占用一片存儲空間,這個空間裡面的内容就是類的位元組碼,不同的類的位元組碼是不同的,

是以它們在記憶體中的内容是不同的,這一個個的空間可分别用一個個的對象來表示,這些對象顯然具有相同的類型,這個類型是什麼呢?

如何得到各個位元組碼對應的執行個體對象( Class類型)

三種方式:

1.

類名.class,例如,System.class

2.

對象.getClass(),例如,new Date().getClass()

3.

Class.forName("類名"),例如,Class.forName("java.util.Date");

下面是執行個體用到的一個類:

public class Person 
{
	private int id;
	private String name;
	public Person(int i,String n)
	{
		id=i;
		name=n;
	}
	@Override
	public String toString() 
	{
		return name+"="+id;
	}
}
           

下面是示範執行個體與注釋:

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class ReflectDemo
{

	public static void main(String[] args) 
	throws Exception 
	{
		test4();
		test3();
		ReflectDemo.test2();
		ReflectDemo.test1();
	}
	//在String泛型修飾的集合内放入Integer對象
	public static void test4() throws Exception
	{
		List<String> list=new ArrayList<String>();
		list.add("strlist");
		System.out.println("==============="+list.size());
		Class<Object> cla=(Class<Object>) Class.forName("java.util.List");
		Method met=cla.getMethod("add", Object.class);
		met.invoke(list, new Integer(1));
		System.out.println("==============="+list.size());
		for (int i=0;i<list.size();i++)
		{
			System.out.println(String.valueOf(list.get(i)));
		}
		System.out.println("==============="+list.size());
	}
	//把對象的屬性值改變
	public static void test3() throws Exception
	{
		Person per=new Person(112,"aAAGGGasdJHdzdanacca");
		 System.out.println(per);	
		//擷取類的位元組碼對象
		Class cla=Class.forName("ljt.reflect.Person");
		//擷取此對象的所有字段
		Field[] fileds=cla.getDeclaredFields();
	    for (Field field : fileds) 
	    {
	    	field.setAccessible(true);
			//如果此字段是String類型的話
	    	if(field.getType()==String.class)
	    	{
	    		//擷取此字段的内容
	    		String oldField=(String)field.get(per);
	    		//将字段中的小寫字母全部轉換為大寫字母
	    		char[] oldChar=oldField.toCharArray();
	    		for (int i=0;i<oldChar.length;i++) 
	    		{
					if(oldChar[i]>96)
					{
						oldChar[i]=(char)(oldChar[i]-32);
					}
				}
	    		String newField=new String(oldChar);
	    		//将對象的相應字段值改變
	    		field.set(per, newField);
	    	}
		}
		  System.out.println(per);	
	}
	//反射的三種方式
	public static void test1() 
			throws ClassNotFoundException
	{
		/*
		 * 得到各個位元組碼對應的執行個體對象( Class類型)
			三種方式:
			1.
			類名.class,例如,System.class
			2.
			對象.getClass(),例如,new Date().getClass()
			3.
			Class.forName("類名"),例如,Class.forName("java.util.Date");*/
		//類名.class,例如,System.class
		Class<String> c1=String.class;
		//對象.getClass(),例如,new Date().getClass()
		Class<String> c2=(Class<String>)new String().getClass();
		//Class.forName("類名"),例如,Class.forName("java.util.Date")
		Class<String> c3=(Class<String>)Class.forName("java.lang.String");
		System.out.println((c1==c2)+"--"+(c1==c3));
	}
	//利用反射擷取構造器
	public static void test2() 
	throws 
	NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
	{
		/*
		 * Class 類的執行個體表示正在運作的 Java 應用程式中的類和接口。
		 * 方法:
		 *  Constructor<T>   getConstructor(Class<?>... parameterTypes) 
          		傳回一個 Constructor 對象,它反映此 Class 對象所表示的類的指定公共構造方法。 
 			Constructor<?>[] getConstructors() 
          		傳回一個包含某些 Constructor 對象的數組,這些對象反映此 Class 對象所表示的類的所有公共構造方法。 
			
		java.lang.reflect 類 Constructor<T>
		Constructor 提供關于類的單個構造方法的資訊以及對它的通路權限。
		方法:
		 T  newInstance(Object... initargs) 
          	使用此 Constructor 對象表示的構造方法來建立該構造方法的聲明類的新執行個體,并用指定的初始化參數初始化該執行個體。 
		 * */
		Class<String> c1=String.class;
		//擷取參數清單為一個String類型的對象的構造方法
		Constructor<String> const1=c1.getConstructor(String.class);
		//通過Constructor的newInstance方法擷取String的對象
		String str=const1.newInstance("ijava");
		System.out.println(str);
		//無參構造可以直接使用位元組碼對象建立該類的執行個體
		String str2=c1.newInstance();
		str2="ljt";
		System.out.println(str2);
		
	}
}
           

繼續閱讀