虽然java这么多年除了很多版,但我们项目开发实际上还是用的java8,等到下一个java稳定版有啥特性再来做一版学习总结。
一、接口的变化
1,接口规则
一个接口可以继承多个父接口,会有如下规则:
(1)子接口会得到父接口的一切,包括方法、类变量;
(2)如果两个接口有同名的变量,使用子接口去访问同名变量的时候,
会报错: 对<??>变量的引用不明确。
这时只能通过父接口名来调用变量
(3)如果多个父接口有相同的方法声明,不影响继承。
2,Java 8对接口的改变
(1)增加了default方法和static方法,这两种方法完全可以有方法体,所以如果有人说接口没有方法体,那他肯定不熟悉java 8;
(2)default方法属于实例,static方法属于类(接口)。也就是说default方法得有实例才能调用,static方法,有类就可以直接调用。
(3)接口里面的静态方法不会被继承,静态变量会被继承下来
(4)如果一个类实现了多个接口,并且这些接口互相之间没有继承关系,同时存在相同的默认方法会报错;不相关默认值
如果多个接口有继承关系,默认方法会被子接口覆盖。
(5)如果有多个实现(接口继承父接口也有同样问题),并且有相同的默认方法,则需指定访问那个方法
public void test2() {
TestInter.super.test2();
}
(6)如果一个接口只有一个抽象方法(包括继承的),该接口是一个函数式接口。
函数式接口 可以使用Lambda实现。
(7)如果接口里面使用@FunctionalInterface,则指定了必须是函数式接口(有且仅有一个抽象方法)
(8)子接口可以重写父接口的默认方法,重写为抽象方法。
总结:
(1)java8接口加入了静态方法和默认方法,方法前面使用static或者default方法,这种方法必须有方法体;
(2)如果一个接口只有一个抽象方法,默认自动变成函数式接口;
(3)如果使用了@FunctionalInterface对接口进行注解,该接口就只能只有一个抽象方法。
default和static测试:
package new_feature;
public interface TestInter {
static void test1() {
System.out.println("TestInter里的静态方法");
}
default void test2() {
System.out.println("TestInter里的默认方法");
}
}
interface TestInter1 /* extends TestInter */ {
static void test1() {
System.out.println("TestInter1里的静态方法");
}
default void test2() {
System.out.println("TestInter1里的默认方法");
}
}
class TestInterface implements TestInter, TestInter1 {
// 同时存在两个同名的default方法,则会报错,需要这样写
@Override
public void test2() {
TestInter.super.test2();
}
}
class MainClass {
public static void main(String[] args) {
// static方法不会被继承
// TestInterface.test1();
// 这样能够访问
TestInter.test1();
TestInter1.test1();
TestInterface testInterface = new TestInterface();
testInterface.test2();
}
}
函数式接口测试:
package new_feature;
//因为该接口只有一个抽象方法,默认就是函数式接口
interface TestFunctionInterface1 {
void test();
}
// 没有方法的接口是普通的接口,这种接口通常用于标记使用,比如Java的序列化
interface TestFunctionInterface2 {
}
// 加了这个接口就必须是函数式接口,有且仅有一个抽象方法
@FunctionalInterface
interface TestFunctionInterface3 {
void test1();
// void test2();
static void test3() {
}
}
public class TestFunctionalInterface {
}
二、Lambda表达式
函数式接口:之前讲过,只有一个抽象方法的接口。
注解:从Java5开始引入注解,对字节码文件进行一些说明
@FunctionalInterface注解的作用是用于在编译过程中告诉编译器该接口只能有一个抽象方法。
Lambda表达式只能针对函数式接口使用,以一个函数式接口为例:
@FunctionalInterface
interface UserTest {
void test();
}
采用内部类实现方法:
// 匿名内部类的实现方式,在Java8之前,没有Lambda表达式
UserTest ut = new UserTest() {
@Override
public void test() {
System.out.println("使用匿名内部类实现");
}
};
采用lambda表达式:
// ():表示参数列表,不需要指定参数的类型,会自动推断
// ->:连接符
// {}:表示方法体
UserTest ut1 = () -> {
System.out.println("使用Lambda表达式");
};
ut1.test();
在Lambda表达式中:
():表示参数列表,不需要指定参数的类型,会自动推断
->:连接符
{}:表示方法体
如果方法只有一行,则可以再进行简化:
// 如果只有一句还能简化:
// 如果有返回值,连return也可以省略
UserTest ut2 = () -> System.out.println("使用最简化的lambda表达式");
1,对于参数和返回值的处理
(1)接口方法有一个参数
// 接口方法有一个参数
@FunctionalInterface
interface UserTest1 {
void test(int i);
}
main方法中:
int i = 100;
// 圆括号内只需要指定参数的名称,不需要指定参数的类型
UserTest1 ut11 = (x) -> {
System.out.println("一个参数,一行代码输出参数的值:" + x);
};
ut11.test(i);
针对单一的参数,也可以写成这样:
// 如果参数列表里面,只有一个参数,可以省略圆括号
UserTest1 ut12 = x -> System.out.println("一个参数,省略圆括号一行代码输出参数的值:" + x);
;
ut12.test(i);
(2)接口方法有2个参数:
// 接口方法有两个参数
@FunctionalInterface
interface UserTest2 {
void test(int i, int j);
}
main方法中:
// 两个参数:
UserTest2 ut21 = (x, y) -> {
System.out.println("两个参数中x:" + x);
System.out.println("两个参数中y:" + y);
};
ut21.test(5, 4);
(3)一个参数,一个返回值
// 一个参数,一个返回值
@FunctionalInterface
interface UserTest3 {
int test(int i);
}
main方法中:
// 有返回值的情况
UserTest3 ut31 = b -> {
return b + 5;
};
System.out.println(ut31.test(4));
// 有返回值的情况,省略写法:
UserTest3 ut32 = b -> b + 5;
System.out.println(ut32.test(4));
当然有返回值时,当然尽量有括号和return关键字。
2,以方法引用作为参数进行调用
(1)引用实例方法
引用实例方法时,自动把调用方法时的参数,全部传给引用的方法,
@FunctionalInterface
interface MethedRed {
void test(String s);
}
main方法中:
// 使用方法的引用 :实例方法的引用
// System.out是一个实例
MethedRed r1 = System.out::println;
r1.test("222");
(2)引用类方法
@FunctionalInterface
interface MethedRed1 {
void test(int arr[]);
}
在main方法中:
// 类方法
MethedRed1 r2 = Arrays::sort;
int[] a = new int[] { 4, 52, 44, 13, 22 };
r2.test(a);
r.test(Arrays.toString(a));
(3)引用构造器
// 测试构造器引用
@FunctionalInterface
interface MethedRed2 {
String test(char[] cs);
}
main方法中:
// 引用构造器,根据函数式接口的方法名来推断引用哪个构造器
MethedRed2 r3 = String::new;
String ok = r3.test(new char[] { '啊', '付' });
System.out.println(ok);