1. 程式人生 > >Java不懂反射,和鹹魚有什麼區別啊!

Java不懂反射,和鹹魚有什麼區別啊!

Java反射的功能非常之強大,能夠深入的理解其思想,對自己的開發能力將有非常大的提高。

反射概述

Reflection(反射)是Java被視為動態語言的關鍵,反射機制允許程式在執行期藉助於Reflection API取得任何類的內部資訊,並能直接操作任意物件的內部屬性及方法。

在這裡還是要推薦下我自己建的Java學習裙:574加上253再加上075,群裡都是學Java開發的,如果你正在學習Java ,小編歡迎你加入,大家都是軟體開發黨,不定期分享乾貨(只有Java軟體開發相關的),包括我自己整理的一份2018最新的Java進階資料和高階開發教程,歡迎進階中和進想深入java的小夥伴

Java反射機制主要提供了以下功能:

· 在執行時構造任意一個類的物件

· 在執行時獲取任意一個類所具有的成員變數和方法

· 在執行時呼叫任意一個物件的方法(屬性)

· 生成動態代理

Class 是一個類; 一個描述類的類.

封裝了描述方法的 Method,

描述欄位的 Filed,

描述構造器的 Constructor 等屬性.

獲取Class物件的三種方式

1.通過類名獲取 類名.class

2.通過物件獲取 物件名.getClass()

3.通過全類名獲取 Class.forName(全類名)

public class ReflectionTest {

@Test

public void testClass() throws ClassNotFoundException {

Class clazz = null;

clazz = Person.class;

//這種方式是用在傳進來一個物件,卻不知道物件型別的時候使用

Person person = new Person();

clazz = person.getClass();

//上面這個例子的意義不大,因為已經知道person型別是Person類,再這樣寫就沒有必要了

//如果傳進來是一個Object類,這種做法就是應該的

Object obj = new Person();

clazz = obj.getClass();

//一般框架開發中這種用的比較多,因為配置檔案中一般配的都是全類名,通過這種方式可以得到Class例項

String className=" com.atguigu.java.fanshe.Person";

clazz = Class.forName(className);

//字串的例子

clazz = String.class;

clazz = “javaTest”.getClass();

clazz = Class.forName(“java.lang.String”);

System.out.println();

}

}

反射中最常用的幾個類:

Method

Field

Constructor

Annotation

如何描述方法-Method

public class ReflectionTest {

@Test

public void testMethod() throws Exception{

Class clazz = Class.forName(“com.atguigu.java.fanshe.Person”);

//

// 1.1 獲取取clazz對應類中的所有方法–方法陣列(一)

// 不能獲取private方法,且獲取從父類繼承來的所有方法

Method[] methods = clazz.getMethods();

for(Method method:methods){

System.out.print(" "+method.getName());

}

System.out.println();

//

// 1.2.獲取所有方法,包括私有方法 --方法陣列(二)

// 所有宣告的方法,都可以獲取到,且只獲取當前類的方法

methods = clazz.getDeclaredMethods();

for(Method method:methods){

System.out.print(" "+method.getName());

}

System.out.println();

// 1.3.獲取指定的方法

// 需要引數名稱和引數列表,無參則不需要寫

// 對於方法public void setName(String name) { }

Method method = clazz.getDeclaredMethod(“setName”, String.class);

System.out.println(method);

// 而對於方法public void setAge(int age) { }

method = clazz.getDeclaredMethod(“setAge”, Integer.class);

System.out.println(method);

// 這樣寫是獲取不到的,如果方法的引數型別是int型

// 如果方法用於反射,那麼要麼int型別寫成Integer: public void setAge(Integer age) { }

// 要麼獲取方法的引數寫成int.class

//

// invoke第一個引數表示執行哪個物件的方法,剩下的引數是執行方法時需要傳入的引數

Object obje = clazz.newInstance();

method.invoke(obje,2);

//如果一個方法是私有方法,第三步是可以獲取到的,但是這一步卻不能執行

//私有方法的執行,必須在呼叫invoke之前加上一句method.setAccessible(true);

}

}

如何描述欄位-Field

@Test

