一、什麼是反射?
請結合註解學習
1.定義
將類的各個組成部分封裝爲其他對象(Field,Constructor,Method),就是反射機制
2. 比如將class文件中的成員變量封裝爲第二階段Class類中的Field類
二、反射有什麼用?
- 運行的時候操作這些對象,
比如:你使用idea時候的class. 然後自動彈出的可用的提示方法
- 降低程序的耦合性。
三、如何獲取Class對象的3種方式,
1. 三種方式
-
Class.forName(“全類名”) : 階段1可以使用,將class文件,加載進內存並返回Class對象
多用於配置文件,讀取文件,加載類 -
Student.class : 階段2 可用,類的的屬性class **
多用於傳參** -
student.getClass() : 階段3可用,對象實例的方法
多用於對象獲取字節碼文件
2. 代碼示例
package Java學習.Java高級.註解和反射.反射.獲取Class類的方法;
/**
* 1. Class.forName("全類名") : 階段1可以使用,**將class文件,加載進內存並返回Class對象**
* 多用於**配置文件,讀取文件,加載類**
*
*
* 2. Student.class : 階段2 可用,**類的的屬性class **
* 多用於**傳參**
*
* 3. student.getClass() : 階段3可用,**對象實例的方法**
* 多用於**對象**獲取字節碼文件
*/
public class Demo01黑馬 {
public static void main(String[] args) throws ClassNotFoundException {
//1.
System.out.println("----1. Class.forName(\"全類名\")------");
System.out.println(Class.forName("Java學習.Java高級.註解和反射.反射.獲取Class類的方法.Student01"));
//2.
System.out.println("--------2. Student.class---------");
System.out.println(Student01.class);
//3.
System.out.println("-----3. student.getClass()-----");
System.out.println(new Student01().getClass());
System.out.println("-------123是否相等----------");
System.out.println(new Student01().getClass().hashCode());
System.out.println(Student01.class.hashCode());
System.out.println(Class.forName("Java學習.Java高級.註解和反射.反射.獲取Class類的方法.Student01").hashCode());
System.out.println("HashCode的值相等,地址值相等,");
System.out.println("結論: 同一個class字節碼文件的在程序的運行中,只會被加載一次" +
"\n無論通過哪一種方式獲取的class對象都是同一個.");
}
}
class Student01{
}
Run:
----1. Class.forName(“全類名”)------
class Java學習.Java高級.註解和反射.反射.獲取Class類的方法.Student01
--------2. Student.class---------
class Java學習.Java高級.註解和反射.反射.獲取Class類的方法.Student01
-----3. student.getClass()-----
class Java學習.Java高級.註解和反射.反射.獲取Class類的方法.Student01
-------123是否相等----------
1915910607
1915910607
1915910607
HashCode的值相等,地址值相等,
結論: 同一個class字節碼文件的在程序的運行中,只會被加載一次
無論通過哪一種方式獲取的class對象都是同一個.
Process finished with exit code 0
四、獲取的反射對象有什麼用?通過Class 獲取該類的Field,Constructor和Method對象,並且可以使用對應部分的方法(例如fiead.get())
1. Field
(1)知識點
* 一、獲取成員變量Field
* 1. getField("publicField") (public權限)1個字段publicField
* 2. getFields() (public權限)全部字段們
*
* 3. getDeclaredField("privateField") (所有權限)的1個字段privateField
* 4. getDeclaredFields() (所有權限)的字段們
* 二、使用field
* 1.get(): .get(person02)
* 2.set(): .set(person02,"設置的值")
* 3.暴力反射:獲取非public字段後需要暴力反射才能使用privateField的方法(比如get())
* privateField1.setAccessible(true);
(2) 代碼
package Java學習.Java高級.註解和反射.反射.heima.使用Class對象02.獲取字段Field021;
import Java學習.Java高級.註解和反射.反射.heima.使用Class對象02.Person02;
import java.lang.reflect.Field;
/**
* 一、獲取成員變量Field
* 1. getField("publicField") (public權限)1個字段publicField
* 2. getFields() (public權限)全部字段們
* <p>
* 3. getDeclaredField("privateField") (所有權限)的1個字段privateField
* 4. getDeclaredFields() (所有權限)的字段們
* 二、使用field
* 1.get(): .get(person02)
* 2.set(): .set(person02,"設置的值")
* 3.暴力反射:獲取非public字段後需要暴力反射才能使用privateField的方法(比如get())
* privateField1.setAccessible(true);
* <p>
* --------------------------------------------------------------------------
* 一、獲取構造方法Constructor
* 1. getConstructor(String.class) (public權限)1個String參數的Constructor
* 2.3.4.同理
* 二、使用constructor
* 1.newInstance(): 新建Person的實例 ,newInstance(String "name",int age)
* <p>
* -----------------------------------------------
* 一、獲取成員方法Method
* 1. getMethod("方法名eat",String.class) public權限的字段
* String.class方法的參數的類型String
* 2.3.4同上
* 二、Method的使用
* 1.invoke(): 調用方法 invoke("蛇皮怪"),蛇皮怪就是方法的參數。
* <p>
* -----------------------------------------------
* 一、獲取類名getName
* 1. getName()
*/
public class Demo02 {
public static void main(String[] args) throws Exception {
Person02 person02 = new Person02();
Class<? extends Person02> class1 = person02.getClass();
/**
* * 一、獲取成員變量Field
* * 1. getField(String name) public權限的字段
* * 2. getFields() 全部public權限字段們
* *
* * 3. getDeclaredField(String name) 獲取所有權限的(public --private)的字段
* * 4. getDeclaredFields() 獲取所有權限的(public --private)的字段們
* 拓展
* 5.獲取class1對象下字段privateField的值 privateField.get(class1)
* 6.設置值: privateField.set(class1,"設置的值")
* 7.暴力反射獲取
* privateField1.setAccessible(true);
*/
Field publicField = class1.getField("publicField");
System.out.println("-----------一、.---------");
System.out.println("1.getField(\"publicField\");-------");
System.out.println(publicField);
Object[] fields;
fields = class1.getFields();
System.out.println("2.getFields()-------");
for (int i = 0; i < fields.length; i++) {
System.out.println(fields[i]);
}
System.out.println("結論:只能獲取public類型的field");
System.out.println("4.getDeclaredFields()--------");
fields = class1.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
System.out.println(fields[i]);
}
/**
* * 拓展
* * 5.獲取class1對象下字段privateField的值 privateField.get(class1)
* * 6.設置值: privateField.set(class1,"設置的值")
* * 7.暴力反射獲取
* privateField1.setAccessible(true);
*/
System.out.println("5.獲取class1對象下字段privateField的值 privateField.get(person02)-------\n" +
"6.設置值: privateField.set(person02,\"設置的值\")-------");
Field privateField = class1.getField("publicField");
System.out.println("privateField.get(person02): " + privateField.get(person02));
privateField.set(person02, "set的值");
System.out.println("privateField.set(person02,\"set的值\"): " + privateField.get(person02));
System.out.println("暴力反射privateField1.setAccessible(true);----------");
Field privateField1 = class1.getDeclaredField("privateField");
//暴力反射前訪問私有報錯java.lang.IllegalAccessException
//System.out.println(privateField1.get(person02));
privateField1.setAccessible(true);
System.out.println("暴力反射就能獲取私有Field: " + privateField1.get(person02));
}
}
Run:
-----------一、.---------
1.getField(“publicField”);-------
public java.lang.String Java學習.Java高級.註解和反射.反射.heima.使用Class對象02.Person02.publicField
2.getFields()-------
public java.lang.String Java學習.Java高級.註解和反射.反射.heima.使用Class對象02.Person02.publicField
結論:只能獲取public類型的field
4.getDeclaredFields()--------
private java.lang.String Java學習.Java高級.註解和反射.反射.heima.使用Class對象02.Person02.privateField
java.lang.String Java學習.Java高級.註解和反射.反射.heima.使用Class對象02.Person02.defaltField
protected java.lang.String Java學習.Java高級.註解和反射.反射.heima.使用Class對象02.Person02.protectField
public java.lang.String Java學習.Java高級.註解和反射.反射.heima.使用Class對象02.Person02.publicField
5.獲取class1對象下字段privateField的值 privateField.get(person02)-------
6.設置值: privateField.set(person02,“設置的值”)-------
privateField.get(person02): null
privateField.set(person02,“set的值”): set的值
暴力反射privateField1.setAccessible(true);----------
暴力反射就能獲取私有Field: null
Process finished with exit code 0
2, Constructor
(1)知識點
* 一、獲取構造方法Constructor
* 1. getConstructor(String.class) (public權限)1個String參數的Constructor
* 2.3.4.同理
* 二、使用constructor
* 1.newInstance(): 新建Person的實例 ,newInstance(String "name",int age)
(2)code
package Java學習.Java高級.註解和反射.反射.heima.使用Class對象02.獲取構造方法Method022;
import Java學習.Java高級.註解和反射.反射.heima.使用Class對象02.Person02;
import java.lang.reflect.Constructor;
public class Demo022 {
public static void main(String[] args) throws Exception {
/**
* 一、獲取構造方法Constructor
* 1. getConstructor(String.class) (public權限)1個String參數的Constructor
* 2.3.4.同理
* 二、使用constructor
* 1.newInstance(): 新建Person的實例 ,newInstance(String "name",int age)
*/
Person02 person02 = new Person02();
Class<? extends Person02> aClass = person02.getClass();
Constructor<? extends Person02> constructor = aClass.getConstructor();//獲取無參構造
Constructor<? extends Person02> constructor1 = aClass.getConstructor(String.class);//獲取一個參數的構造
System.out.println("無參構造: " + constructor);
System.out.println("1參構造: " + constructor1);
System.out.println("-------二、獲取構造的作用,newInstance()新建person對象實例------------");
Person02 person021 = constructor1.newInstance("參數1");
System.out.println(person021);
}
}
Run:
無參構造: public Java學習.Java高級.註解和反射.反射.heima.使用Class對象02.Person02()
1參構造: public Java學習.Java高級.註解和反射.反射.heima.使用Class對象02.Person02(java.lang.String)
-------二、獲取構造的作用,newInstance()新建person對象實例------------
Person02{privateField=‘參數1’, defaltField=‘null’, protectField=‘null’, publicField=‘null’}
Process finished with exit code 0
3.Method
(1)知識點
* 一、獲取成員方法Method
* 1. getMethod("方法名eat",String.class) public權限的字段
* String.class方法的參數的類型String
* 2.3.4同上
* 二、Method的使用
* 1.invoke(): 調用方法 invoke("蛇皮怪"),蛇皮怪就是方法的參數。
(2)code
package Java學習.Java高級.註解和反射.反射.heima.使用Class對象02.獲取成員方法們Method023;
import Java學習.Java高級.註解和反射.反射.heima.使用Class對象02.Person02;
import java.lang.reflect.Method;
/**
* * 一、獲取成員方法Method
* * 1. getMethod("方法名eat",String.class) public權限的字段
* * String.class方法的參數的類型String
* * 2.3.4同上
* * 二、Method的使用
* * 1.invoke(): 調用方法 invoke("蛇皮怪"),蛇皮怪就是方法的參數。
*
* 1.使用class獲取Method
* 2.使用Method
* (1)使用method調用方法
* (2)使用method獲取方法名稱
*/
public class Demo_023 {
public static void main(String[] args) throws Exception {
//1.使用class獲取Method
Person02 person02 = new Person02();
Class<? extends Person02> aClass = person02.getClass();
Method eatMethod = aClass.getMethod("eat", String.class);
//2.使用method調用方法invoke()
eatMethod.invoke(person02, "個蛇皮");
System.out.println(eatMethod.getName());
}
}
Run:
eat…個蛇皮
eat
Process finished with exit code 0
五、案例練習.
1. 需求:
- 寫一個框架,不能改變類的任何的代碼的情況下,創建類的對象,並且執行其中的任意代碼
2. 實現原理:
- 配置文件
- 反射
3. 實現步驟
- 需要將創建對象的全類名和需要執行的文件定義在配置文件中
className=Java學習.Java高級.註解和反射.反射.heima.反射項目.Person
methodName=eat
- 在程序中加載讀取配置文件
//2.在程序中**加載讀取配置文件**----------
//2.1創建Properties對象
Properties properties = new Properties();
//2.2加載load()方法,加載配置文件,儲存key value 的值在properties中
//2.2.1 :load() 需要傳遞參數InputStream
String configuration = "D:\\Program Files\\JetBrains\\test1\\Lab\\src\\Java學習\\Java高級\\註解和" +
"反射\\反射\\heima\\反射項目\\configuration.properties";
FileInputStream fileInputStream = new FileInputStream(configuration);
properties.load(fileInputStream);
//2.3 獲取配置文件的數據:
String className = properties.getProperty("className");
String methodName = properties.getProperty("methodName");
- 使用反射技術加載類進內存
Class.forName("全類名")
- 創建Person對象
//4.創建Person對象------
//4.1因爲Class類的創建Person對象方法newInstance()已經棄用
//我們先創建獲得構造函數類Constructor在創建Person對象
//獲得構造函數類Constructor 無參
Constructor<?> constructor = aClass.getConstructor();
//4.2 newInstance()創建Person對象
Object person = constructor.newInstance();
- **5.用aClass獲取getMethod對象,然後再使用新建的person對象invoke(person)執行方法 **
//5.用aClass獲取getMethod對象,然後再使用新建的person對象invoke(person)執行方法---------------
Method method = aClass.getMethod(methodName);
method.invoke(person);
4. 代碼:
1.配置文件 configuration.properties
className=Java學習.Java高級.註解和反射.反射.heima.反射項目.Person
methodName=eat
2.Person 類:Person.java
package Java學習.Java高級.註解和反射.反射.heima.反射項目;
public class Person {
private String privateField;
String defaltField;
protected String protectField;
public String publicField;
public void eat(){
System.out.println("eat....");
}
public void eat(String food){
System.out.println("eat..."+food);
}
public Person() {
this.privateField = privateField;
}
public Person(String privateField) {
this.privateField = privateField;
}
@Override
public String toString() {
return "Person02{" +
"privateField='" + privateField + '\'' +
", defaltField='" + defaltField + '\'' +
", protectField='" + protectField + '\'' +
", publicField='" + publicField + '\'' +
'}';
}
public Person(String privateField, String defaltField, String protectField, String publicField) {
this.privateField = privateField;
this.defaltField = defaltField;
this.protectField = protectField;
this.publicField = publicField;
}
public String getPrivateField() {
return privateField;
}
public void setPrivateField(String privateField) {
this.privateField = privateField;
}
public String getDefaltField() {
return defaltField;
}
public void setDefaltField(String defaltField) {
this.defaltField = defaltField;
}
public String getProtectField() {
return protectField;
}
public void setProtectField(String protectField) {
this.protectField = protectField;
}
public String getPublicField() {
return publicField;
}
public void setPublicField(String publicField) {
this.publicField = publicField;
}
}
Demo_01.java
package Java學習.Java高級.註解和反射.反射.heima.反射項目;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;
/**
* 一、Properties類是Map的子類,性質類
* 1. Properties 對象可以把以properties結尾的文件
* 用load方法讀取到內存裏面形成一個集合
*
*/
public class Demo_01 {
public static void main(String[] args) throws Exception {
//2.在程序中**加載讀取配置文件**----------
//2.1創建Properties對象
Properties properties = new Properties();
//2.2加載load()方法,加載配置文件,儲存key value 的值在properties中
//2.2.1 :load() 需要傳遞參數InputStream
String configuration = "D:\\Program Files\\JetBrains\\test1\\Lab\\src\\Java學習\\Java高級\\註解和" +
"反射\\反射\\heima\\反射項目\\configuration.properties";
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(configuration),"GBK");
// 解碼出錯,properties是GBK格式
properties.load(inputStreamReader);
//2.3 獲取配置文件的數據:
String className = properties.getProperty("className");
String methodName = properties.getProperty("methodName");
System.out.println(className);
//3. 使用**反射**技術加載類**進內存**-----------
Class aClass = Class.forName(className);
//4.創建Person對象------
//4.1因爲Class類的創建Person對象方法newInstance()已經棄用
//我們先創建獲得構造函數類Constructor在創建Person對象
//獲得構造函數類Constructor 無參
Constructor<?> constructor = aClass.getConstructor();
//4.2 newInstance()創建Person對象
Object person = constructor.newInstance();
//5.用aClass獲取getMethod對象,然後再使用新建的person對象invoke(person)執行方法---------------
Method method = aClass.getMethod(methodName);
method.invoke(person);
}
}
Run:
Java學習.Java高級.註解和反射.反射.heima.反射項目.Person
eat…
Process finished with exit code 0