Java03接口与内部类

来源:互联网 发布:java生成时间戳 编辑:程序博客网 时间:2024/05/16 14:31

6 接口与内部类

接口 interface

对象克隆

内部类 inner class

代理 proxy

 

6.1 接口

public interface Comparable<T>{    int compareTo(T other);}


Arrays.sort(Object[] a) 利用的是mergesort

 

接口也可以被扩展

public interface Moveable{    void move(double x, double y);}public interface Powered extends Moveable{    double milesPerGallon();  //public abstract    double SPEED_LIMIT = 95; //public static final}


标准库中的SwingConstants接口只包含NORTHSOUTHHORIZOTAL等常量,任何实现此接口的类都自动继承了这些常量。

class Employee implements Cloneable, Comparable

 

6.2 对象克隆

Objectclone()protected,默认浅拷贝。

 

实现Cloneable接口(空接口,标记用)

使用public访问修饰符重新定义clone方法

 

标记接口的唯一作用,可以使用instanceof进行类型检查

class Employ implements Cloneable{    public Employ clone() throws CloneNotSupportedException    {    ...    }}

只要在clone中含有未实现Cloneable接口的对象,Object类的clone方法就会抛出一个CloneNotSupportException异常。

如果是final类,也可不抛异常,而是try-catch

 

6.3 接口与回调

回调(call back)是一种常见的设计模式。可以指出某个特定事件发生时应该采取的动作。

 

public interface ActionListener

{

void actionPerformed(ActionEvent event);

}

 

class TimePrinter implements ActionListener{ }

new Timer(1000, new TimePrinter()).start();  

//Timer构造器的第一个参数是发出通告的时间间隔,单位是毫秒;第二个是监听器对象,在时间到后执行actionPerformed()

 

javax.swing.JOptionPane

static void showMessageDialog(Component parent, Object message)

如果parentnull,则在中央显示

javax.swing.Timer

Timer(int interval, ActionListener listener)

void start()

void stop()

java.awt.Toolkit

void beep()

 

6.4 内部类

定义在另一个类中的类。

使用原因:

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

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

当想定义一个回调函数时,使用匿名内部类比较便捷

 

内部类中添加了一个外围类引用的参数 OuterClass.this

在外部类外引用公开内部类OuterClass.InnerClass

 

内部类是一种编译器现象,与虚拟机无关。

编译器将内部类翻译成用$分隔外部类名与内部类名的常规类文件,虚拟机对此一无所知

OuterClass$InnerClass

编译器为了引用外围类,生成了一个附加的实例域final OuterClass this$0

外围类将添加静态方法 static boolean access$0(OuterClass)InnerClass将调用此方法来访问外部类的私有域。

 

 

局部内部类不能用publicprivate访问说明符进行声明

它的作用域被限定在声明这个局部类的块中

优势:对外部世界可以完全隐藏起来

可以访问外部类,和被声明为final的局部变量

 

匿名内部类 anonymous inner class

InnerClass ic = new InnerClass(){ 类的实现 };

InnerClass可以是一个接口,类内实现接口方法

只创建类的一个对象

 

静态内部类

只是为了把一个类隐藏在另一个类的内部,并不需要内部类引用外围类对象

static 进行声明

 

6.5 代理

在运行时创建一个实现了一组给定接口的新类。

这种功能在编译时无法确定需要实现哪个接口时才有必要使用。

 

应用场景:

一个接口,其确切类型在编译时无法知道。

需要在程序运行状态定义一个实现这些接口的新类。

 

方案一:

生成代码,将代码放置在一个文件中,调用编译器进行编译,然后再加载结果类文件。

方案二:

代理机制,在运行时创建全新的类。这样的代理类能够实现指定接口。

指定接口有如下方法:

指定接口所需的全部方法;

Object类中的全部方法:toString equals hashcode

 

方法:

1、定义调用处理器(invocation handler),包装基本类对象。

调用处理器是实现了InvocationHandler接口的类对象。在这个接口中只用一个方法:

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

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

2、创建代理对象。

使用Proxy类的newProxyInstance方法,有三个参数:

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

 

例:

public interface Run{    void run();}
public class Animal implements Run{    @Override    public void run()    {        System.out.println("Animal is running");    }}
public RunHandler implements InvocationHandler{    private Object target;    public RunHandler(Object target)    {        this.target = target;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args)    {        System.out.println("Proxy is running");        return method.invoke(target, args);    }}

Animal animal = new Animal(); //基本类对象InvocationHandler handler = new RunHandler(animal); //封装基本类对象//handler封装的是实现Run接口的类对象。Object proxy = Proxy.newProxyInstance(Run.class.getClassLoader(), new Class[]{Run.class}, handler);(Run)proxy.run(); //此时代理对象proxy可以调用Run接口的方法。 


代理的特性:

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

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

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

为了履行代理对象的职责,所需要的任何附加数据都必须存储在调用处理器中。

 

代理类覆盖了Object类中的方法toString equals hashCode,这些方法调用了调用处理器的invoke

Object类的clonegetClass没有被重新定义。

 

没有定义代理类的名字,虚拟机中的Proxy类将生成一个以字符串$Proxy开头的类名。

对于特定类的加载器和预设的一组接口来说,只能有一个代理类。即,如果使用同一个类加载器和接口数组调用了两次newInstance方法的话,那么只能得到同一个类的两个对象。

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

代理类一定是publicfinal

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

 

0 0
原创粉丝点击