<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Java的反射(reflection
)機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意方法和屬性,既然能拿到,那麼我們就可以修改部分型別資訊;這種動態獲取資訊以及動態呼叫物件方法的功能稱為java語言的反射(reflection
)機制。
1、在日常的第三方應用開發過程中,經常會遇到某個類的某個成員變數、方法或是屬性是私有的或是只對系統應用開放,這時候就可以利用Java的反射機制通過反射來獲取所需的私有成員或是方法 。
2、反射最重要的用途就是開發各種通用框架,比如在spring
中,我們將所有的類Bean
交給spring
容器管理,無論是XML
設定Bean
還是註解設定,當我們從容器中獲取Bean
來依賴注入時,容器會讀取設定,而設定中給的就是類的資訊,spring
根據這些資訊,需要建立哪些Bean
,spring
就動態的建立這些類。
Java程式中許多物件在執行時會出現兩種型別:執行時型別(RTTI)和編譯時型別,例如Person p = newStudent();
這句程式碼中p
在編譯時型別為Person
,執行時型別為Student
。程式需要在執行時發現物件和類的真實資訊。而通過使用反射程式就能判斷出該物件和類屬於哪些類。
類名 | 用途 |
---|---|
Class類 | 代表類的實體,在執行的Java應用程式中表示類和介面 |
Field類 | 代表類的成員變數/類的屬性 |
Method類 | 代表類的方法 |
Constructor類 | 代表了類的構造方法 |
Class代表類的實體,在執行的Java應用程式中表示類和介面 .
Java
檔案被編譯後,生成了.class
檔案,JVM
此時就要去解讀.class
檔案 ,被編譯後的Java
檔案.class
也被JVM
解析為一個物件,這個物件就是 java.lang.Class
.這樣當程式在執行時,每個類檔案就最終變成了Class
類物件的一個範例。我們通過Java
的反射機制應用到這個範例,就可以去獲得甚至去新增改變這個類的屬性和動作,使得這個類成為一個動態的類 .
常用獲得類相關的方法:
方法 | 用途 |
---|---|
getClassLoader() | 獲得類的載入器 |
getDeclaredClasses() | 返回一個陣列,陣列中包含該類中所有類和介面類的物件(包括私有的) |
forName(String className) | 根據類名返回類的物件 |
newInstance() | 建立類的範例 |
getName() | 獲得類的完整路徑名字 |
常用獲得類中屬性相關的方法(以下方法返回值為Field相關)
方法 | 用途 |
---|---|
getField(String name) | 獲得某個公有的屬性物件 |
getFields() | 獲得某個公有的屬性物件 |
getDeclaredField(String name) | 獲得某個屬性物件 |
getDeclaredFields() | 獲得某個屬性物件 |
獲得類中註解相關的方法:
方法 | 屬性 |
---|---|
getAnnotation(Class annotationClass) | 返回該類中與引數型別匹配的公有註解物件 |
getAnnotations() | 返回該類所有的公有註解物件 |
getDeclaredAnnotation(Class annotationClass) | – |
getDeclaredAnnotations() | 返回該類所有的註解物件 |
獲得類中構造器相關的方法(以下方法返回值為Constructor相關)
方法 | 屬性 |
---|---|
getConstructor(Class…<?> parameterTypes) | 獲得該類中與引數型別匹配的公有構造方法 |
getConstructors() | 獲得該類的所有公有構造方法 |
getDeclaredConstructor(Class…<?> parameterTypes) | 獲得該類中與引數型別匹配的構造方法 |
getDeclaredConstructors() | 獲得該類中所以構造方法 |
在反射之前,我們需要做的第一步就是先拿到當前需要反射的類的Class
物件,然後通過Class
物件的核心方法,達到反射的目的,即:在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意方法和屬性,既然能拿到,那麼我們就可以修改部分型別資訊。
第一種,使用 Class.forName("類的全路徑名")
; 靜態方法。
前提:已明確類的全路徑名。
第二種,使用 .class
方法。
說明:僅適合在編譯前就已經明確要操作的 Class
。
第三種,使用類物件的 getClass()
方法。
程式碼範例:
本節程式碼均在一個包下面。
package reflectTest; class Student{ //私有屬性name private String name = "bit"; //公有屬性age public int age = 18; //不帶引數的構造方法 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("i am eat"); } public void sleep(){ System.out.println("i am pig"); } private void function(String str) { System.out.println(str); } @ Override public String toString() { return "Student{" + "name='" + name + ''' + ", age=" + age + '}'; } } public class test01 { public static void main(String[] args) { try { //通過 Class 物件的 forName() 靜態方法來獲取,用的最多, //但可能丟擲 ClassNotFoundException 異常 Class<?> c1 = Class.forName("reflectTest.Student"); //直接通過 類名.class 的方式得到,該方法最為安全可靠,程式效能更高 //這說明任何一個類都有一個隱含的靜態成員變數 class Class<?> c2 = Student.class; //通過getClass獲取Class物件 Student student = new Student(); Class<?> c3 = student.getClass(); System.out.println(c1.equals(c2)); System.out.println(c1.equals(c3)); System.out.println(c2.equals(c3)); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
輸出結果:
package reflectTest; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * 通過class類的newInstance方法獲取類的範例 */ public class ReflectClassDemo { public static void reflectNewInstance(){ try { //獲得Class物件 Class<?> c1 = Class.forName("reflectTest.Student"); //建立類的範例 Student student = (Student) c1.newInstance(); System.out.println(student); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } } /** * 反射私有的構造方法 */ public static void reflectPrivateConstructor() { try { Class<?> c1 = Class.forName("reflectTest.Student"); //構造方法 Constructor<?> constructor = c1.getDeclaredConstructor(String.class,int.class); //設定為true後可修改存取許可權 constructor.setAccessible(true); Student student = (Student) constructor.newInstance("world",18); System.out.println(student); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } /** * 反射私有屬性 */ public static void reflectPrivateField() { try { Class<?> c1 = Class.forName("reflectTest.Student"); Student student = (Student) c1.newInstance(); Field field = c1.getDeclaredField("name"); field.setAccessible(true); field.set(student,"zhang"); System.out.println(student); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } } // 反射私有方法 public static void reflectPrivateMethod() { try { Class<?> c1 = Class.forName("reflectTest.Student"); Student student = (Student) c1.newInstance(); Method method = c1.getDeclaredMethod("function",String.class); method.setAccessible(true); method.invoke(student,"我是私有的方法的引數"); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } public static void main(String[] args) { // reflectNewInstance(); // reflectPrivateConstructor(); // reflectPrivateField(); reflectPrivateMethod(); } }
優點:
1.對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法
2.增加程式的靈活性和擴充套件性,降低耦合性,提高自適應能力
3.反射已經運用在了很多流行框架如:Struts、Hibernate、Spring
等等。
缺點:
1.使用反射會有效率問題。會導致程式效率降低。
2.反射技術繞過了原始碼的技術,因而會帶來維護問題。反射程式碼比相應的直接程式碼更復雜 。
列舉的主要用途是:將一組常陣列織起來,在這之前表示一組常數通常使用定義常數的方式:
public static int final RED = 1; public static int final GREEN = 2; public static int final BLACK = 3;
但是常數舉例有不好的地方,例如:可能碰巧有個數位1,但是他有可能誤會為是RED,現在我們可以直接用列舉來進行組織,這樣一來,就擁有了型別,列舉型別。而不是普通的整形1。
程式碼範例:
package enumTest; public enum test01 { RED,BLACK,GREEN,WHITE; public static void main(String[] args) { // System.out.println(test01.BLACK); // System.out.println(BLACK); test01 te = test01.BLACK; switch (te) { case RED: System.out.println("red"); break; case BLACK: System.out.println("black"); break; case WHITE: System.out.println("white"); break; case GREEN: System.out.println("green"); break; default: break; } } }
輸出結果:
優點:將常陣列織起來統一進行管理;
場景:錯誤狀態碼,訊息型別,顏色的劃分,狀態機等等…
本質:是 java.lang.Enum
的子類,也就是說,自己寫的列舉類,就算沒有顯示的繼承 Enum
,但是其預設繼承了這個類。
方法名稱 | 描述 |
---|---|
values() | 以陣列形式返回列舉型別的所有成員 |
ordinal() | 獲取列舉元的索引位置 |
valueOf() | 將普通字串轉換為列舉範例 |
compareTo() | 比較兩個列舉元在定義時的順序 |
values()程式碼範例 :
public enum test01 { RED,BLACK,GREEN,WHITE; public static void main(String[] args) { test01[] te = test01.values(); for (int i = 0; i < te.length; i++) { System.out.println(te[i]); } } }
輸出結果:
ordinal() 程式碼範例:
public enum test01 { RED,BLACK,GREEN,WHITE; public static void main(String[] args) { test01[] te = test01.values(); for (int i = 0; i < te.length; i++) { System.out.println(te[i] + " --> " + te[i].ordinal()); } } }
輸出結果:
valueOf() 、compareTo() 程式碼範例:
public enum test01 { RED,BLACK,GREEN,WHITE; public static void main(String[] args) { //把字串變成對應的列舉物件 test01 te = test01.valueOf("RED"); System.out.println(te); System.out.println(RED.compareTo(GREEN));//-2 System.out.println(BLACK.compareTo(RED));//1 } }
輸出結果:
列舉的構造方法預設是私有的
public enum test01 { //列舉物件 RED("red",1),BLACK(),GREEN(),WHITE(); public String color; public int ordinal; //private 加或者不加其都是私有的 test01(String color, int ordinal) { this.color = color; this.ordinal = ordinal; } //無參構造 test01(){ } }
優點:
1.列舉常數更簡單安全 。
2.列舉具有內建方法 ,程式碼更優雅。
缺點:
1.不可繼承,無法擴充套件。
java.lang.Enum
Lambda
表示式是Java SE 8
中一個重要的新特性。lambda
表示式允許你通過表示式來代替功能介面。 lambda
表示式就和方法一樣,它提供了一個正常的參數列和一個使用這些引數的主體(body,可以是一個表示式或一個程式碼塊)。 Lambda
表示式(Lambda expression)
可以看作是一個匿名函數,基於數學中的λ
演算得名,也可稱為閉包(Closure
)。
基本語法: (parameters) -> expression 或 (parameters) ->{ statements; }
Lambda表示式由三部分組成:
1.paramaters
:類似方法中的形參列表,這裡的引數是函數式介面裡的引數。這裡的引數型別可以明確的宣告也可不宣告而由JVM
隱含的推斷。另外當只有一個推斷型別時可以省略掉圓括號。
2.->
:可理解為“被用於”的意思
3.方法體:可以是表示式也可以程式碼塊,是函數式介面裡方法的實現。程式碼塊可返回一個值或者什麼都不反回,這裡的程式碼塊等同於方法的方法體。如果是表示式,也可以返回一個值或者什麼都不返回。
// 1. 不需要引數,返回值為 2 () -> 2 // 2. 接收一個引數(數位型別),返回其2倍的值 x -> 2 * x // 3. 接受2個引數(數位),並返回他們的和 (x, y) -> x + y // 4. 接收2個int型整數,返回他們的乘積 (int x, int y) -> x * y // 5. 接受一個 string 物件,並在控制檯列印,不返回任何值(看起來像是返回void) (String s) -> System.out.print(s)
程式碼範例:
package lambdaTest; @FunctionalInterface //函數式介面 interface NoParameterNoReturn { //注意:只能有一個方法 void test(); } //無返回值一個引數 @FunctionalInterface interface OneParameterNoReturn { void test(int a); } //無返回值多個引數 @FunctionalInterface interface MoreParameterNoReturn { void test(int a,int b); } //有返回值無引數 @FunctionalInterface interface NoParameterReturn { int test(); } //有返回值一個引數 @FunctionalInterface interface OneParameterReturn { int test(int a); } //有返回值多引數 @FunctionalInterface interface MoreParameterReturn { int test(int a,int b); } public class test01 { public static void main(String[] args) { // {} return 可以省略 NoParameterReturn noParameterReturn = ()->{return 10;}; int ret = noParameterReturn.test(); System.out.println(ret);//10 //()可以省略 OneParameterReturn oneParameterReturn = (a) -> a; System.out.println(oneParameterReturn.test(10));//10 MoreParameterReturn moreParameterReturn = (a,b) -> a+b; System.out.println(moreParameterReturn.test(1,2));//3 } public static void main3(String[] args) { //() {} 可省略 OneParameterNoReturn oneParameterNoReturn = (a)-> System.out.println(a); oneParameterNoReturn.test(10);//10 //int型別可以省略 MoreParameterNoReturn moreParameterNoReturn = (a,b)-> System.out.println(a+b); moreParameterNoReturn.test(10,20);//30 } public static void main2(String[] args) { NoParameterNoReturn noParameterNoReturn = () -> System.out.println("重寫方法"); noParameterNoReturn.test(); } public static void main1(String[] args) { NoParameterNoReturn noParameterNoReturn = new NoParameterNoReturn(){ public void test(){ System.out.println("重寫方法"); } }; noParameterNoReturn.test(); } }
函數式介面定義:一個介面有且只有一個抽象方法 。
注意:
1.如果一個介面只有一個抽象方法,那麼該介面就是一個函數式介面。
2.如果我們在某個介面上宣告了 @FunctionalInterface
註解,那麼編譯器就會按照函數式介面的定義來要求該介面,這樣如果有兩個抽象方法,程式編譯就會報錯的。所以,從某種意義上來說,只要你保證你的介面中只有一個抽象方法,你可以不加這個註解。加上就會自動進行檢測的。
程式碼範例:
@FunctionalInterface //函數式介面 interface NoParameterNoReturn { //注意:只能有一個方法 void test(); } public static void main1(String[] args) { NoParameterNoReturn noParameterNoReturn = new NoParameterNoReturn(){ public void test(){ System.out.println("重寫方法"); } }; noParameterNoReturn.test(); } }
Lambda 表示式中存在變數捕獲 ,瞭解了變數捕獲之後,我們才能更好的理解Lambda 表示式的作用域 。Java當中的匿名類中,會存在變數捕獲。
package lambdaTest; class Test { public void func(){ System.out.println("func()"); } } public class test02 { public static void main(String[] args) { int a = 100; new Test(){ @Override public void func() { System.out.println("我是內部類,且重寫了func這個方法!"); System.out.println("捕獲遍歷" + a);//能捕獲到的變數,要麼是常數,要麼未發生改變過。 } }; } }
Lambda表示式的優點很明顯,在程式碼層次上來說,使程式碼變得非常的簡潔。缺點也很明顯,程式碼不易讀。
優點:
程式碼簡潔,開發迅速;方便函數語言程式設計;非常容易進行平行計算;Java 引入 Lambda,改善了集合操作;
缺點:
程式碼可讀性變差;在非平行計算中,很多計算未必有傳統的 for 效能要高;不容易進行偵錯;
本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注it145.com的更多內容!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45