天天看點

黑馬程式員-反射-.class-Class.forName()-object.getClass()-Constructor-Field

------<a href="http://www.itheima.com" target="_blank" rel="external nofollow" target="blank">Java教育訓練、Android教育訓練、iOS教育訓練、.Net教育訓練</a>、期待與您交流! -------

反射

Class 類:反射的基石

反射就是将java類中的各種成分映射成相應的java類。

java程式中的各個java類,可以描述為同一類事物,用Class類來表示。

換句話說:Class類是全部java類的抽象,無論是JDK中的,還是自定義的類。

void,數組,java基本資料類型也都表示為Class對象。

特性:

Class類沒有公共構造方法,Class對象是在加載類時由Java虛拟機以及通過調用類加載器中的defineClass方法自動構造的。

1. Class cls1 = 類名.class;

2. Class cls2 = 對象引用(或對象).getClass();

3. Class cls3 = Class.forName(“類名稱”);

常用方法:

1. Object.getClass():傳回此Object的運作時類。

2. isPrimitive():判定指定的Class對象,是否指定一個基本資料類型。

3. Class.forName(String className)

傳回 字元串指定的類或接口相關連的Class對象。

傳回位元組碼檔案(.class檔案)兩種方式:

1. 已加載過得類,放在java虛拟機中。

2. 沒有加載過,類加載器加載到虛拟機中。

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

1. 類名.class (如:System.class)

2. 對象.getClass() (如:new Data().getClass)

3. Class.forName(“類名”) (如:Class.forName(“java.lang.Thread”) )

forNmae(“類名”),将執行個體化該類

getConstructor() Constructor strConst =  Class.forName("java.lang.String").getConstructor(StringBuffer.class); 獲得具體的構造方法時,要傳遞類型 Constructor類 String str = (String)strConst.newInstance(new StringBuffer("abc")); 調用獲得的方法來構造對象時,要用到相同類型的執行個體對象。 getField() 1. 非private成員 ① 通過反射通路成員變量時,通過Class類的getField(“成員變量名稱”)方法,得到Field對象。 ② 再将被通路的對象,傳遞給Field對象,即可得到該值了。 2. private成員 ① 使用Class類的getDeclaredField(),該方法可以傳回全部聲明過的字段。 ② 使用Field類的父類AccessibleObject的setAccessible(boolean flag)方法将私有變量設定成為可通路的變量。

public static void myGetField() throws Exception {
		// 1. 使用反射得到單個變量的構造方法的對象,這是傳遞的變量為構造函數的類型
		Constructor fieConst = ReflectField.class.getConstructor(int.class,int.class);
		
		// 2. 使用此構造方法類的對象,執行個體化類,傳遞給類型對應的對象
		ReflectField rf = (ReflectField)fieConst.newInstance(4,5);
		
		// 3. 傳遞要查詢的字段名,傳回
		Field fieldA = ReflectField.class.getField("x");
		
		// 4. 傳遞對象,字段對象根據獲得其相應的值,說明該類通路另一個對象。
		System.out.println(fieldA.get(rf));
		
		// y字段為private,需要使用Field的getDeclaredField,傳回所有聲明過的對象。
		Field fieldY = ReflectField.class.getDeclaredField("y");
		// 私有成員變量,需要暴力反射,設定為可以通路
		fieldY.setAccessible(true);
		System.out.println(fieldY.get(rf));
	
      

getMethod() public Method getMethod(String name, Class<T>... parameterTypes ) name : 方法名 parameter Types : 參數清單   Method類 invoke()方法: public Object invoke(Object obj , Object...arg / Object[]...args) 參數: 1. obj : 從這個對象中調用底層方法。  ① 如果底層方法是靜态的,則可以忽略obj參數,該參數可以為null。 ② 如果底層方法是靜态,并且尚未初始化聲明此方法的類,則會将其初始化 2. args : 參數清單。 * 如果底層方法所需的形參個數為0,則所提供的args長度,可以為0或null。     public static void myGetMethod() throws Exception { String str = "123"; Method charAtMethod = String.class.getMethod("charAt", int.class); System.out.println(charAtMethod.invoke(str,1)); System.out.println(charAtMethod.invoke(str, new Object[]{2})); }   對接收數組方式的成員方法反射 在A類的main方法中,調用B類的main方法,并且傳遞字元串參數給B的main方法: 注意: 1. 需要給A的main的參數清單args[0]複制,B類的名稱。 2. main方法是static的,則可以忽略該對象參數,而隻傳遞null。

public class GetXxx {

	public static void main(String[] args) throws Exception {
		//myGetConstructor();
		//myGetMethod();
		/**
		 * 1. 因為在GetXxx類運作時,其main方法的參數傳遞了TestArguments的完整類名,
		 * 是以,就能夠根據ClassName來獲得該類的位元組碼,進而可以得到該類的全部内容。
		 * **/
		String mainArgument = args[0];
		
		// 2.根據args[0]就可以獲得TestArguments類的位元組碼檔案,進而得到main方法。
		Method mainMethod = Class.forName(mainArgument).getMethod("main", String[].class);
		
		// 3. main()方法是靜态的,靜态的則不用傳遞對象,傳遞null即可。
		mainMethod.invoke(null, (Object)new String[]{"111","222","333"});
		
	}
}
           
class TestArguments {
	public static void main(String[] args) {
		for(String arg : args) {
			System.out.println(arg);
		}
	}
}
           

數組: Class類: 每個數組屬于被映射為Class對象的一個類,所有具有相同類型及次元的數組 都共享該Class類。   getName():

public String getName() 

以 String 的形式傳回此 Class 對象所表示的實體(類、接口、數組類、基本類型或 void)名稱。

1. 當類對象表示一個數組類型: ① 其名字為: 表示該數組嵌套的一個或多個”[”字元加元素類型名。 2. 當類對象表示一個非數組類型的引用類型: 3. 當類對象表示一個基本資料類型或void: ① 傳回該類的二進制名稱   getSuperclass()

public Class<? super T> getSuperclass() 

傳回表示此 Class 所表示的實體(類、接口、基本類型或 void)的超類的 Class。

System.out.println(a1.getClass().getSuperclass().getName());
		System.out.println(s1.getClass().getSuperclass().getName());
		System.out.println(a1.getClass().getSuperclass().getName() == s1.getClass().getSuperclass().getName());
           

結果:

java.lang.Object

java.lang.Object

true

Arrays類

asList方法

public static <T> List<T> asList(T... a)

說明:JDK1.4asList方法,其參數支援Object[]數組。是以傳遞的是Object數組,則其可以直接解析,非Object的參數,則傳回其對應的getName()方法傳回的數組的名稱。

int[][] a4 = new int[][]{{1,2,3,4}};
		String[] s2 = new String[]{"a","b","c"};
		
		System.out.println(Arrays.asList(a4));
		System.out.println(Arrays.asList(s2));
           

結果為:

[[[email protected]]

[a, b, c]

需求:

使用反射,周遊類的數組。

Class類 --> isArray()

boolean isArray() 

判定此 Class 對象是否表示一個數組類。

Array類 --> getLength(Object obj)

static int getLength(Object array) 

以 int 形式傳回指定數組對象的長度。

Array類 --> get(Object array, int index)

static Object get(Object array, int index) 

傳回指定數組對象中索引元件的值。

public static void main(String[] args) {
		// testArray();
		int[][] a = new int[][]{{1,2,3,4}};
		int[] a1 = new int[]{11,22,33,44};
		int i = 2;
		String[] s = new String[]{"a","b","c"};
		Object[] objs = {a,a1,i,s};
		for(Object obj : objs) {
			printArray(obj);
		}
	}
	
	public static void printArray(Object objs) {
		// 1. Class類的isArray()方法,判斷該對象是否為數組
		if(objs.getClass().isArray()) {
			// 2. Array類的static getLength(Object obj)方法,獲得該數組對象的長度。
			for(int i = 0; i < Array.getLength(objs) ; i++) {
				// 3. Array類的static get(Object obj , int index)方法,得到數組對應索引上的值。
				System.out.println(Array.get(objs, i));
			}
		} else {
			System.out.println(objs);
		}
	}
           

架構

架構的思想

架構就是開發商改好的毛坯房,自己寫的類就像後來根據門框大小,木桶标準等等自己安裝的家具門窗。自己寫的類是為架構服務的。

與工具類的差別

工具類是為自己寫的類服務的,而自己寫的類是為架構服務的。

代碼:

config.properties

className=java.util.HashSet

package com.lxh.reflect;
import java.util.*;
import java.io.*;
public class ReflectFrame {

	public static void main(String[] args) throws Exception {
		InputStream in = new FileInputStream("C:\\Users\\fox\\Workspaces\\MyEclipse 8.5\\reflect\\src\\com\\lxh\\reflect\\config.properties");
		Properties prop = new Properties();
		prop.load(in);
		String className = prop.getProperty("className");
		/**
		 * 反射
		 * 先寫好這個類,隻需要在開始運作這個類之前,其他類已經寫好了就可以。
		 * */
		Collection collections = (Collection)Class.forName(className).newInstance();
		
		// 建立幾個圓點的對象,其中rf1和rf3的值相同。
		ReflectField rf1 = new ReflectField(1,1);
		ReflectField rf2 = new ReflectField(2,2);
		ReflectField rf3 = new ReflectField(1,1);
		
		collections.add(rf1);
		collections.add(rf2);
		collections.add(rf3);
		collections.add(rf1);
		
//		rf1.x = 5;
//		collections.remove(rf3);
		System.out.println(collections.size());
	}

}
           

繼續閱讀