Java核心技术卷一第六章读书笔记

21 篇文章 1 订阅

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。且内部类对象只能在静态方法中构造
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值