力扣每日一題:有效的山脈陣列
阿新 • • 發佈:2020-11-03
一·基本概念
-
通常情況下編寫程式碼都是固定的,無論執行多少次執行的結果也是固定的,在某些特殊場合中編寫
程式碼時不確定要建立什麼型別的物件,也不確定要呼叫什麼樣的方法,這些都希望通過執行時傳遞 的引數來決定,該機制叫做動態程式設計技術,也就是反射機制。
-
通俗來說,反射機制就是用於動態建立物件並且動態呼叫方法的機制。
-
目前主流的框架底層都是採用反射機制實現的。 如: Person p = new Person(); - 表示宣告Person型別的引用指向Person型別的物件 p.show(); - 表示呼叫Person類中的成員方法show
二·Class類
2.1基本概念
-
java.lang.Class類的例項可以用於描述Java應用程式中的類和介面,也就是一種資料型別。
-
該類沒有公共構造方法,該類的例項由Java虛擬機器和類載入器自動構造完成,本質上就是載入到內 存中的執行時類
2.2 獲取Class物件的方式
-
使用資料型別.class的方式可以獲取對應型別的Class物件(掌握)。
-
使用引用/物件.getClass()的方式可以獲取對應型別的Class物件。
-
使用包裝類.TYPE的方式可以獲取對應基本資料型別的Class物件。
-
使用Class.forName()的方式來獲取引數指定型別的Class物件(掌握)。
-
使用類載入器ClassLoader的方式獲取指定型別的Class物件。
功能介紹 | |
---|---|
static Class<?> forName(String className) | 用於獲取引數指定型別對應的Class物件並返回 |
T newInstance() |
public class ClassTest { public static void main(String[] args) throws ClassNotFoundException { // 1.使用資料型別.class的方式可以獲取對應型別的Class物件 Class c1 = String.class; System.out.println("c1 = " + c1); // 自動呼叫toString方法 class java.lang.String c1 = int.class; System.out.println("c1 = " + c1); // int c1 = void.class; System.out.println("c1 = " + c1); // void System.out.println("---------------------------------------------------"); // 2.使用物件.getClass()的方式獲取對應的Class物件 String str1 = new String("hello"); c1 = str1.getClass(); System.out.println("c1 = " + c1); // class java.lang.String Integer it1 = 20; c1 = it1.getClass(); System.out.println("c1 = " + c1); // class java.lang.Integer int num = 5; //num.getClass(); Error: 基本資料型別的變數不能呼叫方法 System.out.println("---------------------------------------------------"); // 3.使用包裝類.TYPE的方式來獲取對應基本資料型別的Class物件 c1 = Integer.TYPE; System.out.println("c1 = " + c1); // int c1 = Integer.class; System.out.println("c1 = " + c1); // class java.lang.Integer System.out.println("---------------------------------------------------"); // 4.呼叫Class類中的forName方法來獲取對應的Class物件 //c1 = Class.forName("String"); // Error 要求寫完整的名稱:包名.類名 c1 = Class.forName("java.lang.String"); System.out.println("c1 = " + c1); // class java.lang.String c1 = Class.forName("java.util.Date"); System.out.println("c1 = " + c1); // class java.util.Date //c1 = Class.forName("int"); //System.out.println("c1 = " + c1); // 不能獲取基本資料型別的Class物件 System.out.println("---------------------------------------------------"); // 5.使用類載入器的方式來獲取Class物件 ClassLoader classLoader = ClassTest.class.getClassLoader(); System.out.println("classLoader = " + classLoader); // null c1 = classLoader.loadClass("java.lang.String"); System.out.println("c1 = " + c1); // class java.lang.String } }
三 Constructor類
3.1 基本概念
java.lang.reflect.Constructor類主要用於描述獲取到的構造方法資訊
方法宣告 | 功能介紹 |
---|---|
Constructor getConstructor(Class<?>... parameterTypes) | 用於獲取此Class物件所表示型別中引數指定的 公共構造方法 |
Constructor<?>[] getConstructors() | 用於獲取此Class物件所表示型別中所有的公共 構造方法 |
3.2Constructor類的常用方法
方法宣告 | 功能介紹 |
---|---|
T newInstance(Object... initargs) | 使用此Constructor物件描述的構造方法來構造Class物件代表類 型的新例項 |
int getModifiers() | 獲取方法的訪問修飾符 |
String getName() | 獲取方法的名稱 |
Class<?>[] getParameterTypes() | 獲取方法所有引數的型別 |
public static void main(String[] args) throws Exception { // 1.使用原始方式以無參形式構造Person型別的物件並列印 Person p1 = new Person(); System.out.println("無參方式建立的物件是:" + p1); // null 0 System.out.println("---------------------------------------------------"); // 2.使用反射機制以無參形式構造Person型別的物件並列印 // 建立物件的型別可以從鍵盤輸入 //System.out.println("請輸入要建立物件的型別:"); //Scanner sc = new Scanner(System.in); //String str1 = sc.next(); //Class c1 = Class.forName("com.lagou.task20.Person"); // 建立物件的型別可以從配置檔案中讀取 BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("d:/a.txt"))); String str1 = br.readLine(); Class c1 = Class.forName(str1); //System.out.println("無參方式建立的物件是:" + c1.newInstance()); // null 0 // 獲取Class物件對應類中的無參構造方法,也就是Person類中的無參構造方法 Constructor constructor = c1.getConstructor(); // 使用獲取到的無參構造方法來構造對應型別的物件,也就是Person型別的物件 System.out.println("無參方式建立的物件是:" + constructor.newInstance()); //sc.close(); br.close(); System.out.println("---------------------------------------------------"); // 3.使用原始方式以有參方式構造Person型別的物件並列印 Person p2 = new Person("zhangfei", 30); System.out.println("有參方式構造的物件是:" + p2); // zhangfei 30 System.out.println("---------------------------------------------------"); // 4.使用反射機制以有參方式構造Person型別的物件並列印 // 獲取Class物件對應類中的有參構造方法,也就是Person類中的有參構造方法 Constructor constructor1 = c1.getConstructor(String.class, int.class); // 使用獲取到的有參構造方法來構造對應型別的物件,也就是Person型別的物件 // newInstance方法中的實參是用於給有參構造方法的形參進行初始化的,也就是給name和age進行初始化的 System.out.println("有參方式構造的物件是:" + constructor1.newInstance("zhangfei", 30)); // zhangfei 30 System.out.println("---------------------------------------------------"); // 5.使用反射機制獲取Person類中所有的公共構造方法並列印 Constructor[] constructors = c1.getConstructors(); for (Constructor ct : constructors) { System.out.println("構造方法的訪問修飾符是:" + ct.getModifiers()); System.out.println("構造方法的方法名稱是:" + ct.getName()); Class[] parameterTypes = ct.getParameterTypes(); System.out.print("構造方法的所有引數型別是:"); for (Class cs : parameterTypes) { System.out.print(cs + " "); } System.out.println(); System.out.println("-------------------------------------------------"); } } }
四· Field類
20.4.1 基本概念
java.lang.reflect.Field類主要用於描述獲取到的單個成員變數資訊。
4.2 Class類的常用方法
方法宣告 | 功能介紹 |
---|---|
Field getDeclaredField(String name) | 用於獲取此Class物件所表示類中引數指定的單個成員變數 資訊 |
Field[] getDeclaredFields() | 用於獲取此Class物件所表示類中所有成員變數資訊 |
4.3 Field類的常用方法
方法宣告 | 功能介紹 |
---|---|
Object get(Object obj) | 獲取引數物件obj中此Field物件所表示成員變數的數值 |
void set(Object obj, Object value) | 將引數物件obj中此Field物件表示成員變數的數值修改為引數 value的數值 |
void setAccessible(boolean flag) | 當實參傳遞true時,則反射物件在使用時應該取消 Java 語言訪 問檢查 |
int getModifiers() | 獲取成員變數的訪問修飾符 |
Class<?> getType() | 獲取成員變數的資料型別 |
String getName() | 獲取成員變數的名稱 |
public class PersonFieldTest { public static void main(String[] args) throws Exception { // 1.使用原始方式來構造物件以及獲取成員變數的數值並列印 Person p1 = new Person("zhangfei", 30); //System.out.println("獲取到的成員變數數值為:" + p1.name); // zhangfei System.out.println("-------------------------------------------------------"); // 2.使用反射機制來構造物件以及獲取成員變數的數值並列印 // 2.1 獲取Class物件 Class c1 = Class.forName("com.lagou.task20.Person"); // 2.2 根據Class物件獲取對應的有參構造方法 Constructor constructor = c1.getConstructor(String.class, int.class); // 2.3 使用有參構造方法來得到Person型別的物件 Object object = constructor.newInstance("zhangfei", 30); // 2.4 根據Class物件獲取對應的成員變數資訊 Field field = c1.getDeclaredField("name"); // 設定Java語言訪問檢查的取消 暴力反射 field.setAccessible(true); // 2.5 使用Person型別的物件來獲取成員變數的數值並列印 // 獲取物件object中名字為field成員變數的數值,也就是成員變數name的數值 System.out.println("獲取到的成員變數數值為:" + field.get(object)); // zhangfei System.out.println("-------------------------------------------------------"); // 3.使用原始方式修改指定物件中成員變數的數值後再次列印 //p1.name = "guanyu"; //System.out.println("修改後成員變數的數值為:" + p1.name); // guanyu System.out.println("-------------------------------------------------------"); // 4.使用反射機制修改指定物件中成員變數的數值後再次列印 // 表示修改物件object中名字為field成員變數的數值為guanyu,也就是成員變數name的數值為guanyu field.set(object, "guanyu"); System.out.println("修改後成員變數的數值為:" + field.get(object)); // guanyu System.out.println("-------------------------------------------------------"); // 5.獲取Class物件對應類中所有的成員變數 Field[] declaredFields = c1.getDeclaredFields(); for (Field ft : declaredFields) { System.out.println("獲取到的訪問修飾符為:" + ft.getModifiers()); System.out.println("獲取到的資料型別為:" + ft.getType()); System.out.println("獲取到的成員變數名稱是:" + ft.getName()); System.out.println("---------------------------------------------"); } } }
五·Method類
java.lang.reflect.Method類主要用於描述獲取到的單個成員方法資訊。
方法宣告 | 功能介紹 |
---|---|
Method getMethod(String name, Class<?>... parameterTypes) | 用於獲取該Class物件表示類中名字為name引數為 parameterTypes的指定公共成員方法 |
Method[] getMethods() | 用於獲取該Class物件表示類中所有公共成員方法 |
方法宣告 | 功能介紹 |
---|---|
Object invoke(Object obj, Object... args) | 使用物件obj來呼叫此Method物件所表示的成員方法,實 參傳遞args |
int getModifiers() | 獲取方法的訪問修飾符 |
Class<?> getReturnType() | 獲取方法的返回值型別 |
String getName() | 獲取方法的名稱 |
Class<?>[] getParameterTypes() | 獲取方法所有引數的型別 |
Class<?>[] getExceptionTypes() | 獲取方法的異常資訊 |
public class PersonMethodTest { public static void main(String[] args) throws Exception { // 1.使用原始方式構造物件並呼叫方法列印結果 Person p1 = new Person("zhangfei", 30); System.out.println("呼叫方法的返回值是:" + p1.getName()); // zhangfei System.out.println("------------------------------------------------------"); // 2.使用反射機制構造物件並呼叫方法列印結果 // 2.1 獲取Class物件 Class c1 = Class.forName("com.lagou.task20.Person"); // 2.2 根據Class物件來獲取對應的有參構造方法 Constructor constructor = c1.getConstructor(String.class, int.class); // 2.3 使用有參構造方法構造物件並記錄 Object object = constructor.newInstance("zhangfei", 30); // 2.4 根據Class物件來獲取對應的成員方法 Method method = c1.getMethod("getName"); // 2.5 使用物件呼叫成員方法進行列印 // 表示使用object物件呼叫method表示的方法,也就是呼叫getName方法來獲取姓名 System.out.println("呼叫方法的返回值是:" + method.invoke(object)); // zhangfei System.out.println("------------------------------------------------------"); // 3.使用反射機制來獲取類中的所有成員方法並列印 Method[] methods = c1.getMethods(); for (Method mt : methods) { System.out.println("成員方法的修飾符是:" + mt.getModifiers()); System.out.println("成員方法的返回值型別是:" + mt.getReturnType()); System.out.println("成員方法的名稱是:" + mt.getName()); System.out.println("成員方法形參列表的型別是:"); Class<?>[] parameterTypes = mt.getParameterTypes(); for (Class ct : parameterTypes) { System.out.print(ct + " "); } System.out.println(); System.out.println("成員方法的異常型別列表是:"); Class<?>[] exceptionTypes = mt.getExceptionTypes(); for (Class ct: exceptionTypes) { System.out.print(ct + " "); } System.out.println(); System.out.println("---------------------------------------------------"); } } }
六·獲取其它結構資訊
方法宣告 | 功能介紹 |
---|---|
Package getPackage() | 獲取所在的包資訊 |
Class<? super T> getSuperclass() | 獲取繼承的父類資訊 |
Class<?>[] getInterfaces() | 獲取實現的所有介面 |
Annotation[] getAnnotations() | 獲取註解資訊 |
Type[] getGenericInterfaces() | 獲取泛型資訊 |
@MyAnnotation public class Student<T, E> extends Person implements Comparable, Serializable { @Override public int compareTo(Object o) { return 0; } }
@Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { }
public class StudentTest { public static void main(String[] args) throws Exception { // 獲取Student型別的Class物件 Class c1 = Class.forName("com.lagou.task20.Student"); System.out.println("獲取到的包資訊是:" + c1.getPackage()); System.out.println("獲取到的父類資訊是:" + c1.getSuperclass()); System.out.println("-------------------------------------------------"); System.out.println("獲取到的介面資訊是:"); Class[] interfaces = c1.getInterfaces(); for (Class ct : interfaces) { System.out.print(ct + " "); } System.out.println(); System.out.println("-------------------------------------------------"); System.out.println("獲取到的註解資訊是:"); Annotation[] annotations = c1.getAnnotations(); for (Annotation at : annotations) { System.out.print(at + " "); } System.out.println(); System.out.println("-------------------------------------------------"); System.out.println("獲取到的泛型資訊是:"); Type[] genericInterfaces = c1.getGenericInterfaces(); for (Type tt : genericInterfaces) { System.out.print(tt + " "); } System.out.println(); } }