反射

1)Class 類的使用java

(1)在面向對象的世界裏,萬事萬物皆對象。(靜態成員、普通數據類型)json

類是對象,類是java.lang.Class類的實例對象數組

(2)這個對象的表示方式有三種:函數

  • 第一種表示方式:

Class c1 = Foo.class;//任何一個類都有一個隱含的靜態成員變量class工具

  • 第二種表示方式:

Class c2 = foo1.getClass();//已知該類的對象,經過getClass方法獲得這個實例類的class(類類型)code

  • l 第三種表達方式

Class c3 = Class.forName("test.reflect.Foo");對象

(3)能夠經過類類型建立該類的類對象繼承

Class c1 = Foo.class;//c1就是類類型get

Foo foo=(Foo)c1.newInstance();虛擬機

 

2)區分動態加載和靜態加載

        new建立對象是靜態加載類,在編譯時進行加載,若是程序中其餘的類有問題,那麼沒有問題的類也是沒法執行的,解決這個問題可使用動態加載。

        Word w = new Word(); // 靜態加載

        Class c  = Class.forName(「類的絕對路徑」); // 動態加載

        c叫作類的類類型,也能夠經過類類型建立實例:c.newInstance();

        功能性的類最好使用動態加載,而不是靜態加載。動態加載類指的是程序運行時加載類,而靜態加載指的是編譯時加載類,編譯時加載的缺點是程序中全部的功能都不能有差錯,不然的話程序就不能用了,而動態加載類的好處就是咱們須要使用哪個類虛擬機就會動態加載根據咱們的須要動態的加載這個類,這樣程序的使用就不會受到其餘的影響。

 

3)反射獲取類信息的一些操做:

(1)Class類的基本API操做

  • c.getName()能夠獲取類的名稱
  • c.getSimpleName();//不包含包名的類的名稱
  • c.getConstructor()得到Constructor[]全部公有構造方法信息
  • c.getDeclaredConstructors()獲取本身聲明的構造方法
  • c.getFields()方法獲取的是全部的public的成員變量信息
  • c.getDeclaredFields獲取的是該類本身聲明的成員變量信息
  • c.getMethods()獲取類的【public方法】集合,【包括繼承來的】
  • c.getDeclaredMethods()獲取的是全部該類【本身聲明】的方法,【不問訪問權限】

(2)成員方法,Method類提供了一些API操做

  • getReturnType()獲得該方法的返回值類型的類類型(class),如int.class String.class
  • getName()獲得方法的名稱
  • getParameterTypes()得到參數列表類型的類類型

(3)成員變量,java.lang.reflect.Field類的一些API

  • Field類封裝了關於成員變量的操做
  • Field[] fs = c.getFields()方法獲取全部public的成員變量Field[]信息
  • Field[] fs = c.getDeclaredFields獲取的是該類本身聲明的成員變量信息
  • field.getType()得到成員類型的類類型
  • field.getName()得到成員的名稱

(4)構造函數,java.lang.Constructor類的對象

  • 經過Constructor[] cs = class.getConstructor()得到對象全部公有構造方法信息
  • 經過Constructor[] cs = getDeclaredConstructors()獲取本身聲明的構造方法
  • getName()獲得構造函數名稱
  • Class[] c = Constructor.getParameterTypes(): 獲得的是參數列表的類型的類類型

下面經過編寫一個打印類信息的工具類,經過反射獲取類的信息:

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

/**
 * 獲取類信息工具類
 * 
 * @author Smile
 */
public class ClassUtil {

	public static void main(String[] args) {
		int a = 0;
		printClassMethodObject(a);
	}

	/**
	 * 打印類的成員函數信息
	 * 
	 * @param obj 該對象所屬類的信息
	 */
	public static void printClassMethodObject(Object obj) {
		// 要獲取類的信息,首先要獲取類的類類型
		Class c = obj.getClass(); // 獲取對象所屬類的類類型
		// 獲取類的名稱
		System.out.println("類的名稱是:" + c.getName());

		/*
		 * 獲取類的成員方法 getMethods()方法獲取的是全部的public的函數,包括父類繼承而來的
		 * getDeclaredMethods()方法獲取的是全部該類本身聲明的方法,不問訪問權限
		 */
		Method[] ms = c.getMethods(); // Method[] ms1 = c.getDeclaredMethods();
		for (Method method : ms) {
			// 獲取方法的返回值類型(其實是返回值的類類型)
			Class returnType = method.getReturnType();
			System.err.print(returnType.getSimpleName() + " "); // 打印返回類型名稱
			// 獲得方法的名稱
			System.out.print(method.getName() + " ( ");
			// 獲取參數類型(其實是參數列表的類類型)
			Class[] paramTypes = method.getParameterTypes();
			for (Class paramTypeClass : paramTypes) {
				// 打印參數類型的名稱
				System.out.print(paramTypeClass.getSimpleName() + "  ");
			}
			System.out.println(")");
		}

	}

