欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中的反射,枚舉及l(fā)ambda表達式的使用詳解

 更新時間:2022年03月04日 16:00:30   作者:來學習的小張  
這篇文章主要為大家詳細介紹了Java的反射,枚舉及l(fā)ambda表達式,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助

一、反射

1.1 定義

Java的反射(reflection)機制是在運行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意方法和屬性,既然能拿到,那么我們就可以修改部分類型信息;這種動態(tài)獲取信息以及動態(tài)調用對象方法的功能稱為java語言的反射(reflection)機制。

1.2 用途

1、在日常的第三方應用開發(fā)過程中,經(jīng)常會遇到某個類的某個成員變量、方法或是屬性是私有的或是只對系統(tǒng)應用開放,這時候就可以利用Java的反射機制通過反射來獲取所需的私有成員或是方法 。

2、反射最重要的用途就是開發(fā)各種通用框架,比如在spring中,我們將所有的類Bean交給spring容器管理,無論是XML配置Bean還是注解配置,當我們從容器中獲取Bean來依賴注入時,容器會讀取配置,而配置中給的就是類的信息,spring根據(jù)這些信息,需要創(chuàng)建哪些Bean,spring就動態(tài)的創(chuàng)建這些類。

1.3 反射基本信息

Java程序中許多對象在運行時會出現(xiàn)兩種類型運行時類型(RTTI)和編譯時類型,例如Person p = newStudent();這句代碼中p在編譯時類型為Person,運行時類型為Student。程序需要在運行時發(fā)現(xiàn)對象和類的真實信息。而通過使用反射程序就能判斷出該對象和類屬于哪些類。

1.4 與反射相關的類

類名用途
Class類代表類的實體,在運行的Java應用程序中表示類和接口
Field類代表類的成員變量/類的屬性
Method類代表類的方法
Constructor類代表了類的構造方法

1.5 Class類(反射機制的起源 )

Class代表類的實體,在運行的Java應用程序中表示類和接口 .

Java文件被編譯后,生成了.class文件,JVM此時就要去解讀.class文件 ,被編譯后的Java文件.class也被JVM解析為一個對象,這個對象就是 java.lang.Class .這樣當程序在運行時,每個類文件就最終變成了Class類對象的一個實例。我們通過Java的反射機制應用到這個實例,就可以去獲得甚至去添加改變這個類的屬性和動作,使得這個類成為一個動態(tài)的類 .

1.6 Class類中的相關方法

常用獲得類相關的方法:

方法用途
getClassLoader()獲得類的加載器
getDeclaredClasses()返回一個數(shù)組,數(shù)組中包含該類中所有類和接口類的對象(包括私有的)
forName(String className)根據(jù)類名返回類的對象
newInstance()創(chuàng)建類的實例
getName()獲得類的完整路徑名字

常用獲得類中屬性相關的方法(以下方法返回值為Field相關)

方法用途
getField(String name)獲得某個公有的屬性對象
getFields()獲得某個公有的屬性對象
getDeclaredField(String name)獲得某個屬性對象
getDeclaredFields()獲得某個屬性對象

獲得類中注解相關的方法

方法屬性
getAnnotation(Class annotationClass)返回該類中與參數(shù)類型匹配的公有注解對象
getAnnotations()返回該類所有的公有注解對象
getDeclaredAnnotation(Class annotationClass)
getDeclaredAnnotations()返回該類所有的注解對象

獲得類中構造器相關的方法(以下方法返回值為Constructor相關)

方法屬性
getConstructor(Class…<?> parameterTypes)獲得該類中與參數(shù)類型匹配的公有構造方法
getConstructors()獲得該類的所有公有構造方法
getDeclaredConstructor(Class…<?> parameterTypes)獲得該類中與參數(shù)類型匹配的構造方法
getDeclaredConstructors()獲得該類中所以構造方法

1.7 獲得Class對象的三種方式

在反射之前,我們需要做的第一步就是先拿到當前需要反射的類的Class對象,然后通過Class對象的核心方法,達到反射的目的,即:在運行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意方法和屬性,既然能拿到,那么我們就可以修改部分類型信息。

第一種,使用 Class.forName("類的全路徑名"); 靜態(tài)方法。

前提:已明確類的全路徑名。

第二種,使用 .class 方法。

說明:僅適合在編譯前就已經(jīng)明確要操作的 Class。

第三種,使用類對象的 getClass() 方法。

代碼示例:

本節(jié)代碼均在一個包下面。

package reflectTest;
class Student{
    //私有屬性name
    private String name = "bit";
    //公有屬性age
    public int age = 18;
    //不帶參數(shù)的構造方法
    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() 靜態(tài)方法來獲取,用的最多,
            //但可能拋出 ClassNotFoundException 異常
            Class<?> c1 = Class.forName("reflectTest.Student");
            //直接通過 類名.class 的方式得到,該方法最為安全可靠,程序性能更高
            //這說明任何一個類都有一個隱含的靜態(tài)成員變量 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();
        }
    }
}

