反射&枚举&以及lambda表达式

反射,Java代码中,让一个对象,认识到自己,也叫做"自省"自己清楚的认识自己

谁是最认识对象的??程序员

程序员是非常清楚,某个对象是属于哪个类的

这个对象里面有哪些属性(属性的名字,类型,private/public,其他的修饰符注解之类的)

这个对象里有哪些方法(方法的名字,参数列表,private/public)

这个类的父类是谁

这个类实现了接口有哪些

这些东西程序员只需要看看代码,就知道这些事情了

程序运行的过程中,某个对象也能获取到上述的信息

Java / JVM 提供了一组 API 拿到指定对象的上述信息

反射有什么用呢?

反射这个东西在世界开发中是要"慎用"的,双刃剑 / 非常规编程手段(不是很推荐使用的),正常的进门,拿钥匙进门,非正常情况,通过开锁师傅

反射,理解即可

Class stringClass = Class.forName("java.lang.String");
Class stringClass

 这个类对象就代表了"String"这个类,进一步的就能拿到这个类的各种信息,甚至还能创建这个类的实例

String s = "";

这种写法下,你创建的对象一定是 String 类型的,这件事是在程序员代码写完了就确定了("静态") 

//通过反射,获取到 String 这个类的 Class 对象
Class stringclass = Class.forName("java.lang.String");
Object obj = stringClass.newInstance();
String str = (String) obj;
System.out.println(str);

完全可以让用户输入,这个东西,可能来自于代码事先写好的,也可能 来自用户在控制台输入,还可能从文件读取,还可能通过一系列计数得出来的,还可能从网络读取的,程序跑起来之后/过程中获取到的"动态"

 为了获取"动态"付出的代价很明显的,代码更复杂了,动态的收益是啥呢? => 代码的"通用性",写一份代码,支持各种不同的情况

class Student {
    private int id;
    private String name;
}
Student s = new Student(1,"小李");
class Animal {
    private int animalld;
    private String animalName;
    private int age;
}
Animal cat = new Animal(2,"大黄",4);

反射可以知道这个类中有哪些属性(名字),此时,就可以比较容易的通过一套代码,就能够兼容多种不同类型的类,只要告诉我这个类的 Class 对象是什么,按照 Class 对象里面该类的属性名,就可以知道这个字符串如何解析,如何构造还原出一个一样的对象出来 

由于两个类不同,序列化得到的字符串的结构不同,后续进行反序列化,规则也是不同的,有了反射之后,就可以大幅度降低上述序列化实现的成本

Class.forName(className);

拿到类对象

stringClass.newInstance();

根据类对象创建实例 

通过反射,随意的访问某个对象中的任意属性,无论是 private

枚举,本身表示的含义"可以列举的概念"

这个部分也是可以通过"整数"或者其他的方案,来代替枚举的

表示性别

约定

1 => 表示男性  0 => 表示女性

但是用整数表示 性别 ,只是权宜之计,性别概念,本身就和 整数 没有任何关系的

当不小心把枚举误用了,进行一些不应该的计算的时候,编译器直接报销

enum 可以认为是特殊的 class 其实在枚举中,也是可以定义属性

虽然枚举和类很相似,但是还是有很明显的差别的

类可以随意的在外面创建实例,枚举不行,枚举项的创建必须在 枚举内部进行(构造方法一定是私有的)

枚举能支持额外的属性和方法

反射可以拿到类的私有的属性/方法

枚举的构造方法也是私有的

能否通过反射,拿到枚举的私有的构造方法,然后在再外面进行枚举,创建出新的枚举项??

这个是不能的(JVM)源代码

层次上做出了限制,这种做法本身就是故意找茬,没有实际价值的做法,java的反射 api 实现中,针对枚举这个特殊情况特殊处理

lambad 表达式

很多编程语言中,支持一个语法,匿名函数(没有名字的函数),这样的函数用一次就可以丢了,开发中非常常用的,通常作为"回调函数"的时候使用.

