国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > Java > 正文

Java高質(zhì)量代碼之反射

2019-11-06 06:14:39
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

反射是java的一個(gè)非常重要但又很容易被忽略的知識(shí)點(diǎn),下面先讓我們來(lái)看看反射的基本使用:

a/新建Person類

public class Person {	public String name;	PRivate int age;	public void setAge(int age) {		this.age = age;	}		// 無(wú)參數(shù)	public void show() {		System.out.println("這是一個(gè)人");	}	// 一個(gè)參數(shù)	public void showNation(String nation) {		System.out.println("國(guó)籍是------->" + nation);	}		// 多個(gè)參數(shù)	public void showNation(String name, String nation, int age) {		this.name = name;		this.age = age;		System.out.println(name + "的國(guó)籍是------->" + nation + ",年齡是------>" + age);	}	@Override	public String toString() {		return "Person [name=" + name + ", age=" + age + "]";	}}b/執(zhí)行測(cè)試代碼

import java.lang.reflect.Field;import java.lang.reflect.Method;import org.junit.Test;public class TestReflection {	@Test	public void test1() throws Exception {		// 1、獲取運(yùn)行時(shí)類		Class clazz = Class.forName("com.test.Person");				// 2、創(chuàng)建運(yùn)行時(shí)類		// Person必須要有空參的構(gòu)造函數(shù),否則用newInstance實(shí)例化會(huì)報(bào)錯(cuò),構(gòu)造器修飾符權(quán)限要足夠,最好要給類留個(gè)空參構(gòu)造器、		Person person1 = (Person) clazz.newInstance();				// 3、操作屬性		//    3.1、公共屬性		Field field1 = clazz.getField("name");		field1.set(person1, "劉德華");		System.out.println(person1);		//    3.2、操作私有屬性		Field field2 = clazz.getDeclaredField("age");		field2.setaccessible(true);		field2.set(person1, 30);				// 4、操作方法。		//    4.1、方法無(wú)參數(shù)		Method method1 = clazz.getMethod("show");		method1.invoke(person1);		//    4.2、方法一個(gè)參數(shù)		Method method2 = clazz.getMethod("showNation", String.class);  // (方法名,參數(shù)類型)		method2.invoke(person1, "中國(guó)"); // (對(duì)象,實(shí)參)		//    4.3、方法多個(gè)參數(shù)		Method method3 = clazz.getMethod("showNation", String.class, String.class, int.class);		method3.invoke(person1, "張學(xué)友", "中國(guó)香港", 40);	}}結(jié)果輸出:

Person [name=劉德華, age=0]

這是一個(gè)人

國(guó)籍是------->中國(guó)

張學(xué)友的國(guó)籍是------->中國(guó)香港,年齡是------>40

1.注意Class類的特殊性      Java語(yǔ)言是先把Java源文件編譯成后綴為class的字節(jié)碼文件,然后通過(guò)ClassLoader機(jī)制把類文件加載到內(nèi)存當(dāng)中,最后生成實(shí)例執(zhí)行的,在描述一個(gè)類是,Java使用了一個(gè)元類來(lái)對(duì)類進(jìn)行描述,這就是Class類,他是一個(gè)描述類的類,所以注定Class類是特殊的       1.Class類無(wú)構(gòu)造函數(shù),Class對(duì)象加載時(shí)由JVM通過(guò)調(diào)用類加載器的         defineClass方法來(lái)構(gòu)造Class對(duì)象       2.Class類還可以描述基本數(shù)據(jù)類型,由于基本類型并不是Java中的對(duì)象,它們         一般存在于棧,但Class仍然可以對(duì)它們進(jìn)行描述,例如使用int.class       3.其對(duì)象都是單例模式,一個(gè)Class的實(shí)現(xiàn)對(duì)象描述一個(gè)類,并且只描述一個(gè)類         所以只要是該被描述的類所有對(duì)象都只有一個(gè)Class實(shí)例       4.Class類是Java反射的入口 2.適時(shí)選擇getDeclaredXXX和getXXX      Class類中提供了很多getDeclaredXXX和getXXX的方法,請(qǐng)看以下例子 

public static void main(String[] args) {		Class cls = User.class;		// 獲取類方法		cls.getDeclaredMethods();		cls.getMethods();		// 獲取類構(gòu)造函數(shù)		cls.getDeclaredConstructors();		cls.getConstructors();		// 獲取類屬性		cls.getDeclaredFields();		cls.getFields();	}      getXXX的方式是獲取所有公共的(public)級(jí)別的,包括從父類繼承的方法,而getDeclaredXXX的方式是獲取所有的,包括公共的(public),私有的(private),不受限與訪問(wèn)權(quán)限, 

3.反射訪問(wèn)屬性或方法時(shí)將Accessible設(shè)置為true      在調(diào)用構(gòu)造函數(shù)或方法的invoke前檢查accessible已經(jīng)是公認(rèn)的寫法,例如以下代碼 

public static void main(String[] args) throws Exception {		Class cls = User.class;		// 創(chuàng)建對(duì)象		User user = cls.newInstance();		// 獲取test方法		Method method = cls.getDeclaredMethod("test");		// 檢查Accessible屬性		if (!method.isAccessible()) {			method.setAccessible(true);		}		method.invoke(user);	}

      讀者可以嘗試獲取Class的getMethod,也就是公開的方法,再輸出isAccessible,可以看到輸出的其實(shí)也是false,其實(shí)因?yàn)閍ccessible屬性的語(yǔ)義并不是我們理解的訪問(wèn)權(quán)限,而是指是否進(jìn)行安全檢查,而安全監(jiān)察是非常消耗資源的,所以反射提供了Accessible可選項(xiàng),讓開發(fā)者逃避安全檢查,有興趣的讀者可以查看AccessibleObject類觀察其源碼了解安全檢查. 4.使用forName動(dòng)態(tài)加載類      forName相信各位讀者不會(huì)陌生,在使用JDBC時(shí)要?jiǎng)討B(tài)加載數(shù)據(jù)庫(kù)驅(qū)動(dòng)就是使用forName的方式進(jìn)行加載,同時(shí)亦可以從外部配置文件中讀取類的全路徑字符串進(jìn)行加載,在使用forName時(shí),被加載的類就會(huì)被加載到內(nèi)存當(dāng)中,只會(huì)加載類,并不會(huì)執(zhí)行任何代碼,而我們的數(shù)據(jù)庫(kù)驅(qū)動(dòng)就是利用static代碼塊來(lái)執(zhí)行操作的,因?yàn)楫?dāng)類被加載到內(nèi)存中時(shí),會(huì)執(zhí)行static代碼塊 5.使用反射讓模板方法更強(qiáng)大      模板方法的定義是,定義一個(gè)操作的算法骨架,將某些步驟延遲到子類當(dāng)中實(shí)現(xiàn),而實(shí)現(xiàn)細(xì)節(jié)由子類決定,父類只決定骨架,以下是一個(gè)傳統(tǒng)模板方法的事例 

public abstract class Test {		public final void doSomething() {			System.out.println("start...");			doInit();			System.out.println("end.....");		}		protectedabstractvoid doInit();	} 

