Java学习笔记(四)
Contents
Java核心技术卷一基础知识第10版
#接口、lambda 表达式与内部类
#接口
- 接口中的所有方法自动地属于
public
,在接口中声明方法时不必提供关键字public
。 - 接口绝不能含有
实例域
。提供实例域和方法实现的任务应该由实现接口的那个类来完成。 - 为了让类实现一个接口,需要:
- 将类声明为实现给定的接口。
要将类声明为实现某个接口,需要使用关键字 implements。
1
class Employee implements Comparable
- 对接口中的所有方法进行定义。
- 将类声明为实现给定的接口。
- 如果存在这样一种通用算法,它能够对两个不同的子类对象进行比较,则应该在
超类
中提供一个compareTo
方法,并将这个方法声明为final
。 - 接口不是类,不能使用
new
运算符实例化一个接口,但是可以声明接口的变量,接口变量必须引用实现了接口的类对象。1
2
3x = new Comparable(...); // ERROR
Comparable x; // OK
x = new Employee(...); // OK provided Employee implements Comparable - 可以使用
instance
检查一个对象是否实现了某个特定的接口。1
if (anObject instanceof Comparable) {...}
- 接口中的域将被自动设为
public static final
。 - 在实现接口时,必须把方法声明为
public
,否则,编译器将认为这个方法的访问属性是包可见性,即类的默认访问属性,之后编译器就会给出试图提供更严格的访问权限的警告信息。 - 每个类可以实现多个接口。
- 可以为接口方法提供一个默认实现,必须用
default
修饰符标记这样一个方法。 - 默认方法的一个重要用法是
接口演化(interface evolution)
,保证不会对旧代码产生影响。 - 如果先在一个接口中将一个方法定义为默认方法,然后又在超类或另一个接口中定义了同样的方法,遵循如下规则:
- 超类优先。
如果超类提供了一个具体方法,同名而且有相同参数类型的默认方法会被忽略。 - 接口冲突。
如果一个超接口提供了一个默认方法,另一个接口提供了一个同名而且参数类型(不论是否是默认参数)相同的方法,必须覆盖这个方法来解决冲突。
- 超类优先。
接口与回调可能在这里不太看得懂,暂时跳过。[1]
#lambda 表达式
- lambda表达式就是一个代码块, 以及必须传入代码的变量规范。
1
2(String first, String second)
-> first.length() - second.length() - 如果代码要完成的计算无法放在一个表达式中,就可以像写方法一样,把这些代码放在
{}
中, 并包含显式的 return 语句。1
2
3
4
5
6(String first, String second) ->
{
if (first.length() < second.length()) return -1;
else if (first.length() > second.length()) return 1;
else return 0;
} - 即使 lambda 表达式没有参数,仍然要提供空括号,就像无参数方法一样。
1
() -> { for (int i = 100; i >= 0; i-- ) System.out.println(i); }
- 如果可以推导出一个 lambda 表达式的参数类型,则可以忽略其类型。
1
2
3Comparator<String> comp
= (first, second) // Same as (String first, String second)
-> first.length() - second.length(); - 如果方法只有一个参数,而且这个参数的类型可以推导得出,那么甚至还可以省略小括号。
- 无需指定 lambda 表达式的返回类型。lambda 表达式的返回类型总是会由上下文推导得出。
- 要用
::
操作符分隔方法名与对象或类名主要有3种情况:- object::instanceMethod
- Class::staticMethod
- Class::instanceMethod
- 无法构造泛型类型
T
的数组。(数组构造器引用对于克服这个限制很有用。)1
2Object[] people = stream.toArray(); // Object数组引用
Person[] people = stream.toArray(Person[]::new); // Person数组引用 - lambda 表达式中捕获的变量必须实际上是
最终变量(effectively final)
。 - lambda 表达式的体与嵌套块有相同的作用域。
- 在 lambda 表达式中声明与一个局部变量同名的参数或局部变量是不合法的。
1
2
3
4Path first = Paths.get("/usr/bin");
Comparator<String> comp =
(first, second) -> first.length() - second.length();
// Error: Variable first already defined - 在一个 lambda 表达式中使用
this
关键字时,是指创建这个 lambda 表达式的方法的this
参数。 - 使用 lambda 表达式的重点是
延迟执行(deferred execution)
。
#内部类
- 使用内部类的原因:
- 内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据。
- 内部类可以对同一个包中的其他类隐藏起来。
- 当想要定义一个回调函数且不想编写大量代码时,使用匿名(anonymous)内部类比较便捷。
- 使用外围类引用的正规语法为
OuterClass.this
。
好晕啊😭,看不懂。[2]
代理也待看[3]