JAVA - 類反射

什麼是類反射?

來自百度百科的解釋:
 
JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。
 
JAVA反射機制提供了一下功能:
  • 在運行時判斷任意一個對象所屬的類;
  • 在運行時構造任意一個類的對象;
  • 在運行時判斷任意一個類所具有的成員變量和方法;
  • 在運行時調用任意一個對象的方法。
 

Class類

正常情況下,需要先有一個類的完整路徑引入之後纔可以按照固定的格式產生實例化對象,但在JAVA中允許通過一個實例化對象找到一個類的完整信息,那麼這就是Class類的功能。在JAVA中所有類的對象實際上都是Class類的實例。

實例化Class類對象的三種方式

package HelloClass;

class Hello {
}

public class GetClassDemo {
	public static void main(String[] args) throws ClassNotFoundException {
		Class <?> c1 = null;
		Class <?> c2 = null;
		Class <?> c3 = null;
		
		//1.
		c1 = Class.forName("HelloClass.Hello");
		//2.
		c2 = new Hello().getClass();
		//3.
		c3 = Hello.class;
		
		System.out.println("類名稱: " + c1.getName());
		System.out.println("類名稱: " + c2.getName());
		System.out.println("類名稱: " + c3.getName());
	}
}


以上方法都可以實例化Class對象,除forName()方法外,其他兩種:“對象.getClass()”,"類.class"都需要導入一個明確的類,如果一個類操作不明確時,可能會受到一些限制。但是,forName()只需要以字符串的方式傳入即可,具有較大的靈活性。

通過Class調用無參構造實例化對象

package HelloClass;

class Person {
	private String name;
	private int 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 toString() {
		return "姓名: " + this.name + " 年齡: " + this.age;
	}	
}

public class GetClassDemo {
	public static void main(String[] args) throws Exception {
		Person person = null;
		Class<?> c = Class.forName("HelloClass.Person");
		
		person = (Person) c.newInstance(); //實例化Person對象,替代了原來的new操作 
		
		person.setName("jianwei.wang");
		person.setAge(18);
		System.out.println(person);
	}
}

以上程序通過Class.forName()方法實例化Class對象之後,直接調用newInstance()方法就可以實例化字符串傳入的對象,完全取代了之前使用new關鍵字的操作,但要記住一點被實例化對象的類中必須存在無參構造方法,如果不存在是無法實例化的。

以下代碼演示:在Person類中添加有參構造方法,則實例化的時候會發生錯誤:

package HelloClass;

class Person {
	private String name;
	private int age;
	
