zoukankan      html  css  js  c++  java
  • 第6章 接口与内部类

    接口

    对象克隆

    接口与回调

    内部类

    代理

    6.1 接口

    在Java程序设计语言中,接口不是类,而是对类的一组需求描述,这些类要遵从接口描述的统一格式进行定义。

    接口使用interface关键字声明。

    要将类声明为实现某个接口,需要使用关键字implements。

    6.1.1 接口的特性

    • 接口不能使用new运算符实例化。
    • 可以使用instanceof检查一个对象是否实现了某个特定的接口。
    • 接口可以被扩展,接口扩展接口使用extends关键字。
    • 接口中的所有方法自动地属于public。
    • 接口中不能包含实例域或静态方法,但却可以包含常量,接口中的域将被自动设为public static final。
    • 每个类能够拥有一个超类,但却可以实现多个接口。

    6.1.2 接口与抽象类

    java中不存在多继承。

    6.2 对象克隆

    对于每个类,都需要做出下列判断:

    • 默认的clone方法是否满足要求
    • 默认的clone方法是否能够通过调用可变子对象的clone得到修补。
    • 是否不应该使用clone.

    实际上,选项3是默认的。如果要选择1或2,类必须:

    • 实现Cloneable接口。
    • 使用public 访问修饰符重新定义clone方法。

    6.3 接口与回调

    回调(callback)是一种常见的程序设计模式。在这种模式中,可以指出某个特定事件发生时应该采取的动作。

    6.4 内部类

    内部类(inner class)是定义在另一个类中的类。使用内部类的主要原因有以下三点:

    内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据。

    内部类可以对同一个包中的其他类隐藏起来。

    当想要定义一个回调函数且不想编写大量代码是,使用匿名(anonymous)内部类比较便捷。

    6.4.1 使用内部类访问对象状态

    内部类既可以访问自身的数据域,也可以访问创建它的外围对象的数据域。

    6.4.2 内部类的特殊语法规则

    内部类使用外围类引用的语法OuterClass.this

    在外围类的作用域之外,可以这样引用内部类OuterClass.InnerClass

    6.4.3 内部类是否又用、必要和安全

    内部类是一种编译器现象,与虚拟机无关。编译器将会把内部类翻译成用$分隔外部类名与内部类名的常规类文件,而虚拟机则对此一无所知。

    6.4.4 局部内部类

       

    public void start(){

    class TimePrinter implements ActionListener{

    public void actionPerformed(ActionEvent event){

     

    }

    }

    ActionListener listener = new TimePrinter();

    Timer t = new Timer(interval,listener);

    t.start();

    }

     

    局部类有一个优势,即对外部世界可以完全地隐藏起来。除了声明它的方法之外,没有任何方法知道它的存在。

    6.4.5 由外部方法访问final变量

    与其他内部类相比较,局部类还有一个优点。它们不仅能够访问包含它们的外部类,还可以访问局部变量。

    6.4.6 匿名内部类

    假如只创建这个类的一个对象,就不必命名了。这种类被称为匿名内部类(anonymous inner class)。

       

    public void start(int interval,final boolean beep){

    ActionListener listener = new ActionListener(){

    public void actionPerformed(ActionEvent event){

    }

    }

    Timer t = new Timer(interval,listener);

    t.start();

    }

     

    6.4.7 静态内部类

    有时候,使用内部类只是为了把一个类隐藏在另一个类的内部,并不需要内部类引用外围对象。为此,可以将内部类声明为static,以便取消产生的引用。

    6.5 代理

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

    代理类可以在运行时创建全新的类。这样的代理类能够实现指定的接口。尤其是,它具有些列方法:

    • 指定接口所需要的全部方法。
    • Object类中的全部方法,例如,toString、equals等。

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

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

    • 一个类加载器(class loader)。
    • 一个Class对象数组,每个元素都是要实现的接口。
    • 一个调用处理器。

       

    package proxy;

    import java.lang.reflect.*;

    import java.util.*;

    /**

    * This program demonstrates the use of proxies.

    * @version 1.00 2000-04-13

    * @author Cay Horstmann

    */

    public class ProxyTest

    {

    public static void main(String[] args)

    {

    Object[] elements = new Object[1000];

    // fill elements with proxies for the integers 1 ... 1000

    for (int i = 0; i < elements.length; i++)

    {

    Integer value = i + 1;

    InvocationHandler handler = new TraceHandler(value);

    Object proxy = Proxy.newProxyInstance(null, new Class[] { Comparable.class } , handler);

    elements[i] = proxy;

    }

    // construct a random integer

    Integer key = new Random().nextInt(elements.length) + 1;

    // search for the key

    int result = Arrays.binarySearch(elements, key);

    // print match if found

    if (result >= 0) System.out.println(elements[result]);

    }

    }

    /**

    * An invocation handler that prints out the method name and parameters, then

    * invokes the original method

    */

    class TraceHandler implements InvocationHandler

    {

    private Object target;

    /**

    * Constructs a TraceHandler

    * @param t the implicit parameter of the method call

    */

    public TraceHandler(Object t)

    {

    target = t;

    }

    public Object invoke(Object proxy, Method m, Object[] args) throws Throwable

    {

    // print implicit argument

    System.out.print(target);

    // print method name

    System.out.print("." + m.getName() + "(");

    // print explicit arguments

    if (args != null)

    {

    for (int i = 0; i < args.length; i++)

    {

    System.out.print(args[i]);

    if (i < args.length - 1) System.out.print(", ");

    }

    }

    System.out.println(")");

    // invoke actual method

    return m.invoke(target, args);

    }

    }

     

    代理类的特性

    所有的代理类都扩展于Proxy类。

    一个代理类只有一个实例域——调用处理器,它定义在Proxy的超类中。

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

       

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

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

        可以通过调用Proxy类中的isProxyClass检测一个特定的Class对象是否代表一个代理类。

  • 相关阅读:
    Count and Say leetcode
    Find Minimum in Rotated Sorted Array II leetcode
    Find Minimum in Rotated Sorted Array leetcode
    Search in Rotated Sorted Array II leetcode
    search in rotated sorted array leetcode
    Substring with Concatenation of All Words
    Subsets 子集系列问题 leetcode
    Sudoku Solver Backtracking
    Valid Sudoku leetcode
    《如何求解问题》-现代启发式方法
  • 原文地址:https://www.cnblogs.com/xuzhen97/p/7738189.html
Copyright © 2011-2022 走看看