1. 程式人生 > >通過反射機制建立一個構造方法中引數數量可變的物件

通過反射機制建立一個構造方法中引數數量可變的物件

自學的時候剛看到Class類與Java反射,才開始講解了Class類得到對應類構造方法的方法。

我們可以用getConstructors()等四個方法得到需要的Constructor構造方法或者其陣列,然後再利用Constructor的newInstance方法進行建立物件。

但是我嘗試了很多次,都無法直接取到構造方法引數數量可變的Constructor物件,只能直接得到引數數量固定的Constructor,而想要取到前者,則暫時以我自身的知識掌握需要採取其他的方式。

首先建立一個含有需要的構造方法的類A

public class A {
	//這是一個實驗類,含有無參構造方法和三個有參構造方法
	//其中兩個有參構造方法的引數數量可變
	public A(){
		System.out.println("無參構造方法");
	}
	public A(int i){
		System.out.println("有參構造方法,引數為一個int");
		System.out.println("該int值為:"+i);
	}
	public A(int...arr){
		System.out.println("有參構造方法,引數為一個int型別的陣列");
		if (arr.length==0){
			System.out.println("該陣列的容量為0");
		}else{
			System.out.print("該陣列的值分別為:"+arr[0]);
			for (int i=1;i<arr.length;i++){
				System.out.print("-"+arr[i]);
			}
			System.out.println();
		}
	}
	public A(String...arr){
		System.out.println("有參構造方法,引數為一個String型別的陣列");
		if (arr.length==0){
			System.out.println("該陣列的容量為0");
		}else{
			System.out.print("該陣列的值分別為:"+arr[0]);
			for (int i=1;i<arr.length;i++){
				System.out.print("-"+arr[i]);
			}
			System.out.println();
		}
	}
}
對應的我在TestA測試類裡寫了六個方法用於測試和學習

方法一是測試無參構造方法是否能成功建立物件。

public static void getNull(){
	System.out.println("---getNull---");
	Class class1=A.class;
	try{
		Constructor<A> constructor=class1.getConstructor(null);
		A a=constructor.newInstance(null);
	}catch(Exception e){
		System.out.println("錯誤型別為"+e.getClass().getName());
	}
}
輸出結果:
---getNull---
無參構造方法
方法二和三是測試getConstructor方法的引數必須是陣列還是單個,雖然引數形式是一個可變長度陣列的形式。[i=1]
public static void getInt1(int i){
	System.out.println("---getInt1---");
	Class class1=A.class;
	try{
		//錯誤方式:引數是int,則必須用int.calss;引數是Integer才能用Integer.class
		//Constructor<A> constructor=class1.getConstructor(Integer.class);
		Constructor<A> constructor=class1.getConstructor(int.class);
		A a=constructor.newInstance(i);
	}catch(Exception e){
		System.out.println("錯誤型別為"+e.getClass().getName());
	}
}
輸出結果:
---getInt1---
有參構造方法,引數為一個int
該int值為:1
public static void getInt2(int i){
	System.out.println("---getInt2---");
	Class class1=A.class;
	try{
		Class[] classs=new Class[]{int.class};
		Constructor<A> constructor=class1.getConstructor(classs);
		A a=constructor.newInstance(i);
	}catch(Exception e){
		System.out.println("錯誤型別為"+e.getClass().getName());
	}
}
輸出結果:
---getInt2---
有參構造方法,引數為一個int
該int值為:1
方法四是給getConstructor的引數為一個固定長度的Class陣列,由三個int.class組成。

[arr={1,2,3}]

public static void getInts1(int...arr){
	System.out.println("---getInts1---");
	Class class1=A.class;
	try{
		Class[] classs=new Class[]{int.class,int.class,int.class};
		Constructor<A> constructor=class1.getConstructor(classs);
		A a=constructor.newInstance(arr);
	}catch(Exception e){
		System.out.println("錯誤型別為"+e.getClass().getName());
	}
}
輸出結果:
---getInts1---
錯誤型別為java.lang.NoSuchMethodException
說明以固定長度的class陣列作為引數是得不到我們想要的Constructor物件的。

方法五嘗試性地用了一下可能能得到class不確定長度陣列的方式,並將其作為引數。[arr={1,2,3}]

public static void getInts2(int...arr){
	System.out.println("---getInts2---");
	Class class1=A.class;
	try{
		Constructor<A> constructor=class1.getConstructor(int.class.getClasses());
		A a=constructor.newInstance(arr);
		/*
		System.out.println(constructor);
		A a=constructor.newInstance(null);
		*/
	}catch(Exception e){
		System.out.println("錯誤型別為"+e.getClass().getName());
	}
}
輸出結果:
---getInts2---
錯誤型別為java.lang.IllegalArgumentException
輸出結果2:(將“A a=constructor.newInstance(arr);”註釋並且將原本註釋的釋放出來)
---getInts2---
public com.A()
無參構造方法
第一個輸出結果的錯誤型別是引數不匹配,也就是說得到的Constructor方法的引數不匹配arr,通過第二個輸出結果我們得到結論,這種方式得到的實際上是類的無參構造方法。