	public Person(String name, int age) {
		this.setName(name);
		this.setAge(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 toString() {
		return "姓名: " + this.name + " 年齡: " + this.age;
	}	
}

public class GetClassDemo {
	public static void main(String[] args) throws Exception {
		Person person = null;
		Class<?> c = Class.forName("HelloClass.Person");
		
		person = (Person) c.newInstance(); //實例化Person對象,替代了原來的new操作 
		
		person.setName("jianwei.wang");
		person.setAge(18);
		System.out.println(person);
	}
}


 

Exception in thread "main" java.lang.InstantiationException: HelloClass.Person
	at java.lang.Class.newInstance0(Unknown Source)
	at java.lang.Class.newInstance(Unknown Source)
	at HelloClass.GetClassDemo.main(GetClassDemo.java:38)

通過Class調用無參構造實例化對象

需要明確地調用類中的構造方法,並將參數傳遞進去之後纔可以進行實例化操作。具體步驟如下:

  1. 通過Class類中的getConstructors()取得本類中的全部構造方法;
  2. 想構造方法中傳遞一個對象數據進去,裏面包含了構造方法中所需要的各個參數;
  3. 之後通過Constructor實例化對象。
public class GetClassDemo {
	public static void main(String[] args) throws Exception {
		Person person = null;
		Class<?> c = Class.forName("HelloClass.Person");
		
		Constructor<?> cons[] = c.getConstructors();
		person = (Person) cons[0].newInstance("jianwei.wang", 18);
		System.out.println(person);
	}
}


獲取類的結構

可以通過反射得到一個類的完整結構,要適用到java.lang.reflect包中的幾個類:

  1. Constructor:表示類中的構造方法;
  2. Field:表示類中的屬性;
  3. Method:表示類中的方法。
package HelloClass;

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

interface China {
	public static final String NATIONAL = "China";
	public static final String AUTHOR = "ABC";
	public void sayChina();
	public String sayHello(String name, int age);
}

class Person implements China {
	private String name;
	private int age;
	
	public Person() {
	}
	
	public Person(String name, int age) {
		this.setName(name);
		this.setAge(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 toString() {
		return "姓名: " + this.name + " 年齡: " + this.age;
	}

	public void sayChina() {
		System.out.println("作者: " + AUTHOR + ", 國籍 " + NATIONAL);
	}

	public String sayHello(String name, int age) {
		return name + ", 你好! 我今年" + age + "歲了。。。";
	}	
}

public class GetClassDemo {
	public static void main(String[] args) throws Exception {
		Person person = null;
		Class<?> c = Class.forName("HelloClass.Person");
		
		System.out.println("=====取得全部接口=====");
		Class<?> interfeca[] = c.getInterfaces();
		for(int i = 0; i < interfeca.length; i++) {
			System.out.println(interfeca[i].getName());
		}
		
		System.out.println("=====取得父類=======");
		Class<?> superClass = c.getSuperclass();
			System.out.println(superClass.getName());
		
		System.out.println("=====取得構造方法=====");
		Constructor<?>[] constructs = c.getConstructors();
		for(int i = 0; i < constructs.length; i++) {
			System.out.println(constructs[i]);
		}
		
		System.out.println("=====取得全部方法=====");
		 Method method[]=c.getMethods(); 
	        for(int i=0;i<method.length;++i){ 
	            Class<?> returnType=method[i].getReturnType(); 
	            Class<?> para[]=method[i].getParameterTypes(); 
	            int temp=method[i].getModifiers(); 
	            System.out.print(Modifier.toString(temp)+" "); 
	            System.out.print(returnType.getName()+"  "); 
	            System.out.print(method[i].getName()+" "); 
	            System.out.print("("); 
	            for(int j=0;j<para.length;++j){ 
	                System.out.print(para[j].getName()+" "+"arg"+j); 
	                if(j<para.length-1){ 
	                    System.out.print(","); 
	                } 
	            } 
	            Class<?> exce[]=method[i].getExceptionTypes(); 
	            if(exce.length>0){ 
	                System.out.print(") throws "); 
	                for(int k=0;k<exce.length;++k){ 
	                    System.out.print(exce[k].getName()+" "); 
	                    if(k<exce.length-1){ 
	                        System.out.print(","); 
	                    } 
	                } 
	            }else{ 
	                System.out.print(")"); 
	            } 
	            System.out.println(); 
	        }
	        
	    System.out.println("=====取得本類全部屬性=====");
	    Field[] field = c.getDeclaredFields();  //、。。。。
        for (int i = 0; i < field.length; i++) { 
            // 權限修飾符 
            int mo = field[i].getModifiers(); 
            String priv = Modifier.toString(mo); 
            // 屬性類型 
            Class<?> type = field[i].getType(); 
            System.out.println(priv + " " + type.getName() + " "
                    + field[i].getName() + ";"); 
        }
        
        System.out.println("=====實現的接口或者父類的屬性====="); 
        // 取得實現的接口或者父類的屬性 
        Field[] filed1 = c.getFields(); 
        for (int j = 0; j < filed1.length; j++) { 
            // 權限修飾符 
            int mo = filed1[j].getModifiers(); 
            String priv = Modifier.toString(mo); 
            // 屬性類型 
            Class<?> type = filed1[j].getType(); 
            System.out.println(priv + " " + type.getName() + " "
                    + filed1[j].getName() + ";"); 
        } 
	}
}

運行結果:

=====取得全部接口=====
HelloClass.China
=====取得父類=======
java.lang.Object
=====取得構造方法=====
public HelloClass.Person()
public HelloClass.Person(java.lang.String,int)
=====取得全部方法=====
public void  setAge (int arg0)
public int  getAge ()
public void  sayChina ()
public java.lang.String  sayHello (java.lang.String arg0,int arg1)
public java.lang.String  toString ()
public java.lang.String  getName ()
public void  setName (java.lang.String arg0)
public final native java.lang.Class  getClass ()
public native int  hashCode ()
public boolean  equals (java.lang.Object arg0)
public final native void  notify ()
public final native void  notifyAll ()
public final native void  wait (long arg0) throws java.lang.InterruptedException 
public final void  wait (long arg0,int arg1) throws java.lang.InterruptedException 
public final void  wait () throws java.lang.InterruptedException 
=====取得本類全部屬性=====
private java.lang.String name;
private int age;
=====實現的接口或者父類的屬性=====
public static final java.lang.String NATIONAL;
public static final java.lang.String AUTHOR;

通過反射調用類中的方法

使用反射調用類中的方法可以通過Method類完成,操作步驟如下

  1. 通過Class類的getMethod(String name, Class...parameterTypes)方法取得一個Method的對象,並設置次方法操作時所需要的參數類型;
  2. 使用invoke()進行調用,並向方法中傳遞要設置的參數類型。
public class GetClassDemo {
	public static void main(String[] args) throws Exception {
		Person person = null;
		Class<?> c = Class.forName("HelloClass.Person");
		
		Method met = c.getMethod("sayChina"); //調用無參方法
		met.invoke(c.newInstance());
		
		Method met2 = c.getMethod("sayHello", String.class, int.class);
		String rv = (String) met2.invoke(c.newInstance(), "Jianwei", 18);
		System.out.println(rv);
	}
}
作者: ABC, 國籍 China
Jianwei, 你好! 我今年18歲了。。。


BR~

Jianwei Wang


 


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