輸出結果:

在這里插入圖片描述

1.8 反射的使用

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");
           //創(chuàng)建類的實例
           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,"我是私有的方法的參數(shù)");
        } 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.9 反射優(yōu)點和缺點

優(yōu)點

1.對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意一個方法

2.增加程序的靈活性和擴展性,降低耦合性,提高自適應能力

3.反射已經(jīng)運用在了很多流行框架如:Struts、Hibernate、Spring 等等。

缺點

1.使用反射會有效率問題。會導致程序效率降低。

2.反射技術繞過了源代碼的技術,因而會帶來維護問題。反射代碼比相應的直接代碼更復雜 。

二、枚舉

枚舉的主要用途是:將一組常量組織起來,在這之前表示一組常量通常使用定義常量的方式:

public static int final RED = 1;
public static int final GREEN = 2;
public static int final BLACK = 3;

但是常量舉例有不好的地方,例如:可能碰巧有個數(shù)字1,但是他有可能誤會為是RED,現(xiàn)在我們可以直接用枚舉來進行組織,這樣一來,就擁有了類型,枚舉類型。而不是普通的整形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;
        }
    }
}

輸出結果:

在這里插入圖片描述

優(yōu)點:將常量組織起來統(tǒng)一進行管理;

場景:錯誤狀態(tài)碼,消息類型,顏色的劃分,狀態(tài)機等等…

本質:是 java.lang.Enum 的子類,也就是說,自己寫的枚舉類,就算沒有顯示的繼承 Enum ,但是其默認繼承了這個類。

2.1 Enum 類的常用方法

方法名稱描述
values()以數(shù)組形式返回枚舉類型的所有成員
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(){
    }
}

2.2 枚舉的優(yōu)點和缺點

優(yōu)點

1.枚舉常量更簡單安全 。

2.枚舉具有內置方法 ,代碼更優(yōu)雅。

缺點

1.不可繼承,無法擴展。

  • 枚舉非常安全,不能通過反射,拿到實例對象。
  • 枚舉本身就是一個類,其構造方法默認為私有的,且都是默認繼承于 java.lang.Enum
  • 枚舉可以避免反射和序列化問題

三、Lambda 表達式

Lambda表達式是Java SE 8中一個重要的新特性。lambda表達式允許你通過表達式來代替功能接口。 lambda表達式就和方法一樣,它提供了一個正常的參數(shù)列表和一個使用這些參數(shù)的主體(body,可以是一個表達式或一個代碼塊)。 Lambda 表達式(Lambda expression)可以看作是一個匿名函數(shù),基于數(shù)學中的λ演算得名,也可稱為閉包Closure)。

3.1 Lambda表達式的語法及基本使用

基本語法(parameters) -> expression 或 (parameters) ->{ statements; }

Lambda表達式由三部分組成:

1.paramaters:類似方法中的形參列表,這里的參數(shù)是函數(shù)式接口里的參數(shù)。這里的參數(shù)類型可以明確的聲明也可不聲明而由JVM隱含的推斷。另外當只有一個推斷類型可以省略掉圓括號

2.->:可理解為“被用于”的意思

3.方法體:可以是表達式也可以代碼塊,是函數(shù)式接口里方法的實現(xiàn)。代碼塊可返回一個值或者什么都不反回,這里的代碼塊等同于方法的方法體。如果是表達式,也可以返回一個值或者什么都不返回。

// 1. 不需要參數(shù),返回值為 2
() -> 2
// 2. 接收一個參數(shù)(數(shù)字類型),返回其2倍的值
x -> 2 * x
// 3. 接受2個參數(shù)(數(shù)字),并返回他們的和
(x, y) -> x + y
// 4. 接收2個int型整數(shù),返回他們的乘積
(int x, int y) -> x * y
// 5. 接受一個 string 對象,并在控制臺打印,不返回任何值(看起來像是返回void)
(String s) -> System.out.print(s)

代碼示例:

package lambdaTest;
@FunctionalInterface
//函數(shù)式接口
interface NoParameterNoReturn {
    //注意:只能有一個方法
    void test();
}
//無返回值一個參數(shù)
@FunctionalInterface
interface OneParameterNoReturn {
    void test(int a);
}
//無返回值多個參數(shù)
@FunctionalInterface
interface MoreParameterNoReturn {
    void test(int a,int b);
}
//有返回值無參數(shù)
@FunctionalInterface
interface NoParameterReturn {
    int test();
}
//有返回值一個參數(shù)
@FunctionalInterface
interface OneParameterReturn {
    int test(int a);
}
//有返回值多參數(shù)
@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();
    }
}

