大家好,欢迎来到IT知识分享网。
6.1 接口
- 接口:主要用来描述类具有什么功能,而并不需要给出每个功能的具体实现
- lambda表达式:一种可以在将来某个时间点执行的代码块的简介方法
- 在Java程序设计语言中,接口不是类,而是对类的一组需求描述,这些类要遵循接口描述的统一格式进行定义(例如,Arrays里的sort方法,如果要对不是数组的对象进行排序,就需要实现Comparable接口)
- 接口中的方法自动的设置为public,所以不需要提供关键字public,同时在实现接口方法时,需要将方法设置为public
- 接口不能含有实例域,现在的接口可以包含具体方法,但是需要设置为默认方法
- 为了让一个类实现接口,需要以下步骤(关键字:implement)
- 将类声明为实现给定的接口
- 对接口中所有的方法进行定义
- * Arrays.sort()方法使用了两种排序方法(快速排序和优化的归并排序):对于基本类型使用快速排序,对于对象类型,使用归并排序,因为快速排序不是稳定的,归并排序是稳定的
- 接口不是类,尤其不能使用new运算符实例化一个接口:
x = new Comparable()
然而,尽管不能构造接口的对象,却kennel声明接口的变量:
Comparable x;
接口变量必需引用实现类接口的类对象;
- 接口可以继承其他接口
- 与接口中方法自动的设置为public一样,接口中的域将被自动设置为public static final
- 尽管每一个类只能拥有一个超类,但可以实现多个接口。这就为实现类的行为提供类灵活性
- Java的设计者选择类不支持多继承,其主要原因是多继承会让语言变得非常复杂(C++),效率也会降低(Eiffel)
- 在Java SE8中,允许在接口中增加静态方法。理论上讲,没有任何理由认为这是不合法的。只是这有违于将接口作为抽象规范的初衷。通常的做法是将静态方法放在伴随类中。在标准库中,你会看到成对出现的接口和使用工具类,如Collections/Collection
- 默认方法
- 使用默认方法可以不用实现接口的一个方法,减少程序员的工作
- 实现与旧代码的兼容
- 默认方法冲突:
- 超类有限。如果超类提供了一个方法,同名且有相同参数类型的默认方法会被忽略。
- 接口冲突。这个时候必需处理冲突,在子类中决定调用哪个接口的方法。
person.super.getname()
6.2 接口示例
- 回调(callback)是一种常见的程序设计模式,可以指出某个特定事件发生时应该采取的动作
- 接口是实现回调非常好的一种方式,例如ActionLister接口
- clone方法是Object的一个protected方法。
- 对于每一个类,需要确定:
- 默认的clone方法是否满足要求
- 是否可以在可变的子对象上调用clone来修补默认的clone方法
- 是否不该使用clone
- 实现Cloneable接口。重新定义clone方法,并指定public访问修饰符
- Cloneable接口是Java提供的一组标记接口之一。建议在程序中不要使用标记接口。即使clone的默认(浅拷贝)可以满足要求,还是需要实现Cloneable接口,将clone重新定义为public,再调用super.clone
- 克隆没有想象中的那么常用,标准库里只有不到5%的类实现了clone
- 所有数组类型都有一个public的clone方法,而不是protected
6.3 lambda表达式
- 是一个难点,建议编写代码练习
- lambda表达式是一个可传递的代码块,可以在以后执行一次或多次(在Java中传递代码块并不容易,不能直接传递代码块。Java是一种面向对象语言,所以必需构造一个对象,这个对象的类需要有一个方法能包含所需要的代码)
- lambda表达式的语法:
- 参数,箭头(->)以及一个表达式。
(String first, String second) -> first.length() - second.length()
- 如果一句代码无法完成计算,放在{}中:
(String first, String second) -> { if(first.length() < second.length()) return -1; else return 0; }
- 即使lambda表达式没有参数,也需要提供空括号,就像无参数方法一样:
() -> {for(int i = 100;i >= 0;i--) System.out.println(i);}
- 如果可以推导出一个lambda表达式的参数类型,则可以忽略其类型
Comparator<String> comp = (first, second) -> first.length() - second.length()
- 如果方法只有一个参数,而且这个参数的类型可以推导出,那么还可以省略小括号:
ActionListener listener = event -> System.out.println("The time is " + new Date());
- 参数,箭头(->)以及一个表达式。
- 特别重要:lambda表达式是一个函数,可以赋值给一个只有一个抽象方法的函数式接口
- 对于只有一个抽象方法的接口,需要这种接口的对象爱心难过是,就可以提供一个lambda表达式。这种接口称作:函数式接口
- 最好把一个lambda表达式看作一个函数,而不是一个对象,另外要接受lambda表达式可以传递到函数接口
- 为此,Java设计者还是决定保持我们熟悉的接口概念,没有为Java语言增加函数类型
- 方法引用:(当已经有lambda表达式的函数时):
Timer t = new Timer(1000, System.out::println);
- 类似于lambda表达式,方法引用不能独立存在,总是会转化为函数式接口的实例
- 构造器引用于方法引用很相似,只不过方法名为new
Stream<Person> stream - names.stream().map(Person::new)
- 关于代码块以及自由变量值偶一个术语:闭包(closure)。如果有人吹嘘他们的语言有闭包,现在你也可以自信的说Java也有闭包。在Java中,lambda表达式就是闭包
- lambda表达式捕获的变量,必需是最终变量。只能引用值不会改变的变量。在lambda表达式中声明一个与局部变量同名的参数或局部变量是不合法的:
Path first = Paths.get("/usr/bin"); Comparator<String> comp = (first, second) -> first.length() - second.length(); //Error
- 处理lambda表达式:把一个函数式接口对象作为参数,要选择合适的函数式接口,也可以自己编写函数式接口
- 如果自己设计函数式接口,可以用@FunctionalInterface注解来标记这个接口
6.4 内部类
- 使用内部类的原因有一下三点:
- 内部类方法可以访问该类定义所在作用域的数据,包括私有的数据
- 内部类可以对同一个包中的其他类隐藏起来
- 当想要定一个毁掉函数且不想板鞋大量代码时,使用匿名(anonymous)内部类比较便捷
- 内部类既可以访问自身的数据域,也可以访问创建它的外围类的数据域
- 内部类的对象总有一个隐式引用,指向创建它的外部类的对象。这个引用在内部类中定义是不可见的。
- 只有内部类可以是私有类,而常规类只可以具有包可见性,或公有可见性
- 内部类中声明的所有静态域都必须是final
- 内部类不能有static方法
- 局部内部类:可以在一个方法里定义一个类,对外部世界完全隐藏起来
- 静态内部类:把一个类隐藏在另一个类的内部,不需要引用外围类的对象。只有内部类可以声明为static。且内部类对象只能在静态方法中构造
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/25838.html