JAVA 反射、枚举、 Lambda 表达式详解

目录

  • 反射
    • 反射相关的类
    • 反射机制的起源
    • Class类中的相关方法
      • 常用获得类相关的方法
        • 获取对象的3种方法
      • 常用获得类中属性相关的方法
      • 获得类中构造器相关的方法
      • 获得类中方法相关的方法
    • 反射的优缺点
      • 优点
      • 缺点
  • 枚举
    • Enum 类的常用方法
  • Lambda
    • 函数式接口
    • Lambda表达式的基本使用
    • Lambda在集合当中的使用
      • Collection接口
        • sort 方法
      • Map 接口
    • 总结
      • 优点
      • 缺点

反射

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

反射相关的类

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

反射机制的起源

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

  • 字节码文件所对应的对象就是Class对象(保存当前类型的信息)
  • 反射的根本就是从 Class 对象出发的

Class类中的相关方法

常用获得类相关的方法

方法 用途
getClassLoader() 获得类的加载器
getDeclaredClasses() 返回一个数组,数组中包含该类中所有类和接口类的对象(包括私有的)
forName(String className) 根据类名返回类的对象
newInstance() 创建类的实例
getName() 获得类的完整路径名字

获取对象的3种方法

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 ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        
        Class<?> c1 = Class.forName("text_0509.Student");

        Class<?> c2 = text_0509.Student.class;

        Student s = new Student();
        Class<?> c3 = s.getClass();

        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);
    }
}


//执行结果
Student()
class text_0509.Student
class text_0509.Student
class text_0509.Student

常用获得类中属性相关的方法

方法 用途
getField(String name) 获得某个公有的属性对象
getFields() 获得所有公有的属性对象
getDeclaredField(String name) 获得某个属性对象
getDeclaredFields() 获得所有属性对象

获得类中构造器相关的方法

方法 用途
getConstructor(Class… parameterTypes) 获得该类中与参数类型匹配的公有构造方法
getConstructors() 获得该类的所有公有构造方法
getDeclaredConstructor(Class… parameterTypes) 获得该类中与参数类型匹配的构造方法
getDeclaredConstructors() 获得该类所有构造方法

获得类中方法相关的方法

方法 用途
getMethod(String name, Class… parameterTypes) 获得该类某个公有的方法
getMethods() 获得该类所有公有的方法
getDeclaredMethod(String name, Class… parameterTypes) 获得该类某个方法
getDeclaredMethods() 获得该类所有方法

反射的优缺点

优点

  1. 对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法
  2. 增加程序的灵活性和扩展性,降低耦合性,提高自适应能力
  3. 反射已经运用在了很多流行框架如:Struts、Hibernate、Spring 等等

缺点

  1. 使用反射会有效率问题。会导致程序效率降低
  2. 反射技术绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂


枚举

枚举是在JDK1.5以后引入的。主要用途是:将一组常量组织起来,在这之前表示一组常量通常使用定义常量的方式

public static int final RED = 1;
public static int final GREEN = 2;
public static int final BLACK = 3;
优点
将常量组织起来统一进行管理
场景
错误状态码,消息类型,颜色的划分,状态机等等…
本质
是 java.lang.Enum 的子类,也就是说,自己写的枚举类,就算没有显示的继承 Enum ,但是其默认继承了这个类
枚举可以避免反射和序列化问题
public enum TextEnum {
    RED,GREEN,BLACK,WHITE;

    public static void main(String[] args) {
        TextEnum te = TextEnum.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("black");
                break;
            default:
                break;
        }
    }
}

//执行结果
black

Enum 类的常用方法

方法名称 描述
values() 以数组形式返回枚举类型的所有成员
ordinal() 获取枚举成员的索引位置
valueOf() 将普通字符串转换为枚举实例
compareTo() 比较两个枚举成员在定义时的顺序
public static void main(String[] args) {
        TextEnum[] testEnum = TextEnum.values();
        for (int i = 0; i < testEnum.length; i++) {
            System.out.println(testEnum[i] + " " + testEnum[i].ordinal());
        }
        System.out.println("=========================");
        System.out.println(TextEnum.valueOf("GREEN"));
    }

// 执行结果
RED 0
GREEN 1
BLACK 2
WHITE 3
=========================
GREEN
public enum TextEnum {
    RED("red",1),GREEN("green",2),BLACK("black",3),WHITE("white",4);

    public String name;
    public int ordinal;

    TextEnum(String name,int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
    }
}
优点
枚举常量更简单安全
枚举具有内置方法 ,代码更优雅
缺点
不可继承,无法扩展


Lambda

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

  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)