3.2 函數(shù)式接口

函數(shù)式接口定義:一個接口有且只有一個抽象方法 。

注意:

1.如果一個接口只有一個抽象方法,那么該接口就是一個函數(shù)式接口。

2.如果我們在某個接口上聲明了 @FunctionalInterface 注解,那么編譯器就會按照函數(shù)式接口的定義來要求該接口,這樣如果有兩個抽象方法,程序編譯就會報錯的。所以,從某種意義上來說,只要你保證你的接口中只有一個抽象方法,你可以不加這個注解。加上就會自動進行檢測的。

代碼示例:

@FunctionalInterface
//函數(shù)式接口
interface NoParameterNoReturn {
    //注意:只能有一個方法
    void test();
}
public static void main1(String[] args) {
        NoParameterNoReturn noParameterNoReturn =  new NoParameterNoReturn(){
            public void test(){
                System.out.println("重寫方法");
            }
        };
        noParameterNoReturn.test();
    }
}

3.3 變量捕獲

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);//能捕獲到的變量,要么是常量,要么未發(fā)生改變過。
            }
        };
    }
}

Lambda表達式的優(yōu)點很明顯,在代碼層次上來說,使代碼變得非常的簡潔。缺點也很明顯,代碼不易讀。

優(yōu)點

代碼簡潔,開發(fā)迅速;方便函數(shù)式編程;非常容易進行并行計算;Java 引入 Lambda,改善了集合操作;

缺點

代碼可讀性變差;在非并行計算中,很多計算未必有傳統(tǒng)的 for 性能要高;不容易進行調試;

總結

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注腳本之家的更多內容!    

相關文章

  • Java 條件控制與循環(huán)控制實例

    Java 條件控制與循環(huán)控制實例

    下面小編就為大家?guī)硪黄狫ava 條件控制與循環(huán)控制實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • spring?batch線上異常定位記錄

    spring?batch線上異常定位記錄

    這篇文章主要為大家介紹了spring?batch線上異常定位記錄及異常解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪
    2022-03-03
  • 身份證號碼驗證算法深入研究和Java實現(xiàn)

    身份證號碼驗證算法深入研究和Java實現(xiàn)

    這篇文章主要介紹了身份證號碼驗證算法深入研究和Java實現(xiàn),本文講解了18身份證號碼的結構、根據(jù)17位數(shù)字本體碼獲取最后一位校驗碼程序實例等內容,需要的朋友可以參考下
    2015-06-06
  • RocketMQ4.5.2 修改mqnamesrv 和 mqbroker的日志路徑操作

    RocketMQ4.5.2 修改mqnamesrv 和 mqbroker的日志路徑操作

    這篇文章主要介紹了RocketMQ 4.5.2 修改mqnamesrv 和 mqbroker的日志路徑操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • SpringBoot如何通過配置禁用swagger

    SpringBoot如何通過配置禁用swagger

    這篇文章主要給大家介紹了關于SpringBoot如何通過配置禁用swagger的相關資料,Swagger用來在開發(fā)階段方便前后端分離的項目實戰(zhàn)中,提高前后端人員的工作效率,降低交流成本,但是版本上線之后要是把Swagger帶上去會存在很大的風險,需要的朋友可以參考下
    2023-08-08
  • 一篇文章帶你認識Java8接口的默認方法

    一篇文章帶你認識Java8接口的默認方法

    這篇文章主要給大家介紹了如何通過一篇文章帶你認識Java8接口的默認方法的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Java8具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-05-05
  • SpringBoot詳細講解通過自定義classloader加密保護class文件

    SpringBoot詳細講解通過自定義classloader加密保護class文件

    這篇文章主要介紹了SpringBoot通過自定義classloader加密class文件,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-04-04
  • Eclipse連接Mysql數(shù)據(jù)庫操作總結

    Eclipse連接Mysql數(shù)據(jù)庫操作總結

    這篇文章主要介紹了Eclipse連接Mysql數(shù)據(jù)庫操作總結的相關資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-08-08
  • Spring配置和使用Properties文件的詳細步驟

    Spring配置和使用Properties文件的詳細步驟

    在Spring框架中,.properties 文件通常用于存儲配置信息,如數(shù)據(jù)庫連接、服務地址、應用參數(shù)等,本文給大家介紹了Spring配置和使用Properties文件的詳細步驟,需要的朋友可以參考下
    2024-05-05
  • Java根據(jù)ip地址獲取歸屬地實例詳解

    Java根據(jù)ip地址獲取歸屬地實例詳解

    這篇文章主要為大家介紹了Java根據(jù)ip地址獲取歸屬地實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08

最新評論