Java的接口与内部类

来源:互联网 发布:nginx 会话粘滞 编辑:程序博客网 时间:2024/05/16 18:03

接口:主要用于描述类具有什么功能,而不是给出每个功能的具体实现。

一个类可以实现一个或多个接口,并在需要接口的地方,随时使用实现了相应的接口的对象。

克隆对象(深拷贝):指创建一个新对象,且新对象的状态与原始对象的状态相同

当对克隆的新对象进行修改时,不会影响原始对象的状态。

内部类机制:内部类定义在另一个类的内部,其中的方法可以访问包含它们的外部类的域,主要用于设计具有相互协作关系的类集合。

一、接口

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

1>接口中的所有方法自动地属于public,因此,在接口中声明方法时,不必提供关键字public。

2>接口中可以定义常量,不能含有实例域,也不能在接口中实现方法。

3>类实现接口的步骤:

a>将类声明为实现给定的接口。  关键字  implements

b>对接口中的所有方法进行定义。

注:

i>在接口声明中,方法不需要声明为public,因为在接口中的所有方法都自动地是public。不过,在实现接口时,必须把方法声明为public,否则,编译器将认为访问属性为包默认,即类的默认访问属性,之后编译器就会给出试图提供更弱的访问权限的警告信息。

ii>如果需要调用底层的排序服务必须让它实现Comparable接口的compareTo方法。

例如:使用Arrays.sort()方法对数组进行排序,本质上必须对两个对象进行比较,而比较的方式就是通过调用Comparable接口的compareTo方法。所以需要实现Comparable接口,如果直接创建compareTo方法,而不继承接口的话,Java也无法调用。

( 1 )接口的特性

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

2>不能构造接口的对象,却能声明接口的变量,但是接口变量必须引用实现了接口的类对象。

3>如同使用instanceof检查一个对象是否属于某个特定类一样,也可以使用instance检查一个对象是否实现了某个特定的接口。

4>接口可以被扩展,使用extends关键字类扩展某个接口。

5>接口中不能包含实例域或静态方法,但却可以包含常量。

6>接口中的方法都自动被设置为public,接口中的域将被自动设为public static final。

7>每个类只能拥有一个超类,但却可以实现多个接口。

( 2 )接口与抽象类

Java不支持多继承,因为多继承会让语言本身变得非常复杂,效率也会降低。

接口可以提供多重继承,同时能避免多重继承的复杂性和低效性。

二、对象克隆

当拷贝一个变量时,原始变量与拷贝变量引用同一个对象,改变一个变量所引用的对象将会对另一个变量产生影响。

使用clone方法可以创建一个对象的新的copy,最初状态与原来的变量引用的对象一样,而且可以各自改变自己的状态。

1>clone方法时Object类的一个protected方法,用户编写的代码中不能直接调用。

2>默认的克隆操作是浅拷贝,数据域是数值或基本类型,没有问题,但是如果包含子对象的引用,拷贝的结果会使两个域引用同一个子对象。

因此需要重新定义clone方法,以便实现克隆子对象的深拷贝。

重新定义,类必须:

a>实现Cloneable接口;

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

注:

i>在这里Cloneable接口的出现与接口的正常使用没有任何关系,尤其是,它并没有指定clone方法。该接口在这里是作为一个标记,表明类设计者要进行克隆处理。如果不继承该接口,就会产生一个已检查异常。

ii>标记接口没有方法,使用它的唯一目的是可以用instanceof进行类型检查。

iii>只要在clone中含有没有实现Cloneable接口的对象,Object类的clone方法就会抛出一个CloneNot-SupportException异常。

iv>必须谨慎地实现子类的克隆,而且克隆并不像人们想象的普遍。在标准类库中,只有不到5%的类实现了clone。

三、接口与回调

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

例如:

package com.interfaces;/**   @version 1.00 2000-04-13   @author Cay Horstmann*/import java.awt.*;import java.awt.event.*;import java.util.*;import javax.swing.*;import javax.swing.Timer; // to resolve conflict with java.util.Timerpublic class TimerTest{     public static void main(String[] args)   {        ActionListener listener = new TimePrinter();      // construct a timer that calls the listener      // once every 10 seconds      Timer t = new Timer(10000, listener);      t.start();      JOptionPane.showMessageDialog(null, "Quit program?");      System.exit(0);   }}class TimePrinter implements ActionListener{     public void actionPerformed(ActionEvent event)   {        Date now = new Date();      System.out.println("At the tone, the time is " + now);      Toolkit.getDefaultToolkit().beep();   }}

四、内部类

内部类:定义在另一个类中的类。

使用内部类的原因:

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

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

3>当想定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。

( 1 )使用内部类访问对象状态

内部类即可以访问自身的数据域,也可以访问创建它的外围类对象的数据域。(在调用内部类的构造函数时,隐式的将外围类的引用作为传递)

( 2 )匿名内部类

创建一个实现接口的类的新对象,需要实现接口中的方法定义在括号{}内。

语法格式为:

new SuperType(construction parameters){inner class methods and data}
其中SuperType是接口,在{}内实现相应的方法。这样内部类就实现了这个接口。

SuperType也可以是一个类,于是内部类就扩展它。

( 3 )静态内部类

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

为此,可以将内部类声明为static,以便取消产生的引用。

( 4 )代理proxy

Java SE1.3新增加的特性。利用代理可以在运行时创建一个实现了一组给定接口的新类。这种功能只有在编译时无法确定需要实现哪个接口时才有必要使用。

对于应用程序设计人员来说,遇见这种情况的机会很少,但是对于系统程序设计人员来说,代理带来灵活性却十分重要。

1>代理类可以在运行时创建全新的类,这样代理类能够实现指定的接口,而且具有下列方法:

a>指定接口所需要的全部方法。

b>Object类中的全部方法。

2>不能再运行时定义这些方法的新代码,而是要提供一个调用处理器。调用处理器是实现了InvocationHandler接口的类对象,接口中只有一个方法:Object invoke(Object proxy,Method method,Object[] args)

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

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

a>一个类加载器

b>一个Class对象数组,每个元素都是需要实现接口

c>一个调用处理器

4>代理类的特性

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

b>所有的代理类都扩展于Proxy类,一个代理类只有一个实例域------调用处理器,它定义在Proxy的超类中。

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

注:就目前而言,对于代理的部分感觉不理解,目前不常使用,所以暂且搁置,以后再详细了解。
0 0
原创粉丝点击