	/**
	 * 打印類的成員方法信息
	 * 
	 * @param obj
	 */
	public static void printClassFieldMessage(Object obj) {
		Class c = obj.getClass();
		/*
		 * 獲取成員變量 Field類封裝了關於成員變量的操做 getFields()方法獲取的是全部的public的成員變量信息
		 * getDeclaredFields()方法獲取的是該類本身聲明的成員變量的信息
		 */
		Field[] fs = c.getDeclaredFields();
		for (Field field : fs) {
			// 獲得成員變量的類型的類類型
			Class fieldType = field.getType();
			// 獲得成員變量類類型的名稱
			String typeName = fieldType.getName();
			// 獲得成員變量的名稱
			String fieldName = field.getName();
			System.out.println(typeName + " " + fieldName);
		}
	}

	/**
	 * 打印對象的構造函數的信息
	 */
	public static void printClassConMessage(Object obj) {
		Class c = obj.getClass();
		/*
		 * Constructor中封裝了構造函數的信息 getConstructors() 獲取全部的public的構造函數
		 * getDeclaredConstructors() 獲取全部的public的構造函數
		 */
		Constructor[] cs = c.getConstructors();
		for (Constructor constructor : cs) {
			System.out.println(constructor.getName() + " (");
			// 獲取構造函數的參數列表(參數列表的類類型)
			Class[] paramType = constructor.getParameterTypes();
			for (Class class1 : paramType) {
				System.out.print(class1.getName() + " ");
			}
			System.out.println(")");
		}
	}
}

4)方法的反射

獲取一個方法,有兩個步驟:

(1)首先要獲取類的類類型

(2)獲取方法名,由名稱和參數列表來決定惟一一個方法

Eg:

// 一、獲取類類型

Class c = a1.getClass();

// 二、獲取方法名,由名稱和參數列表來決定

Method m1 = c.getMethod("print", new Class[]{int.class, int.class});

下面經過代碼體會一下方法的反射:

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

/**
 * 方法的反射操做Demo
 */
public class MethodDemo {
	public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		// 要獲取方法,先要獲取類類型
		
		A a1 = new A();
		// 一、獲取類類型
		Class c = a1.getClass();
		// 二、獲取方法名,由名稱和參數列表來決定
		Method m1 = c.getMethod("print", new Class[]{int.class, int.class});
		Method m2 = c.getMethod("print", new Class[]{String.class, String.class});
		Method m3 = c.getDeclaredMethod("test", new Class[]{int.class});
		Method m4 = c.getMethod("bMethod"); // 若是用c.getDeclaredMethod("bMethod");就會報錯;由於getDeclaredMethod()獲取的是本身的方法
		
		// 方法的反射操做是指用Method對象來進行方法調用,若是方法沒有返回類型,則返回nul,有則返回具體的值
		Object o1 = m1.invoke(a1, new Object[]{1,2});
		Object o2 = m2.invoke(a1, new Object[]{"AAa", "BBb"});	
		Object o4 = m4.invoke(a1);
//		Object o3 = m3.invoke(a1, new Object[]{1}); // test()方法是私有函數,不能經過反射來獲取
	}
}

class A extends B{
	public void print(int a, int b) {
		System.out.println(a + b);
	}
	
	public void print(String a, String b){
		System.out.println(a.toLowerCase() + " " + b.toUpperCase());
	}
	
	private void test(int t){
		System.out.println("------ " + t + " -------");
	}
}

class B{
	public void bMethod(){
		System.out.println("------------- bMethod() ------------");
	}
}

注意如下幾點:

  • getMethod獲取的是public方法,getDelcaredMethod獲取本身聲明的方法(非私有、非父類方法)
  • 方法的反射操做是指用Method對象來進行方法調用,經過對調用方法a1.print(10,20)和 經過反射調用m.invoke(a1,new Object[]{10,20})有相同的調用效果
  • Object o=m.invoke(對象名,參數);//方法若是沒有返回值返回null,若是有返回值返回具體值,參數可用數組的方式表示,也能夠直接列舉,沒有參數就不寫
相關文章
相關標籤/搜索