Java反射的應用

一:Class類的使用

    在面向對象的世界裏,世間萬物皆對象。類也是對象,類是java.lang.Class類的實例對象

    任何一個類都是Class類的實例對象,這個對象稱爲該類的類類型。這個實例對象有三種表達方式

public class Demo1 {

	public static void main(String[] args) {
      //Reflect的對象
	  Reflect re=new Reflect();
	  
	  //1.第一種表達方式,實際也在告訴我們任何一個類都有一個隱含的靜態成員class
	  Class c1=Reflect.class;
	  
	  //2.第二種方式,已經知道該類的對象通過getClass方式
	  Class c2=re.getClass();
	  
	  //官網說c1,c2表示了Reflect的類類型(Class Type),即萬事萬物皆對象
	  
	  //一個類只可能是Class類的一個實例對象
	  System.out.println(c1==c2); //true
	  
	  //3.第三種方式
	  try {
		Class c3=Class.forName("com.swpu.relect.Reflect");
	} catch (ClassNotFoundException e) {
		e.printStackTrace();
	}
	}
}
 class Reflect{}

二:動態加載類

    Class.forName("類的全稱")不僅表示了類的類類型,還表示了動態加載類。

        編譯時刻加載類是靜態加載類,new創建對象是靜態加載類,在編譯時刻就需要加載所有可能使用到的類,通過動態加載類可以解決該問題。

        運行時刻加載類是動態加載類。

三:java獲取方法信息

     基本類型都有類類型

public class Demo2 {
	public static void main(String[] args) {
		Class c1= int.class;
		Class c2=String.class;
		Class c3=void.class;
		
		System.out.println(c1.getName()); //return int
		System.out.println(c2.getName());  //java.lang.String
		System.out.println(c3.getName());  //void
	}
}

    編寫了一個API接口來獲取類的信息 

public class ClassUtil {
	/**
	 * 打印類的信息,包括類的成員函數,成員變量
	 * @param object
	 */	
	public static void  PrintClassMessage(Object object){
		//要獲取類的信息,首先獲取類的類類型
		Class c=object.getClass();
		//獲取類的名稱
		System.out.println("類的名稱爲:"+c.getName());
		/*
		 * 獲取方法.
		 * getMethods()方法獲取的是所有public的函數,包括從父類繼承而來的
		 * getDeclaredMethods:獲取的是所有自己定義的方法,不問訪問權限,不包括父類繼承過來的
		 */
		Method [] ms=c.getMethods();
		for(Method m:ms){
			//得到方法的返回值類型的類型
			Class returnType=m.getReturnType();
			System.out.print(returnType+" ");
			//獲取到方法名
			System.out.print(m.getName()+"(");
			//獲取參數類型-->得到的是參數 列表類型的類類型
			Class [] ParamTypes=m.getParameterTypes();
			for(Class param:ParamTypes){
				System.out.print(param.getName()+",");
			}
			System.out.println(")");
		}
	}
}

四:java獲取成員變量的信息

		/**
		 * 成員變量也是對象,是java.lang.reflect.Field的對象
		 * 
		 */
		Field[] fs=c.getDeclaredFields();
		for(Field f:fs){
			//得到成員變量的類類型
			Class fieldType=f.getType();
			String typeName=fieldType.getName();
			//得到成員變量的名稱
			String fieldName=f.getName();
			System.out.println(typeName+"("+fieldName+")");
			//
		}

 五:java獲取構造方法的信息

	public static void printConMessage(Object obj){
		Class c=obj.getClass();
		/**
		 * 構造函數也是對象
		 * java.lang.Constructor中封裝了構造函數的信息
		 * getConstructors獲取所有的public的構造函數
		 * getDeclaredConstructors得到所有的構造函數的信息
		 */
		Constructor[] cs=c.getDeclaredConstructors();
		for(Constructor con:cs){
			System.out.print(con.getName()+"(");
			//獲取構造函數的參數列表-->得到的是參數列表的類類型
			Class[] returnType=con.getParameterTypes();
			for(Class class1:returnType){
				System.out.print(class1.getName()+",");
			}
			System.out.println(")");
		}	
	}

六:方法反射對象的基本操作

    1):如何獲取一個方法:方法的名稱和方法的參數列表唯一確定一個方法

    2):方法反射的操作:method.invoke(對象,參數列表)      

public class MethodInvoke {

	public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		//要獲取print(int,int)方法
		A a1=new A();
		Class c=a1.getClass();
	    /*
	     *2.獲取方法 名稱 參數列表
	     */
		try {
			Method m=c.getMethod("print", new Class[] {int.class,int.class});
			//方法的反射操作:用m對象來進行操作,和a1.print(0的效果一樣
			//方法如果沒有返回值返回null,有返回值就返回具體的值
			Object o=m.invoke(a1,10,20);
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		}
		
		try {
			Method ms=c.getMethod("print", String.class,String.class);
			Object o1=ms.invoke(a1, "Hello","World");
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
class A {
	public void print(int a,int b){
		System.out.println(a+b);
	}
	public void print(String a,String b){
		System.out.println(a.toUpperCase()+","+b.toUpperCase());
	}
}

七:通過Class,Method瞭解集合泛型的本質

public class Demo6 {

	public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		ArrayList list=new ArrayList();
		ArrayList<Integer >list1=new ArrayList<Integer>();
		list1.add(1);
		//list1.add("string");是錯誤的
		
		Class c1=list.getClass();
		Class c2=list1.getClass();
		System.out.println(c1==c2); //return true;說明編譯之後集合的泛型是去泛型化的
		//反射的操作都是編譯之後的操作	
		
		/*
		 * java中集合的泛型,是防止錯誤消息的輸入,只在編譯階段有效果,繞過編譯就無效了
		 * 我們可以通過方法的反射來驗證:
		 */
		try {
			Method m=c1.getMethod("add",Object.class);
			Object o=m.invoke(list1, "fanxing");//繞過編譯操作就繞過了泛型
			System.out.println(list1.size());
			System.out.println(list1);
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		}
	}

}

最後進行一下總結:

    我們要用到反射,首先要獲取類,獲取類有三種方法:

        1):通過類.class來獲取

        2):通過類實例化之後的對象.getclass()方法來獲取

        3):通過class.forName("類名")來獲取,這也是動態加載,在這裏還要分清楚動態加載和靜態加載的區別

     我們獲取到類之後就可以通過方法來獲取類中的成員變量(getField),方法(getMethod),方法中的參數列表類型(getParamType),構造函數(getConstructor),進而獲得他們的類類型和名稱。

    當有了這些基礎之後我們就可以來進行方法的反射操作,還可以驗證泛型的本質。

   

    

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