Java 看见别人有匿名函数,Java自己也想有,但是 Java 有一个问题 Java 的方法不能脱离实际类

Java 采取了曲线救国的方式,引入概念"函数式接口" functional interface, 如果这个接口,里面只有一个抽象方法,就可以称为函数式接口

基于函数式接口 => 引申出"匿名函数" => lambad 表达式

PriorityQueue queue = new PriorityQueue(o1, o2) -> (o1.id - o2.id);

圆括号表示形参列表.形参的参数类型是可以省略的

"->" 这个是 lambda 的关键标志,看到这个箭头,就知道这是 lambda, 省略 

"(o1.id - o2.id)"是 lambda的函数的函数体{}

如果 lambda 里面只有一句 return 代码,此时{}可以省略,return 也可以省略

函数式接口 (lambda 表达式的本体)

@FunctionalInterface
interface MyFuncInterface {
    void print(String s);
}

加上注解,进一步强调这个 interface 是函数式接口,万一后续代码写错了,不小心多写了一个方法,编译器可以报错 

实际开发中,及时需要使用 lambda 也很少去写函数式接口,如果写了一个方法,产生需要接受一个 lambda 的时候,使用函数式接口

public static void main(String[] args) {
    MypriorityQueue queue = new MyPriorityQueue((s1, s2) -> s1.compareTO(s2));
}
class  MypriorityQueue {
    
    public MyPriorityQueue(MyPriorityQueueComparator comparator) {
    
    }
}

想要把 lambda 作为另一个方法的实参,就要求该方法的形参是一个函数式接口

MyFuncInterface myFuncInterface = (s) -> System.out.println(s);

把函数赋值给另一个变量,把函数作为另一个函数的参数,把函数作为另一个函数的返回值,函数是"一等公民",这样的特点,"函数式编程语言"非常核心的语法特性

函数式编程语言,广泛使用函数递归,实现逻辑

比如 erlang

1.没有变量 => 常量(原子)

2.没有条件 => 模式匹配(进阶的 Switch case)

3.没有循环 => 递归

大数据开发,用函数式编程更多一点,其他场景见到的都比较少

lambda 表达式的语法精简

1.参数类型可以省略,如果需要,每个参数的类型都要省略

2.参数的小括号里面只有一个参数,那么小括号可以省略

3.如果方法体中只有一个句代码,那么大括号可以省略

4.如果方法体中只有一条语句,且是 return 语句,那么大括号可以省略,且去掉 return 关键字

lambda 的变量捕获

lambda 表达式能够捕获外部的变量,在内部使用

int num = 10000;

MyFuncInterface2 myFuncInterface2 = (String s, int i) -> {
    System.out.println(num);
};

lambda 的执行时机可能是未来的某个时候,执行 lambda 的时候可能这个变量 num 已经销毁了

 

MyFuncInterface2 myFuncInterface2;
{
    int num = 10000;
    myFuncInterface2 = (String s, int i) -> {
        System.out.println(num);
    };
}
myFuncInterface2.print("Hello","world",100);

 上面的两个 num 值是相同的,地址是不同的, lambda 捕获的 num 其实是外部 num 的一份拷贝,还有就是这个打印语句不是立即执行的

lambda 表达式能够使用捕获的变量,奥秘其实是,在定义拉满bda的时候就把这样的被捕获的变量,在lambda 内部偷偷的拷贝了一份.

既然是拷贝,万一这个变量在捕获之后,做出修改呢?

int num = 10000;
myFuncInterface2 = (String s, int i) -> {
    System.out.println(num);
};
num = 20000;

一旦允许修改,意味着捕获到的值和外部的值,就可能存在差异,就会导致代码的含义出现歧义 ,Java为了避免上述的问题,是不允许修改的

变量捕获只能针对 final 修饰的/虽然不是 final 修饰没有进行任何实际修改的

你可能感兴趣的:(java,开发语言)