    此時(shí)子類只需要繼承Test類實(shí)現(xiàn)doInit()方法即可嵌入到doSomething中,現(xiàn)在我們有一個(gè)需求,若我在doSomething中需要調(diào)用一系列的方法才能完成doSomething呢?而且我調(diào)用方法的數(shù)量并不確定,只需遵從某些規(guī)則則可將方法添加到doSomething方法當(dāng)中.請(qǐng)看以下代碼 

	public abstract class Test {		public final void doSomething() throws Exception {			Method[] methods = this.getClass().getDeclaredMethods();			System.out.println("start...");			for (Method method : methods) {				if (this.checkInitMethod(method)) {					method.invoke(this);				}			}			System.out.println("end.....");		}		private boolean checkInitMethod(Method method) {			// 方法名初始是否為init			return method.getName().startsWith("init")					// 是否為public修飾					&& Modifier.isPublic(method.getModifiers())					// 返回值是否為void					&& method.getReturnType().equals(Void.TYPE)					// 是否沒(méi)有參數(shù)					&& !method.isVarArgs()					// 是否抽象類型					&& !Modifier.isAbstract(method.getModifiers());		}	}    

      看到上面的代碼,讀者是否有似曾相識(shí)的感覺(jué)?在使用Junit3時(shí)是不是只要遵守方法的簽名約定,就能成為測(cè)試類?使用這種反射可以讓模板方法更強(qiáng)大,下次需要使用多個(gè)方法在模板方法中時(shí),不要?jiǎng)?chuàng)建多個(gè)抽象方法,嘗試使用以上方式 6.不要過(guò)分關(guān)注反射的效率      反射的效率是一個(gè)老生常談的問(wèn)題,普通的調(diào)用方法,創(chuàng)建類,在反射的情況下需要調(diào)用諸多API才能實(shí)現(xiàn),效率當(dāng)然要比普通情況下低下,但在項(xiàng)目當(dāng)中真正引起性能問(wèn)題的地方,絕大數(shù)不會(huì)是由反射引起的,而反射帶給我們的卻是如此的美妙,當(dāng)今的各系列開源框架,幾乎都存在反射的身影,而且大量存在更比比皆是,讓Java這個(gè)沉睡的美女活起來(lái)的,非反射莫屬 

部分資料源自互聯(lián)網(wǎng)


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 通辽市| 万年县| 商丘市| 岳普湖县| 乐清市| 长寿区| 龙山县| 永丰县| 黎城县| 杭州市| 松滋市| 宜川县| 孟州市| 娄底市| 壤塘县| 黄龙县| 新丰县| 岐山县| 当雄县| 万源市| 潞西市| 安达市| 安泽县| 唐海县| 昭平县| 斗六市| 开封市| 策勒县| 晋中市| 逊克县| 神池县| 静宁县| 武邑县| 汤原县| 谷城县| 林甸县| 元朗区| 蕉岭县| 南丰县| 商城县| 余庆县|