網(wǎng)站規(guī)劃怎么寫英文seo兼職
目錄
基本概念
定義
用途
反射相關(guān)的類
反射基本原理
Class 類中的相關(guān)方法
常用獲得類相關(guān)的方法
常用獲得類中屬性相關(guān)的方法
常用獲得類中構(gòu)造器相關(guān)的方法
常用獲得類中方法相關(guān)的方法
實(shí)例理解
反射優(yōu)缺點(diǎn)
基本概念
定義
- Java 的反射(reflection)機(jī)制是一種強(qiáng)大功能,它可以讓我們?cè)?span style="color:#1c7331;">運(yùn)行時(shí)動(dòng)態(tài)地獲取和操作 類 或 對(duì)象 的信息
實(shí)例理解
- 我們可以通過(guò)反射機(jī)制來(lái)創(chuàng)建一個(gè)類的對(duì)象,而不需要使用 new 關(guān)鍵字
- 我們也可以通過(guò)反射機(jī)制來(lái)訪問(wèn)或修改一個(gè)對(duì)象的私有屬性或方法,而不需要遵循封裝原則
- 我們還可以通過(guò)反射機(jī)制來(lái)調(diào)用一個(gè)對(duì)象的任意方法,而不需要知道它的參數(shù)類型或返回值類型
用途
典型用途一:
- 在開發(fā)第三方應(yīng)用時(shí),我們可能會(huì)遇到一些類的成員變量、方法或?qū)傩允撬接械?#xff0c;或者只對(duì)系統(tǒng)應(yīng)用開放,這就意味著我們不能直接訪問(wèn)這些成員或方法
- 這時(shí)我們便可以在運(yùn)行時(shí) 通過(guò) Java 的反射機(jī)制 來(lái)動(dòng)態(tài)地訪問(wèn)和操作類的內(nèi)部成員,包括私有成員和方法
典型用途二:
- 反射在開發(fā)通用框架 Spring 中起著重要的作用
- 在Spring 框架中,所有類(Bean)都由 Spring 容器進(jìn)行管理,這些 Bean 可以通過(guò) XML 配置或注解來(lái)配置
- 當(dāng)我們從容器中獲取Bean 以進(jìn)行依賴注入時(shí),容器會(huì)讀取配置信息,這些配置信息包含了類的信息,比如類的名稱、屬性、方法等
- Spring根據(jù)這些信息 動(dòng)態(tài)地創(chuàng)建這些類的實(shí)例,這個(gè)過(guò)程就是所謂的 依賴注入,該過(guò)程中,反射起到了關(guān)鍵作用
- Spring 使用反射來(lái)動(dòng)態(tài)地創(chuàng)建類的實(shí)例,調(diào)用方法,以及設(shè)置屬性值
反射相關(guān)的類
反射基本原理
- Java 的反射機(jī)制是基于 java.lang.Class 類實(shí)現(xiàn)的
- 當(dāng)我們編譯一個(gè) Java 文件時(shí),會(huì)生成一個(gè) .class 文件
- 當(dāng) JVM 加載這個(gè) .class 文件時(shí),會(huì)將其解析為一個(gè) java.lang.Class 類的對(duì)象
- 在程序運(yùn)行時(shí),每個(gè) Java 文件都會(huì)被 JVM 解析為一個(gè) Class 類的實(shí)例
- 這個(gè) Class 類的實(shí)例包含了該 Java 文件中所定義類的所有信息,包括類的名稱、屬性、方法等
- 我們可以通過(guò) Java 的反射機(jī)制來(lái)操作這個(gè) Class 類的實(shí)例
- 具體來(lái)說(shuō),我們可以使用反射來(lái)獲取類的屬性和方法,甚至可以添加或修改類的屬性和方法
- 這使得我們可以在運(yùn)行時(shí)動(dòng)態(tài)地操作類,使其成為一個(gè) 動(dòng)態(tài)的類
類名 用途 Class 類 代表類的實(shí)體,在運(yùn)行的 Java 應(yīng)用程序中表示類和接口 Field 類 代表類的成員變量、類的屬性 Method 類 代表類的方法 Constructor 類 代表類的構(gòu)造方法
Class 類中的相關(guān)方法
常用獲得類相關(guān)的方法
方法 用途 getClassLoader() 獲得類的加載器 getDeclaredClasses() 返回一個(gè)數(shù)組,數(shù)組中包含該類中所有類和接口類的對(duì)象(包括私有的) forName(String className) 根據(jù)類名返回類的對(duì)象 newInstance() 創(chuàng)建類的實(shí)例 getName() 獲得類的完整路徑名字 常用獲得類中屬性相關(guān)的方法
方法 用途 getField(String name) 獲得某個(gè)公有的屬性對(duì)象 getFields() 獲得所有公有的屬性對(duì)象 getDeclaredField(String name) 獲得某個(gè)屬性對(duì)象 getDeclaredFields() 獲得所有屬性對(duì)象 常用獲得類中構(gòu)造器相關(guān)的方法
方法 用途 getConstructor(Class <?> parameterTypes) 獲得該類中與參數(shù)類型匹配的公有構(gòu)造方法 getConstructors() 獲得該類的所有公有構(gòu)造方法 getDeclaredConstructor(Class <?> parameterTypes) 獲得該類中與參數(shù)類型匹配的構(gòu)造方法 getDeclaredConstructors() 獲得該類所有構(gòu)造方法 常用獲得類中方法相關(guān)的方法
方法 用途 getMethod(String name, Class <?> parameterTypes) 獲得該類某個(gè)公有的方法 getMethods() 獲得該類所有公有的方法 getDeclaredMethod(String name, Class <?> parameterTypes) 獲得該類某個(gè)方法 getDeclaredMethods() 獲得該類所有方法
實(shí)例理解
- 此處我們先創(chuàng)建一個(gè) Student 類
class Student{//私有屬性nameprivate String name = "master";//公有屬性agepublic int age = 18;//不帶參數(shù)的構(gòu)造方法public Student(){System.out.println("Student()");}private Student(String name,int age) {this.name = name;this.age = age;System.out.println("Student(String,name)");}private void eat(){System.out.println("make hamburger!");}public void sleep(){System.out.println("go to bed!");}private void function(String str) {System.out.println(str);}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';} }
- 此處介紹三種方式來(lái)獲取 Student 的 Class 對(duì)象
public class Demo1 {public static void main(String[] args) { // 有三種方式可以獲取 Class 對(duì)象Student student1 = new Student(); // 1、通過(guò)對(duì)象的 getClass() 方法Class<?> c1 = student1.getClass(); // 2、通過(guò)類名 .class 獲取Class<?> c2 = Student.class; // 3、通過(guò)調(diào)用 Class.forName() 方法獲取了 Student 類的 Class 對(duì)象 // Class.forName() 方法需要一個(gè)類的全限定名(包括 包名和類名) 作為參數(shù) // 此處的 ? 是一個(gè)通配符,用于表示未知類型 // 當(dāng)我們聲明一個(gè)泛型變量時(shí),如果我們不確定或不關(guān)心實(shí)際的類型參數(shù),我們可以使用 ? 來(lái)表示Class<?> c3 = null;try {c3 = Class.forName("Student");} catch (ClassNotFoundException e) {throw new RuntimeException(e);} // 此處證明通過(guò)上述三種方式所獲取的 Class 對(duì)象 都是同一個(gè)System.out.println((c1.equals(c2) && c1.equals(c3) && c2.equals(c3)) ? "true" : "false");} }
- 此處我們通過(guò)反射機(jī)制創(chuàng)建一個(gè)對(duì)象
import java.lang.reflect.InvocationTargetException;public class ReflectClassDemo {// 通過(guò)反射創(chuàng)建一個(gè)對(duì)象public static void reflectNewInstance() throws InstantiationException, IllegalAccessException, ClassNotFoundException {Class<?> c3 = Class.forName("Student"); // 通過(guò)調(diào)用 Class 類的 newInstance() 方法來(lái)創(chuàng)建一個(gè) c3 對(duì)應(yīng)類的新實(shí)例 // newInstance() 方法調(diào)用的是這個(gè)類的無(wú)參構(gòu)造函數(shù) // 如果這個(gè)類沒(méi)有無(wú)參構(gòu)造函數(shù),或者無(wú)參構(gòu)造函數(shù)是私有的,那么 newInstance 會(huì)拋出一個(gè)異常 // 因?yàn)?newInstance() 方法返回的類型為 Object 類 所以需要類型轉(zhuǎn)換,此處轉(zhuǎn)換為 Student 類Student student = (Student) c3.newInstance();System.out.println(student);}public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {reflectNewInstance();} }
運(yùn)行結(jié)果:
- 此處我們通過(guò)反射機(jī)制獲取私有的構(gòu)造方法
import java.lang.reflect.Constructor;public class ReflectClassDemo {// 通過(guò)反射獲取私有的構(gòu)造方法public static void reflectPrivateConstructor() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {Class<?> c3 = Class.forName("Student");Constructor<?> constructor = c3.getDeclaredConstructor(String.class,int.class); // 注意只要是涉及到 private 都要使用 setAccessible(true) 來(lái)打開權(quán)限,此處的構(gòu)造方法為私有的constructor.setAccessible(true); // 此處利用構(gòu)造方法 修改年齡和性別Student student = (Student)constructor.newInstance("xiaolin",20);System.out.println(student);}public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {reflectPrivateConstructor();} }
運(yùn)行結(jié)果:
- 此處我們通過(guò)反射機(jī)制獲取私有屬性
import java.lang.reflect.Field;public class ReflectClassDemo {// 通過(guò)反射獲取私有屬性public static void reflectPrivateField() throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException {Class<?> c3 = Class.forName("Student");Field field = c3.getDeclaredField("name"); // 注意只要是涉及到 private 都要使用 setAccessible(true) 來(lái)打開權(quán)限,此處的 name 屬性是私有的field.setAccessible(true);Student student = (Student) c3.newInstance(); // 此處修改私有屬性field.set(student,"haoran");System.out.println(student);}public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {reflectPrivateField();} }
運(yùn)行結(jié)果:
- 此處我們通過(guò)反射機(jī)制獲取私有方法
import java.lang.reflect.Method;public class ReflectClassDemo {// 通過(guò)反射獲取私有方法public static void reflectPrivateMethod() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {Class<?> c3 = Class.forName("Student");Method method1 = c3.getDeclaredMethod("function", String.class);Method method2 = c3.getDeclaredMethod("sleep"); // 注意只要是涉及到 private 都要使用 setAccessible(true) 來(lái)打開權(quán)限,此處的 function 方法是私有的method1.setAccessible(true);Student student = (Student) c3.newInstance(); // 此處給 function 方法傳參method1.invoke(student,"此處利用反射機(jī)制給 function 方法傳個(gè)字符串參數(shù)"); // 此處調(diào)用 sleep 方法,該方法為 public 無(wú)需額外打開權(quán)限,直接調(diào)用即可method2.invoke(student);}public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {reflectPrivateMethod();} }
運(yùn)行結(jié)果:
反射優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
- 對(duì)于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法,對(duì)于任意一個(gè)類都能調(diào)用它的任意一個(gè)方法
- 增加程序的靈活性和擴(kuò)展性,降低耦合性,提高自適應(yīng)性
- 反射已經(jīng)運(yùn)用在很多流行框架,典型代表為 Spring
缺點(diǎn)
- 使用反射會(huì)有效率問(wèn)題,會(huì)導(dǎo)致程序效率降低
- 反射技術(shù)繞過(guò)了源代碼的技術(shù),因而會(huì)帶來(lái)維護(hù)問(wèn)題
- 反射代碼比相應(yīng)的直接代碼更復(fù)雜
總結(jié):
- 雖然反射非常強(qiáng)大,但也需要謹(jǐn)慎使用
- 我們需要在反射帶來(lái)的靈活性和可擴(kuò)展性與其帶來(lái)的性能開銷、維護(hù)問(wèn)題和代碼復(fù)雜性之間找到一個(gè)平衡
- 某些情況下,比如開發(fā)通用的框架,使用反射式非常有價(jià)值的
- 但在其他情況下,我們可能更傾向于使用更簡(jiǎn)單、更直接的代碼