zoukankan      html  css  js  c++  java
  • Java接口

    接口概念与特性

    Java接口时一系列方法的声明,是一些特征方法的集合,一个接口只有方法的特征而没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以有不同的行为。

    以下以Comparable接口为例,该接口有一个compareTo方法,接受一个Object对象,返回一个整型数值。(用于比较大小)

    让一个类实现一个接口的步骤:

    1)将类声明为实现给定的接口,使用implements关键字;

    2)对接口中所有方法进行定义。

    class A implements Comparable{
       public int ComparaTo(Object obj){
       ......
       }
    }

    接口的一些特性

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

    2)接口不能包含实例域或静态方法,可以包含常量,常量自动地属于public static final。

    3)实现接口时,必须将方法声明为public,与1)比较,该处为实现时。

    public int compareTo(Object obj){...}

    4)接口不是类,不能实例化接口;可以声明接口的变量,但该变量必须引用实现了该接口的类对象。

    c = new Comparable(...)  //错误
    Comparable c;//正确
    c = new Employee(...)  //若Employee类实现了Comparable接口,此语句正确,否则错误

    5)接口允许被拓展,使用extends关键字可以将接口拓展成另一个接口。

    public interface A{...}
    public interface B extends A{...}    //此时,接口B将包含A的方法和它自己定义的方法

    6)尽管每个类只能有一个超类,但却可以实现多个接口;使用逗号分割开多个接口。

    class A implements Comparable, Cloneable

    一个实例:Employee类实现Comparable接口,使得能够使用Array.sort方法对工资排序。

     1 package interfaces;
     2 
     3 public class Employee implements Comparable<Employee> {
     4     private String name;
     5     private double salary;
     6 
     7     public Employee(String name, double salary){
     8         this.name = name;
     9         this.salary = salary;
    10     }
    11 
    12     public String getName() {
    13         return name;
    14     }
    15 
    16     public double getSalary() {
    17         return salary;
    18     }
    19 
    20     public void raiseSalary(double byPercent){
    21         double raise = salary * byPercent/100;
    22         salary += raise;
    23     }
    24 
    25     public int compareTo(Employee other){
    26         return Double.compare(salary,other.salary);
    27     }
    28 }
    Employee.java
     1 package interfaces;
     2 
     3 import java.util.Arrays;
     4 
     5 public class EmployeeSortTest {
     6     public static void main(String[] args){
     7         Employee[] staff = new Employee[3];
     8         staff[0] = new Employee("Harry",30000);
     9         staff[1] = new Employee("Tony", 52000);
    10         staff[2] = new Employee("Tom", 36000);
    11 
    12         Arrays.sort(staff);
    13 
    14         for (Employee e:staff){
    15             System.out.println("name="+e.getName()+",salary="+e.getSalary());
    16         }
    17     }
    18 }
    EmployeeSortTest.java
    1 name=Harry,salary=30000.0
    2 name=Tom,salary=36000.0
    3 name=Tony,salary=52000.0
    结果

    接口与抽象类

    在c++中,一个类允许有多个超类,该特性称为多继承,而Java不支持多继承。因而,使用抽象类作为通用属性就存在这样的问题:当一个类已经继承于一个类,就不能再拓展于第二个类了。接口解决了这个问题,因为一个类可以实现多个接口。

    以下为抽象类和接口的区别与相似性:

              抽象类            接口
                          不能被实例化
            被子类继承           被子类实现
           包含或不包含抽象方法 包含或不包含抽象方法(java se 8后可以在接口中实现方法)
    抽象方法必须被子类实现,否则子类也必须声明为抽象的       抽象方法必须被子类实现
       一个类只能有一个抽象(或普通)的超类       一个类可以实现多个接口
            表示该对象是什么       一般表示该对象能做什么
             abstract修饰         implements修饰

    默认方法与冲突

    可以为使用default关键字为接口方法提供一个默认的实现。

    public interface A{
       default int func(){...}
    }

    这样,实现这个接口时可以选择不覆盖该方法。

    如果一个接口中将一个方法定义为默认方法,然后又在超类或另一个接口中定义了同样的方法。这样就可能会出现命名冲突,Java解决办法

    1)超类优先。如果一个超类提供了具体的方法,接口中的同名同参数的方法将被忽略。

    2)接口冲突。若两个接口有同样的方法的实现,那么必须在子类中覆盖该方法。

    接口与回调

    回调时一种常见的程序设计模式。在这种模式中,可以指出某个特定事件发生时应该采取的动作。例如按下鼠标产生什么效果。下面是一个例子:

    java.swing中有一个Timer类,可以使用它在到达指定时间间隔发出通告。创建一个对象实现java.awt.event包中的ActionListener接口。到达指定间隔时间发生一些事情。

     1 package timer;
     2 
     3 import javax.swing.*;
     4 import java.awt.*;
     5 import java.awt.event.ActionEvent;
     6 import java.awt.event.ActionListener;
     7 import java.util.Date;
     8 
     9 public class TimerTest {
    10 
    11     public static void main(String[] args) {
    12         ActionListener listener = new TimePrinter();
    13 
    14         Timer t = new Timer(10000, listener);//定时器对象,传递对象
    15         t.start();
    16         JOptionPane.showMessageDialog(null, "quit program");//产生消息框
    17         System.exit(0);
    18     }
    19 }
    20 
    21 class TimePrinter implements ActionListener{
    22     public void actionPerformed(ActionEvent event){//实现事件响应方法
    23         System.out.println("at the time, the time is "+ new Date());
    24         Toolkit.getDefaultToolkit().beep();//发出铃响
    25     }
    26 }
    示例

    接口与深浅拷贝

    浅拷贝:原变量和副本都是同一个对象的引用。

    Employee e = new Employee();
    Employee copy = e;

    深拷贝:元变量和副本属于不同的引用,有相同的状态。

    这里需要实现Cloneable接口,这个接口指示一个类提供clone方法。它是Object的一个protected方法。这说明不能直接调用这个方法。

    设计为protected的原因:Object类对某个对象进行clone,它逐一地拷贝所有域。如果域是基本类型自然没有问题,如果域包含一个对象的引用,那么拷贝这个域将得到相同的引用。如此一来,拷贝对象仍然和原对象共享一些信息。

    也就是说,如果默认clone方法不能满足需求(课变得而子对象),那么必须:

    1)实现Cloneable接口

    2)重新定义clone方法,指定public修饰符。

    以下例子:拷贝一个Employee实例,修改日期

    package clone;
    
    import java.util.Date;
    import java.util.GregorianCalendar;
    
    public class Employee implements Cloneable {
        private String name;
        private double salary;
        private Date hireDay;
    
        public Employee(String name, double salary){
            this.name = name;
            this.salary = salary;
            hireDay = new Date();
        }
    
        public Employee clone() throws CloneNotSupportedException{//实现克隆方法
            Employee cloned = (Employee) super.clone();//此时name和hireDay是引用
            cloned.hireDay = (Date) hireDay.clone();//拷贝hireDay
            return cloned;
        }
    
        public void setHireday(int year, int month, int day){
            Date newHireDay = new GregorianCalendar(year,month-1,day).getTime();//格林威治时间
            hireDay.setTime(newHireDay.getTime());
        }
    
        public void raiseSalary(double byPercent){
            double raise = salary * byPercent/100;
            salary += raise;
        }
    
        public String toString(){
            return "Employee[name=" + name + ",salary=" + salary + ",hireDay=" + hireDay + "]";
        }
    }
    Emlpoyee.java
     1 package clone;
     2 
     3 public class CloneTest {
     4     public static void main(String[] args){
     5         try{
     6             Employee original = new Employee("John", 50000);
     7             original.setHireday(2000,1,1);
     8             Employee copy = original.clone();
     9             copy.setHireday(2002,12,31);
    10             System.out.println("original="+original);
    11             System.out.println("copy="+copy);
    12         }catch (CloneNotSupportedException e){
    13             e.printStackTrace();
    14         }
    15     }
    16 }
    cloneTest.java

    结果:

    original=Employee[name=John,salary=50000.0,hireDay=Sat Jan 01 00:00:00 CST 2000]
    copy=Employee[name=John,salary=50000.0,hireDay=Tue Dec 31 00:00:00 CST 2002]

  • 相关阅读:
    HTTP报文
    Linux命令行下快捷键
    ruby离线安装整理
    Tomcat启动时卡在 INFO HostConfig.deployDirectory Deploy
    ruby在线安装整理
    python_控制台输出带颜色的文字方法
    http proxy模块参数
    upstream模块调度算法
    upstream模块介绍
    nginx的upstream目前支持5种方式的分配
  • 原文地址:https://www.cnblogs.com/lht-record/p/8372047.html
Copyright © 2011-2022 走看看