| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> 学习笔记(JavaSE入门)——第5章·接口、lambda表达式与内部类 -> 正文阅读 |
|
[Java知识库]学习笔记(JavaSE入门)——第5章·接口、lambda表达式与内部类 |
第5章 ?接口、lambda表达式与内部类5.1 ?接口5.1.1 接口的基础语法1)接口我们可以看作是抽象类的一种特殊情况,在接口中只能定义抽象的方法和常量。 2)接口是一种“引用数据类型”,编译之后也是一个class字节码文件。 3)接口怎么定义:[修饰符列表] interface 接口名{}。 4)接口支持多继承,一个接口可以继承多个接口。接口之间可以继承,但接口之间不能实现。 5)接口中只有常量+抽象方法。其所有元素都是public修饰的。 6) 接口中的方法默认都是 public abstract 的,不能更改,但可以省略。 7) 接口中的变量默认都是 public static final 类型的,不能更改(可省略),所以必须显式的初始化。 8) 接口不能被实例化,接口中没有构造函数的概念,接口中方法不能有方法体(JDK8中可以有方法体)。 9) 接口中的方法只能通过类来实现,通过implements 关键字。 10) 如果一个类实现了接口,那么接口中所有的方法必须实现。 11) 一类可以实现多个接口,用逗号隔开。 12)extends和implements可以共存,extends在前,implements在后。 13)使用接口,写代码的时候,可以使用多态(父类型引用指向子类型对象)。 5.1.2 接口在开发中作用例如,Arrays类中的sort方法承诺可以对对象数组进行排序,但要求满足下面这个条件:对象所属的类必须实现Comparable接口。下面是Comparable接口的代码:
这说明,任何实现Comparable接口的类都需要包含compareTo方法,这个方法有一个Object参数,并且返回一个整数。假设希望根据员工的薪水进行比较,以下是compareTo方法的实现:
要让一个类使用排序服务必须让他实现compareTo方法。这是理所当然的,因为要向sort方法提供对象的比较方法。但是为什么不能再Employee类中直接提供一个compareTo方法,而必须实现Comparable接口呢? 主要原因在于Java程序设计语言是一种强类型语言。在调用方法的时候,编译器要能检查这个方法确实存在。 注意:Comparable接口的文档建议compareTo方法应该与equals方法兼容。也就是说,当x.equals(y)时x.compareTo(y)就应该等于0。JavaAPI中大多数实现Comparable接口的类都遵从了这个建议。不过又一个重要的例外,就是BigDecimal。 在Java中接口其实描述了类需要做的事情,类需要做的事情,类要遵循接口的定义来做事,使用接口到底有什么本质的好处?可以归纳为两点:
5.1.3 接口和抽象类的区别
5.1.4 静态和私有方法(了解)在Java8中,允许在接口中增加静态方法。在标准库中,会看到成对出现的接口和实用工具类,如Collection/Collections。在Java9中,接口中的方法可以是private。private方法可以是静态方法或实例方法。由于私有方法只能在接口本身的方法中使用,所以它们的用法很有限,只能作为接口中其他方法的辅助方法。 5.1.5 接口的属性如同使用instanceof检查一个对象是否属于某个特定类一样,也可以使用instanceof检查一个对象是否实现了某个特定的接口。接口不是类。具体来说,不能使用new运算符实例化一个接口。不过,尽管不能构造接口的对象,却能声明接口的变量:
接下来,如果使用instanceof检查一个对象是否属于某个特定类一样,也可以使用instanceof检查一个对象是否实现了某个特定的接口:
与建立类的继承层次一样,也可以扩展接口。这里允许有多条接口链,从通用性较高的接口扩展到专用性较高的接口。 5.1.7 Comparator接口假设我们希望按长度递增的顺序对字符串进行排序,而不是按字典顺序进行排序。肯定不能让String类用两种不同的方式实现compareTo方法。要处理这种情况,Arrays.sort方法还有第二个版本,有一个数组和一个比较器(comparator)作为参数,比较器是实现了Comparator接口的类的实例。
要按长度比较字符串,可以如下定义一个实现Comparator<String>的类:
具体完成比较时,需要建立一个实例:
将这个调用与word[i].compareTo(words[j])进行比较。这个compare方法要在比较器对象上调用,而不是在字符串本身上调用。要对一个数组排序,需要为Arrays.sort方法传入一个LengthComparator对象:
现在这个数组可能是[“Paul”,”Mary”,”Peter”]或[“Mary”,”Paul”,”Peter”]。 5.2 ?lambda表达式5.2.1 为什么引入lambda表达式lambda表达式是一个可传递的代码块,可以在以后执行一次或多次。在Java中传递一个代码段并不容易,不能直接传递代码段。Java是一种面对对象语言,所以必须构造一个对象,这个对象的类需要又一个方法包含所需要的代码。就像下面的代码一样:
这是经典OOP的实现样式。下面我们对上面的代码做一个修改,创建一个功能接口,并对该接口定义抽象方法。
而lambda它将函数式编程概念引入Java,函数式编程的好处在于可以帮助我们节省大量的代码,非常方便易用,能够大幅度的提高我们的编码效率。 至此我们都尚未使用lambda表达式。我们仅创建了Printer接口的具体实现,并将其传递给printSomething方法。 首先我们知道lambda表达式,表达的是接口函数,箭头左侧是函数的逗号分隔的形式参数列表,箭头右侧是函数体代码。现在,我们使用lambda表达式重构下之前的代码。
lambda表达式使我们代码更简洁。对比传统java代码的实现方式,代码量减少了很多。但这仍然不是最简的实现方式,我们一步一步来。
即使没有在箭头的左侧指定参数的类型,编译器也会从接口方法的形式参数中推断出其类型。那么,我们最终通过lambda表达式,简化完成的代码:
lambda表达式表达的是接口函数,箭头左侧是函数参数,箭头右侧是函数体。函数的参数类型和返回值类型都可以省略,程序会根据接口定义的上下文自动确定数据类型。 (param1,param2,param3 ...,paramN)- > { //代码块; } 语法格式一:无参数,无返回值 () -> System.out.println(“Hello Lambda!”); 语法格式二:有一个参数,无返回值 (x) -> System.out.println(x); 语法格式三:若只有一个参数,小括号可以省略不写 x -> System.out.println(“Hello Lambda!”); 语法格式四:有两个以上的参数,有返回值,并且Lambda体中有多条语句 Comparator<Integer> com = (x,y) -> { System.out.println(“函数式接口”); return } 语法格式五:若Lambda体中只有一条语句,return和大括号都可以省略不写 Comparator<Integer> com = (x,y) -> Integer.compare(x,y); 语法格式六:lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器可以通过上下文推断出数据类型,即“类型推断”。 Comparator<Integer> com = (Integer x, Integer y) -> Integer.compare(x,y); ?5.2.2 内置的四大核心函数式接口1.Consumer<T>消费型接口:void accept<T t>;
2.Supplier<T>供给型接口:T get();
3.Function<T, R>函数型接口:R apply(T r);
4.Predicate<T>判断型接口:boolean test(T t);
5.2.4 变量作用域①在lambda表达式中,只能引用值不会改变的变量。如果在lambda表达式中更改变变量,并发执行多个动作时就会不安全。 ②如果在lambda表达式中引用一个变量。而这个变量可能在外部改变,这也是不合法的。 ③lambda表达式中捕获的变量必须实际上是事实最终变量(effectively final)。 ④lambda表达式的体与嵌套块有相同的作用域。这里同样适用明明冲突和遮蔽的有关规则。在lambda表达式中声明一个局部变量同名的参数或者局部变量是不合法的。 ⑤在一个lambda表达式中使用this关键字时,是指创建这个lambda表达式的方法的this参数。 5.2.5 ComparatorComparator接口包含很多方便的静态方法来创建比较器。这些方法可以用于lambda表达式或方法引用。 静态comparing方法提取一个“键提取器”函数,他将类型T映射为一个可比较的类型(如String)。对要比较的对象应用这个函数,然后对返回的键完成比较。例如,假设有一个Person对象数组,可以如下按名字对这些对象进行排序:
与手动实现一个Comparator相比,这当然要容易得多。另外,代码也更为清晰。可以把比较器与thenComparing方法串起来,来处理比较结果相同的情况。例如:
如果两人的姓相同,就会使用第二个比较器。这些方法有很多变体形式,可以为comparing和thenComparing方法提取的键指定一个比较器。例如,可以如下根据人名长度完成排序:
5.3 ?内部类在一个类的内部定义的类,称为内部类,主要分类:①实例内部类;②局部内部类;③静态内部类。 为什么需要使用内部类呢?主要有两个原因:
内部类原先对于简洁地实现回调非常重要,不过如今lambda表达式在这方面可以做得更好。但内部类对于构建代码还是很有用的。使用内部类编写的代码,可读性很差。能不用尽量不用。 5.3.1 实例内部类
5.3.4 静态内部类
5.3.5 局部内部类局部内部类是在方法中定义的,它只能在当前方法中使用,和局部变量的作用一样。局部内部类和实例内部类一致,不能包含静态成员。
5.3.6 匿名内部类使用局部内部类时,通常还可以再进一步。假设只想创建这个类的一个对象,甚至不需要为类指定名字。这样一个类被称为匿名内部类(anonymous inner class)。
一般地,语法如下: new SuperType(construction parameters){ inner class methods and data } 其中,SuperType可以是接口,如ActionListener,如果是这样,内部类就要实现这个接口。SuperType也可以是一个类,如果是这样,内部类就要扩展这个类。 由于构造器的名字必须与类名相同,而匿名内部类没有类名,所以,匿名内部类不能有构造器。实际上,构造参数要传递给超类构造器。具体地,只要内部类实现一个接口,就不能有任何构造参数。不过,仍然要提供一组小括号。尽管匿名内部类不能有构造器,但可以提供一个对象初始化块。 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/17 20:47:06- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |