添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
英俊的海龟  ·  【RCE | ...·  1 年前    · 
聪明伶俐的枇杷  ·  lua 随机数 ...·  1 年前    · 
首页 > 软件编程 > java > Java的反射,枚举及lambda表达式

Java中的反射,枚举及lambda表达式的使用详解

作者:来学习的小张

这篇文章主要为大家详细介绍了Java的反射,枚举及lambda表达式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

1.1 定义

Java的反射( reflection )机制是在 运行状态 中, 对于任意一个类,都能够知道这个类的所有属性和方法 ;对于 任意一个对象 都能够调用它的任意方法和属性 ,既然能拿到,那么我们就可以修改部分类型信息;这种 动态获取信息以及动态调用对象方法的功能称为java语言的反射( reflection )机制

1.2 用途

1、在日常的第三方应用开发过程中,经常会遇到某个类的 某个成员变量、方法或是属性是私有的 或是 只对系统应用开放 ,这时候就可以 利用Java的反射机制通过反射来获取所需的私有成员或是方法

2、反射 最重要的用途 就是 开发各种通用框架 ,比如在 spring 中,我们将所有的类 Bean 交给 spring 容器管理,无论是 XML 配置 Bean 还是注解配置,当我们从容器中获取 Bean 来依赖注入时,容器会读取配置,而配置中给的就是类的信息, spring 根据这些信息,需要创建哪些 Bean spring 就动态的创建这些类。

1.3 反射基本信息

Java程序中许多对象在运行时会出现 两种类型 运行时类型(RTTI)和编译时类型 ,例如 Person p = newStudent(); 这句代码中 p 在编译时类型为 Person ,运行时类型为 Student 。程序需要在运行时发现对象和类的真实信息。而 通过使用反射程序就能判断出该对象和类属于哪些类

1.4 与反射相关的类

类名 用途
Class类 代表类的实体,在运行的Java应用程序中表示类和接口
Field类 代表类的成员变量/类的属性
Method类 代表类的方法
Constructor类 代表了类的构造方法

1.5 Class类(反射机制的起源 )

Class代表类的实体,在运行的Java应用程序中表示类和接口 .

Java 文件被编译后,生成了 .class 文件, JVM 此时就要去解读 .class 文件 ,被编译后的 Java 文件 .class 也被 JVM 解析为一个对象,这个对象就是 java.lang.Class .这样当程序在运行时,每个类文件就最终变成了 Class 类对象的一个实例。我们通过 Java 的反射机制应用到这个实例,就可以去获得甚至去添加改变这个类的属性和动作,使得这个类成为一个动态的类 .

1.6 Class类中的相关方法

常用获得类相关的方法:

方法 用途
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() 获得该类中所以构造方法

1.7 获得Class对象的三种方式

在反射之前,我们需要做的第一步就是先拿到当前需要反射的类的 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();

输出结果:

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");
           //创建类的实例
           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.9 反射优点和缺点

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 ,但是其默认继承了这个类。

2.1 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(){

2.2 枚举的优点和缺点

1.枚举常量更简单安全 。

2.枚举具有内置方法 ,代码更优雅。

1.不可继承,无法扩展。

  • 枚举非常安全,不能通过反射,拿到实例对象。
  • 枚举本身就是一个类,其构造方法默认为私有的,且都是默认继承于 java.lang.Enum
  • 枚举可以避免反射和序列化问题

三、Lambda 表达式

Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。 lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。 Lambda 表达式(Lambda expression)可以看作是一个匿名函数,基于数学中的λ演算得名,也可称为闭包Closure)。

3.1 Lambda表达式的语法及基本使用

基本语法(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();

3.2 函数式接口

函数式接口定义:一个接口有且只有一个抽象方法 。

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();

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);//能捕获到的变量,要么是常量,要么未发生改变过。

Lambda表达式的优点很明显,在代码层次上来说,使代码变得非常的简洁。缺点也很明显,代码不易读。

代码简洁,开发迅速;方便函数式编程;非常容易进行并行计算;Java 引入 Lambda,改善了集合操作;

代码可读性变差;在非并行计算中,很多计算未必有传统的 for 性能要高;不容易进行调试;

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!    

您可能感兴趣的文章:
  • Java SpringBoot实现文件上传功能的示例代码
    Java SpringBoot实现文件上传功能的示例代码
    2022-03-03
  • 使用Mybatis接收Integer参数的问题
    使用Mybatis接收Integer参数的问题
    2022-03-03
  • 使用JPA+querydsl如何实现多条件动态查询
    使用JPA+querydsl如何实现多条件动态查询
    2022-03-03
  • Springboot整合Swagger3全注解配置(springdoc-openapi-ui)
    Springboot整合Swagger3全注解配置(springdoc-openapi-ui)
    2022-03-03
  • 一起来了解Java的Lambda表达式
    一起来了解Java的Lambda表达式
    2022-03-03
  • Java实战之晚会抽奖系统的实现
    Java实战之晚会抽奖系统的实现
    2022-03-03
  • Java 精炼解读数据结构的链表的概念与实现
    Java 精炼解读数据结构的链表的概念与实现
    2022-03-03
  • 浅谈String类型如何转换为time类型存进数据库
    浅谈String类型如何转换为time类型存进数据库
    2022-03-03
  • 美国设下计谋,用娘炮文化重塑日本,已影响至中国
    美国设下计谋,用娘炮文化重塑日本,已影响至中国
    2021-11-19
  • 时空伴随者是什么意思?时空伴随者介绍
    时空伴随者是什么意思?时空伴随者介绍
    2021-11-09
  • 工信部称网盘企业免费用户最低速率应满足基本下载需求,天翼云盘回应:坚决支持,始终
    工信部称网盘企业免费用户最低速率应满足基本下载需求,天翼云盘回应:坚决支持,始终
    2021-11-05
  • 2022年放假安排出炉:五一连休5天 2022年所有节日一览表
    2022年放假安排出炉:五一连休5天 2022年所有节日一览表
    2021-10-26
  • 电脑版 - 返回首页

    2006-2023 脚本之家 JB51.Net , All Rights Reserved.
    苏ICP备14036222号