Java03接口与内部类

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对象是否代表一个代理类。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值