public void testField() throws Exception{

String className = “com.atguigu.java.fanshe.Person”;

Class clazz = Class.forName(className);

// 1.1 獲取所有欄位 – 欄位陣列

// 可以獲取公用和私有的所有欄位,但不能獲取父類欄位

Field[] fields = clazz.getDeclaredFields();

for(Field field: fields){

System.out.print(" "+ field.getName());

}

System.out.println();

// 1.2獲取指定欄位

Field field = clazz.getDeclaredField(“name”);

System.out.println(field.getName());

Person person = new Person(“ABC”,12);

// 2.1獲取指定物件的指定欄位的值

Object val = field.get(person);

System.out.println(val);

// 2.2設定指定物件的指定物件Field值

field.set(person, “DEF”);

System.out.println(person.getName());

// 2.3如果欄位是私有的,不管是讀值還是寫值,都必須先呼叫setAccessible(true)方法

// 比如Person類中,欄位name欄位是公用的,age是私有的

field = clazz.getDeclaredField(“age”);

field.setAccessible(true);

System.out.println(field.get(person));

}

如何描述構造器-Constructor

@Test

public void testConstructor() throws Exception{

String className = “com.atguigu.java.fanshe.Person”;

Class clazz = (Class) Class.forName(className);

//1. 獲取 Constructor 物件

// 1.1 獲取全部

Constructor [] constructors =

(Constructor[]) Class.forName(className).getConstructors();

for(Constructor constructor: constructors){

System.out.println(constructor);

}

// 1.2獲取某一個,需要引數列表

Constructor constructor = clazz.getConstructor(String.class, int.class);

System.out.println(constructor);

//2. 呼叫構造器的 newInstance() 方法建立物件

Object obj = constructor.newInstance(“zhagn”, 1);

}

如何描述註解 – Annotation

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)

@Target(value={ElementType.METHOD})

public @interface AgeValidator {

public int min();

public int max();

}

反射小結

  1. Class: 是一個類; 一個描述類的類.

封裝了描述方法的 Method,

描述欄位的 Filed,

描述構造器的 Constructor 等屬性.

  1. 如何得到 Class 物件:

2.1 Person.class

2.2 person.getClass()

2.3 Class.forName(“com.atguigu.javase.Person”)

  1. 關於 Method:

3.1 如何獲取 Method:

1). getDeclaredMethods: 得到 Method 的陣列.

2). getDeclaredMethod(String methondName, Class … parameterTypes)

3.2 如何呼叫 Method

1). 如果方法時 private 修飾的, 需要先呼叫 Method 的 setAccessible(true), 使其變為可訪問

2). method.invoke(obj, Object … args);

  1. 關於 Field:

4.1 如何獲取 Field: getField(String fieldName)

4.2 如何獲取 Field 的值:

1). setAccessible(true)

2). field.get(Object obj)

4.3 如何設定 Field 的值:

field.set(Obejct obj, Object val)

  1. 瞭解 Constructor 和 Annotation

ClassLoader

在這裡插入圖片描述 類載入的順序

public class ReflectionTest {

@Test

public void testClassLoader() throws ClassNotFoundException, FileNotFoundException{

//1. 獲取一個系統的類載入器(可以獲取,當前這個類PeflectTest就是它載入的)

ClassLoader classLoader = ClassLoader.getSystemClassLoader();

System.out.println(classLoader);

//2. 獲取系統類載入器的父類載入器(擴充套件類載入器,可以獲取).

classLoader = classLoader.getParent();

System.out.println(classLoader);

//3. 獲取擴充套件類載入器的父類載入器(引導類載入器,不可獲取).

classLoader = classLoader.getParent();

System.out.println(classLoader);

//4. 測試當前類由哪個類載入器進行載入(系統類載入器):

classLoader = Class.forName(“com.atguigu.java.fanshe.ReflectionTest”)

.getClassLoader();

System.out.println(classLoader);

//5. 測試 JDK 提供的 Object 類由哪個類載入器負責載入(引導類)

classLoader = Class.forName(“java.lang.Object”)

.getClassLoader();

System.out.println(classLoader);

}

}

//結果:

//null

//null

在這裡插入圖片描述