zoukankan      html  css  js  c++  java
  • 《Java核心技术》第六章读书笔记(接口、lambda表达式和内部类)

    第六章 接口、lambda表达式和内部类

    接口

    • 接口中的方法自动的属于public,因此在接口声明的方法中,不必提供关键字public。

    • 接口绝不能含有实例域

    • 接口不是类,不能使用new运算符实例化一个接口

      x = new Compareble(...)  // Error
      
    • 尽管不能构造接口对象但是可以声明

      Compareble x // ok
      
    • 判断一个对象是否实现了特定接口 instanceof

      public interface Animal {
          void fly();
      }
      
      public class Bird implements Animal{
          @Override
          public void fly() {
              System.out.println("bird can fly");
          }
      }
      
          @Test
          public void test03(){
              Bird bird = new Bird();
              boolean b = bird instanceof Animal;
              System.out.println(b);
          }
      
    • 接口中不能包含实例域,但是可以包含常量,且自动设为public static final

    • 解决默认方法冲突

      • 超类优先,如果超类提供了一个具体方法,同名而且有相同类型的默认方法会被忽略
      • 接口冲突,如果一个超接口提供了一个默认方法,另一个提供了一个完全相同的方法,必须覆盖重写
    • Clone

      需要实现深拷贝的类要实现Cloneable接口,并且要重写clone方法
      数组中有一个public clone方法,可以建立一个新的深拷贝数组
      

    lambda表达式

    有三个部分:

    1. 一个代码块
    2. 参数
    3. 自由变量的值,这里指非参数而且不在代码中定义的变量

    lambda表达式中,只能引用值不会改变的变量

    以上就会报错。因为并发执行多个动作时就会不安全。

    另外如果在lambda表达式中引用变量,而这个变量可能在外部改变,这也是不合法的。

    注意:

    1. lambda表达式不火的变量必须实际上是最终变量,即这个变量初始化之后就不会再为他赋值。
    2. lambda表达式中不能有两个同名的局部变量

    内部类

    内部类既可以访问自身的数据域,也可以访问创建他的外围类对象的数据域,内部类的对象总有一个隐式引用,指向了外部类。

    内部类声明的所有静态域必须是final,我们希望一个静态域只有一个实例,不过对于每个外部对象,会分别有一个单独的内部类实例,如果不是final可能不唯一。

    局部内部类

    局部类不能用public或private进行生命,作用域被限定在声明这个局部类的块中。

    public class DemoTest{
    
    	 public void start() {
    
            class TimePrinter implements ActionListener {
                public void actionPerformed(ActionEvent event){
                    System.out.println("...");
                }
            }
            TimePrinter listener = new TimePrinter();
            Timer t = new Timer(interval,listener);
            t.start()
        }
    }
    
    

    局部内部类有一个优势,即对外部世界可以完全隐藏起来,除了start()方法,没有任何方法知道内部类的存在。

    局部类的方法只能饮用定义为final的局部变量,对他进行初始化后不能够在进行修改。因此,就是的局部变量与在局部类内简历的拷贝保持一致。

    匿名内部类

    匿名内部类既可以是接口,必须要去实现抽象方法,也可以是类,需要去扩展功能。

    双括号初始化,利用了内部类的语法,外层括号建立了一个ArrayList匿名子类,内层括号是一个对象的构造块

    代理

    利用代理可以在运行时创建一个实现了一组给定接口的新类。这种功能只有在编译时无法确定需要实现那个接口时,才有必要使用。

    何时使用代理

    使用场景:假设有一个表示接口的class对象,有可能只包含一个接口,他的确切类型在编译时无法知道,想要构造一个实现这些接口的类,但是不能实例化一个接口,需要在程序处于运行状态时定义一个新类。为了解决这个问题,代理类可以在运行时创建全新的类,这样的代理类能实现指定的接口。

    它具有指定接口所需要的全部方法。

    然而不能在运行时定义这些方法,需要提供一个调用处理器(invocation handler)。调用处理器是为了实现InvocationHandler接口的类对象,在这个接口中只有一个方法:

    Object invoke(Object proxy, Method method, Object[] args)
    

    无论何时调用代理对象的方法,调用处理器的invoke方法都会被调用,并向其传递Method对象和原始的调用参数。调用处理器必须给出处理调用的方式。

    创建代理对象

    要想创建一个代理对象,需要使用Proxy类的newProxyInstance方法,这个方法有三个参数

    1. 一个类加载器(class loader),作为java安全模型的一部分,对于系统类和从因特网上下载下来的类,可以使用不同的类加载器。
    2. 一个Class对象数组,每个元素都是需要实现的接口
    3. 一个调用处理器
    代理类的特性

    代理类是在程序运行过程中创建的,一旦被创建,就变成了常规类,与虚拟机中的任何其他类没有什么区别。

    所有的代理类都扩展于Proxy类,一个代理类只有一个实例域——调用处理器,它定义在Proxy超类中,为了履行代理对象的职责,所需要的任何附加数据都必须存储在调用处理器中。

    所有的代理类覆盖了Object类中的方法toString,equals,hashCode,如同所有的代理方法一样,这些方法仅仅调用了处理器的invoke,Object类中的其他方法,clone和getClass并没有被重新定义。

    对于特定的类加载器和预设的一组接口来说,只能有一个代理类,也就是说,如果同一个类加载器和接口数组调用两次newProxyInstance方法的话,那么只能得到同一个类的两个对象,一可以利用以下方法获取这个类。

    Class proxyClass = proxy.getProxyClass(null,interfaces);
    

    代理类一定是public和final,如果代理类实现的所有接口都是public,代理类就不属于某个特定的包,否则,所有非公有的接口都必须属于同一个包,同时,代理类也属于这个包。

  • 相关阅读:
    基于协同过滤的个性化Web推荐
    自动推荐系统效果为什么不好
    基于模糊聚类和协同过滤的混合推荐系统
    海量数据处理之蓄水池抽样算法
    心灵启发--不羡慕别人的生活
    ubuntu安装软件整理
    Hadoop系列
    网页返回错误编号含义整理
    找出单链表的中间位置指针
    【python爬虫】根据查询词爬取网站返回结果
  • 原文地址:https://www.cnblogs.com/jimmyhe/p/13835282.html
Copyright © 2011-2022 走看看