方法五是目前我可以想到的能得到一個引數數量可變的構造方法的方式,利用了Constructor類的isVarArgs()方法,該方法判定一個Constructor物件的引數列表是否是可變的,為了測試我又給A類加上了引數為String...arr的構造方法用於區分。

public static void getInts3(int...arr){
	System.out.println("---getInts3---");
	Class class1=A.class;
	try{
		Constructor<A>[] constructors=class1.getConstructors();
		for (int i=0;i<constructors.length;i++){
			System.out.println((i+1)+":"+constructors[i]);
			System.out.println("該方法的引數數量可變:"+constructors[i].isVarArgs());
			if (constructors[i].isVarArgs()){
				try{
					A a=constructors[i].newInstance(arr);
				}catch(Exception e2){
					System.out.println("該方法無法以int[]作為引數建立物件");
					System.out.println("錯誤型別為"+e2.getClass().getName());
				}
			}
		}
	}catch(Exception e){
		System.out.println("錯誤型別為"+e.getClass().getName());
	}
}
輸出結果:
---getInts3---
1:public com.A(java.lang.String[])
該方法的引數數量可變:true
該方法無法以int[]作為引數建立物件
錯誤型別為java.lang.IllegalArgumentException
2:public com.A(int[])
該方法的引數數量可變:true
有參構造方法,引數為一個int型別的陣列
該陣列的值分別為:1-2-3
3:public com.A(int)
該方法的引數數量可變:false
4:public com.A()
該方法的引數數量可變:false
成功得到了需要的構造方法,並且用它建立了一個物件。

雖然成功得到了,但是還是覺得應該有某一種方式可以直接得到符合引數要求的單個Constructor物件的方式,而不是在類所有的構造方法中挨個去判定。

= =所以還是有一點糾結,如果在後面的學習中發現了新的方式會補充上來的= =

=================分===============割=================線=======================

找到方法了!!!!找到了媽個雞!!!!

我們將第四個方法改一下![arr={1,2,3}]

public static void getInts2(int...arr){
	System.out.println("---getInts2---");
	Class class1=A.class;
	try{
		Constructor<A> constructor=class1.getConstructor((new int[0]).getClass());
		A a=constructor.newInstance(arr);
		/*
		System.out.println(constructor);
		A a=constructor.newInstance(null);
		*/
	}catch(Exception e){
		System.out.println("錯誤型別為"+e.getClass().getName());
	}
}
輸出結果:
---getInts2---
有參構造方法,引數為一個int型別的陣列
該陣列的值分別為:1-2-3
似乎看上去應該是一個數組物件然後呼叫getClass方法,而不是一個單個的物件呼叫getClass。

所以我覺得需要繼續嘗試一下!

現在要對A類的String那個構造方法進行嘗試![arr={"str1","str2","str3"}]

public static void getStrs1(String...arr){
	System.out.println("---getStrs1---");
	Class class1=A.class;
	try{
		Constructor<A> constructor=class1.getConstructor((new String[0]).getClass());
		System.out.println(constructor);
		A a=constructor.newInstance(arr);
	}catch(Exception e){
		System.out.println("錯誤型別為"+e.getClass().getName());
	}
}
輸出結果:
---getStrs1---
public com.A(java.lang.String[])
錯誤型別為java.lang.IllegalArgumentException
很絕望= =引數不匹配,但是明明Constructor物件已經取正確了啊,引數的確是String的可變長度陣列啊!

於是我又修改了一下= =

	public static void getStrs1(String...arr){
		System.out.println("---getStrs1---");
		Class class1=A.class;
		try{
			Constructor<A> constructor=class1.getConstructor((new String[0]).getClass());
			Class[] fields=constructor.getParameterTypes();
			System.out.println("引數列表長度為:"+fields.length);
			for (int i=0;i<fields.length;i++){
				System.out.println((i+1)+"引數型別為:"+fields[i].getName());
			}
			System.out.println("引數arr的型別為:"+arr.getClass().getName());
			System.out.println(constructor);
			A a=constructor.newInstance(arr);
		}catch(Exception e){
			System.out.println("錯誤型別為"+e.getClass().getName());
		}
	}
輸出結果:
---getStrs1---
引數列表長度為:1
1引數型別為:[Ljava.lang.String;
引數arr的型別為:[Ljava.lang.String;
public com.A(java.lang.String[])
錯誤型別為java.lang.IllegalArgumentException
所以我也不知道說什麼好= =明明型別都是[Ljava.lang.String;,但是就是型別不匹配,心好累= =

等知道為什麼了再繼續寫吧= =