Interface
interface 的设计初衷是面向抽象,提高扩展性。这也留有一点遗憾,Interface 修改的时候,实现它的类也必须跟着改。
为了解决接口的修改与现有的实现不兼容的问题。新 interface 的方法可以用 default
或 static
修饰,这样就可以有方法体,实现类也不必重写此方法。
一个 interface 中可以有多个方法被它们修饰,这 2 个修饰符的区别主要也是普通方法和静态方法的区别。
- default修饰的方法,是普通实例方法,可以用this调用,可以被子类继承、重写。
- static修饰的方法,使用上和一般类静态方法一样。但它不能被子类继承,只能用Interface调用。
我们来看一个实际的例子。
public interface InterfaceNew {
static void sm() {
System.out.println("interface提供的方式实现");
}
static void sm2() {
System.out.println("interface提供的方式实现");
}
default void def() {
System.out.println("interface default方法");
}
default void def2() {
System.out.println("interface default2方法");
}
//须要实现类重写
void f();
}
public interface InterfaceNew1 {
default void def() {
System.out.println("InterfaceNew1 default方法");
}
}
如果有一个类既实现了 InterfaceNew 接口又实现了 InterfaceNew1接口,它们都有def(),并且 InterfaceNew 接口和 InterfaceNew1接口没有继承关系的话,这时就必须重写def()。不然的话,编译的时候就会报错。
public class InterfaceNewImpl implements InterfaceNew , InterfaceNew1{
public static void main(String[] args) {
InterfaceNewImpl interfaceNew = new InterfaceNewImpl();
interfaceNew.def();
}
@Override
public void def() {
InterfaceNew1.super.def();
}
@Override
public void f() {
}
}
在 Java 8 ,接口和抽象类有什么区别的?
很多小伙伴认为:“既然 interface 也可以有自己的方法实现,似乎和 abstract class 没多大区别了。”
其实它们还是有区别的
interface 和 class 的区别,好像是废话,主要有:
接口多实现,类单继承
接口的方法是 public abstract 修饰,变量是 public static final 修饰。 abstract class 可以用其他修饰符
interface 的方法是更像是一个扩展插件。而 abstract class 的方法是要继承的。
开始我们也提到,interface 新增default和static修饰的方法,为了解决接口的修改与现有的实现不兼容的问题,并不是为了要替代abstract class。在使用上,该用 abstract class 的地方还是要用 abstract class,不要因为 interface 的新特性而将之替换。
记住接口永远和类不一样。
functional interface 函数式接口
定义:也称 SAM 接口,即 Single Abstract Method interfaces,有且只有一个抽象方法,但可以有多个非抽象方法的接口。
在 java 8 中专门有一个包放函数式接口java.util.function,该包下的所有接口都有 @FunctionalInterface 注解,提供函数式编程。
在其他包中也有函数式接口,其中一些没有@FunctionalInterface 注解,但是只要符合函数式接口的定义就是函数式接口,与是否有
@FunctionalInterface注解无关,注解只是在编译时起到强制规范定义的作用。其在 Lambda 表达式中有广泛的应用。
Lambda 表达式
接下来谈众所周知的 Lambda 表达式。它是推动 Java 8 发布的最重要新特性。是继泛型(Generics)和注解(Annotation)以来最大的变化。
使用 Lambda 表达式可以使代码变的更加简洁紧凑。让 java 也能支持简单的函数式编程。
Lambda 表达式是一个匿名函数,java 8 允许把函数作为参数传递进方法中。
语法格式
(parameters) -> expression 或
(parameters) ->{ statements; }
Lambda 实战
我们用常用的实例来感受 Lambda 带来的便利
替代匿名内部类
过去给方法传动态参数的唯一方法是使用内部类。比如
1.Runnable 接口
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("The runable now is using!");
}
}).start();
//用lambda
new Thread(() -> System.out.println("It's a lambda function!")).start();
2.Comparator 接口
List
Collections.sort(strings, new Comparator
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;}
});
//Lambda
Collections.sort(strings, (Integer o1, Integer o2) -> o1 - o2);
//分解开
Comparator
Collections.sort(strings, comparator);
3.Listener 接口
JButton button = new JButton();
button.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
e.getItem();
}
});
//lambda
button.addItemListener(e -> e.getItem());
4.自定义接口
上面的 3 个例子是我们在开发过程中最常见的,从中也能体会到 Lambda 带来的便捷与清爽。它只保留实际用到的代码,把无用代码全部省略。那它对接口有没有要求呢?我们发现这些匿名内部类只重写了接口的一个方法,当然也只有一个方法须要重写。这就是我们上文提到的函数式接口,也就是说只要方法的参数是函数式接口都可以用 Lambda 表达式。
@FunctionalInterface
public interface Comparator
@FunctionalInterface
public interface Runnable{}
我们自定义一个函数式接口
@FunctionalInterface
public interface LambdaInterface {
void f();
}
//使用
public class LambdaClass {
public static void forEg() {
lambdaInterfaceDemo(()-> System.out.println("自定义函数式接口"));
}
//函数式接口参数
static void lambdaInterfaceDemo(LambdaInterface i){
i.f();
}
}
集合迭代
void lamndaFor() {
List
//传统foreach
for (String s : strings) {
System.out.println(s);
}
//Lambda foreach
strings.forEach((s) -> System.out.println(s));
//or
strings.forEach(System.out::println);
//map
Map<Integer, String> map = new HashMap<>();
map.forEach((k,v)->System.out.println(v));
}
方法的引用
Java 8 允许使用 :: 关键字来传递方法或者构造函数引用,无论如何,表达式返回的类型必须是 functional-interface。
public class LambdaClassSuper {
LambdaInterface sf(){
return null;
}
}
public class LambdaClass extends LambdaClassSuper {
public static LambdaInterface staticF() {
return null;
}
public LambdaInterface f() {
return null;
}
void show() {
//1.调用静态函数,返回类型必须是functional-interface
LambdaInterface t = LambdaClass::staticF;
//2.实例方法调用
LambdaClass lambdaClass = new LambdaClass();
LambdaInterface lambdaInterface = lambdaClass::f;
//3.超类上的方法调用
LambdaInterface superf = super::sf;
//4. 构造方法调用
LambdaInterface tt = LambdaClassSuper::new;
}
}
访问变量
int i = 0;
Collections.sort(strings, (Integer o1, Integer o2) -> o1 - i);
//i =3;
lambda 表达式可以引用外边变量,但是该变量默认拥有 final 属性,不能被修改,如果修改,编译时就报错。
Stream
标签:Java,void,接口,public,println,特性,interface,Java8,out From: https://www.cnblogs.com/DCFV/p/18347136