函数式接口

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

  1. 如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口
  2. 如果我们在某个接口上声明了 @FunctionalInterface 注解,那么编译器就会按照函数式接口的定义来要求该接口,这样如果有两个抽象方法,程序编译就会报错的。所以,从某种意义上来说,只要你保证你的接口中只有一个抽象方法,你可以不加这个注解。加上就会自动进行检测的
@FunctionalInterface
interface NoParameterNoReturn {
	//注意:只能有一个方法
	void test();
}


//这种也可以
@FunctionalInterface
interface NoParameterNoReturn {
	void test();
	default void test2() {
		System.out.println("JDK1.8新特性,default默认方法可以有具体的实现");
	}
}

Lambda表达式的基本使用

语法精简

  1. 参数类型可以省略,如果需要省略,每个参数的类型都要省略
  2. 参数的小括号里面只有一个参数,那么小括号可以省略
  3. 如果方法体当中只有一句代码,那么大括号可以省略
  4. 如果方法体中只有一条语句,其是return语句,那么大括号可以省略,且去掉return关键字
//无返回值无参数
@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 TestLambda {
    public static void main(String[] args) {
        NoParameterNoReturn noParameterNoReturn = ()->{
            System.out.println("无参数无返回值");
        };
        noParameterNoReturn.test();

        OneParameterNoReturn oneParameterNoReturn = (int a)->{
            System.out.println("无参数一个返回值:"+ a);
        };
        oneParameterNoReturn.test(10);
        
        MoreParameterNoReturn moreParameterNoReturn = (int a,int b)->{
            System.out.println("无返回值多个参数:"+a+" "+b);
        };
        moreParameterNoReturn.test(20,30);
    }

//执行结果
无参数无返回值
无参数一个返回值:10
无返回值多个参数:20 30

	public static void main(String[] args) {
        //有返回值无参数
        NoParameterReturn noParameterReturn = ()->{
            return 10;
        };
        //简写
        NoParameterReturn noParameterReturn2 = ()->10;
        System.out.println(noParameterReturn.test());
        System.out.println(noParameterReturn2.test());

        //有返回值一个参数
        OneParameterReturn oneParameterReturn = (int a)->{
            return a;
        };
        //简写
        OneParameterReturn oneParameterReturn1 = a->a;
        System.out.println(oneParameterReturn.test(20));
        System.out.println(oneParameterReturn1.test(20));

        //有返回值多参数
        MoreParameterReturn moreParameterReturn = (int a,int b)->{
            return a+b;
        };
        //简写
        MoreParameterReturn moreParameterReturn1 = (a,b)->a+b;
        System.out.println(moreParameterReturn.test(10, 20));
        System.out.println(moreParameterReturn1.test(10, 20));
    }

//执行结果
10
10
20
20
30
30
}

Lambda在集合当中的使用

对应的接口 新增的方法
Collection removeIf() spliterator() stream() parallelStream() forEach()
List replaceAll() sort()
Map getOrDefault() forEach() replaceAll() putIfAbsent() remove() replace()computeIfAbsent() computeIfPresent() compute() merge()

Collection接口

    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("Hello");
        list.add("bit");
        list.add("hello");
        list.add("lambda");

        list.forEach((String s)->{
            System.out.println(s);
        });
        System.out.println("===================");
        list.forEach(s-> System.out.println(s));
    }

//执行结果
Hello
bit
hello
lambda
===================
Hello
bit
hello
lambda

sort 方法

    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(20);
        list.add(10);
        list.add(30);
        list.add(50);

        list.sort(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        });
        list.sort((Integer o1,Integer o2)->{return o1.compareTo(o2);});
        list.sort((o1,o2)->o1.compareTo(o2));
        list.forEach(a-> System.out.println(a));
    }


//执行结果
10
20
30
50

Map 接口

    public static void main(String[] args) {
        HashMap<Integer, String> map = new HashMap<>();
        map.put(1, "hello");
        map.put(2, "bit");
        map.put(3, "hello");
        map.put(4, "lambda");
        map.forEach(new BiConsumer<Integer, String>(){
            @Override
            public void accept(Integer k, String v){
                System.out.println(k + "=" + v);
            }
        });
        System.out.println("=======================");
        map.forEach((Integer k,String v)->{
            System.out.println(k + "=" + v);
        });
        System.out.println("=======================");
        map.forEach((k,v)-> System.out.println(k + "=" + v));
    }


//执行结果
1=hello
2=bit
3=hello
4=lambda
=======================
1=hello
2=bit
3=hello
4=lambda
=======================
1=hello
2=bit
3=hello
4=lambda


总结

优点

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

缺点

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

你可能感兴趣的:(Java,java,反射,lambda,枚举类)