1.接口🤨
Arrays类中的sort方法可以对对象数组进行排序,但对象所属的类必须实现Comparable接口
public interface Comparable<T> {
int compareTo(T other);
}
- 接口中的所有方法自动是public方法
- 接口中不能有实例字段,可以看成没有实例字段的抽象类
检查一个类是否实现了特定的接口:
if(anObject instanceof Comparable){...}
接口可以继承其他的接口,可以有常量:
public interface Powered extends Comparable{
double SPEED_LIMIT=95;
double milesPerGallon();
}
实现了Cloneable方法才可以使用clone创建副本(浅克隆)
jdk8之后允许在接口中加入静态方法
jdk9中接口中的方法可以是private,private方法可以是静态方法或实例方法,不过只能在接口本身使用
可以为接口提供一个默认方法:
//用于访问一个数据结构中的元素,实现迭代器就要提供hasNext和next方法
public interface Iterator<E>{
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
...
}
默认方法可以调用其他方法:
public interface Collection{
int size();
default boolean isEmpty(){
return size() == 0;
}
...
}
接口冲突:
interface Person{
default String getName(){return "";};
}
interface Named{
default String getName(){return getClass().getName();};
}
类同时继承两个接口是编译器会报错,解决(类优先规则):
class Studen implements Person,Named {
public String getName(){return Person.super.getName();}
}
对象克隆
要实现Cloneable接口,重写其中的clone方法
clone方法是protected的,要重写为public方法
浅克隆只是克隆出了一个引用对象,深克隆会从最低层的数据克隆出一份,改变原数据是引起的克隆数据变化也不一样
关于深浅克隆的更多实例介绍详见另一篇笔记(原型模式):
https://blog.csdn.net/m0_57538148/article/details/123723453?spm=1001.2014.3001.5502
2.lambda表达式🧐
函数式接口
只有一个抽象方法的接口(接口可以声明非抽象方法)
基本用法
new Thread(() -> {
System.out.println("");
});
var timer = new Timer(1000,event -> System.out.println(event));
方法引用
指示编译器生成一个函数式接口的实例,覆盖这个接口的抽象方法来调用给定的方法
直接把println方法传递到Timer构造器
var timer = new Timer(1000,System.out::println);
Arrays.sort(strings,String::compareToIgnoreCase);
总结:用::
运算符分隔方法名与对象或类名,主要分3种情况:
object::instanceMethod
//等价于向方法传递参数的lambda表达式
//System.out::println即x->System.out.println(x)
Class::instanceMethod
//第一个参数会变成方法的隐式参数,
//String::compareToIgnoreCase即(x,y)->x.compareToIgnoreCase(y)
Class::staticMethod
//所有参数都传递到静态方法
//Math::pow即(x,y)->Math.pow(x,y)
只有当lambad表达式的体只调用一个方法而不做其他操作时,才能把lambda表达式重写为方法引用
比如:s->s.length() == 0
不能使用方法引用
可以在方法引用中使用this参数,比如:this::equals
等价于x->this.equals(x)
使用super也是合法的:super::instanceMethod
使用this作为目标,会调用给定方法的超类版本
//每次定时器滴答时会执行super::greet方法
class Greeter{
public void greet(ActionEvent event){
System.out.println("Hello,the time is"+Instant.ofEpochMilli(event.getWhen()));
}
}
class RepeatedGreeter extends Greeter{
public void greet(ActionEvent event){
var timer = new Timer(1000,super::greet);
timer.start();
}
}
构造器引用
例如:Person::new
是Person构造器的一个引用
可以用数组类型建立构造器引用:int[] :: new
等价于x->new int[x]
无法构造泛型类型T的数组,表达式new T[n]
会产生错误,会自动改为new Object[n]
比如:Object[] people = stream.toArray()
解决:Person[] people = stream.toArray(Person[]::new)
toArray调用构造器来得到正确类型的数组,填充并返回这个数组
变量作用域
lambda表达式实现了闭包
- lambda表达式中捕获的值必须是
事实最终变量
,这个变量初始化之后不能再赋值\更改,包括外部 - lambda表达式的体与嵌套块有相同的作用域,在表达式中不能有同名的局部变量
- 使用this时用法并没有特殊之处
不合法举例:
//只能引用值不会改变的变量
pulic static void countDown(int start,int delay){
ActionListener listener = event ->{
start--;
};
new Timer(delay,listener).start(); //此时并发执行多个动作不安全
}
//引用另一个变量
pulic static void countDown(String text,int count){
for(int i=1;i<=count;i++){
ActionListener listener = event ->{
System.out.println(i+":"+text); //捕获的值i不能改变
};
}
new Timer(delay,listener).start();
}
处理lambda表达式
特点
延迟执行
- 在一个单独的线程中运行代码
- 多次运行代码
- 在算法的适当位置执行代码(排序中的比较操作)
- 发生某种情况时执行代码(点击按钮\数据到达等)
🧱后续待更。。。