zoukankan      html  css  js  c++  java
  • Java基础(十)接口(interface)

      1.接口的概念

      在Java中,接口不是类,而是对类的一组需求描述,这些类要遵从接口描述。

      例如:Array类中的sort方法可以对对象数组进行排序,但要求满足下列前提:对象所属的类必须实现了Comparable接口。

      Comparable接口的代码:任何实现了Comparable接口的类都必须包含compareTo方法。

    public interface Comparable<T> {
        /**
         * Compares this object with the specified object for order.  Returns a
         * negative integer, zero, or a positive integer as this object is less
         * than, equal to, or greater than the specified object.
         *
         * @param   o the object to be compared.
         * @return  a negative integer, zero, or a positive integer as this object
         *          is less than, equal to, or greater than the specified object.
         *
         * @throws NullPointerException if the specified object is null
         * @throws ClassCastException if the specified object's type prevents it
         *         from being compared to this object.
         */
        public int compareTo(T o);
    }

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

      接口没有实例,在接口中可以定义常量,也可以定义简单方法,但是这些方法不能引用实例域。

      提供实例域和方法实现的任务应该由实现接口的那个类来完成,因此,可以将接口看成是没有实例域的抽象类。

      如果希望用Array类的sort方法对Employee对象数组进行排序,那么Employee类就必须实现Comparable接口。

    public class Employee implements Comparable<Employee>
    {
    ...
       public int compareTo(Employee other)
       {
          return Double.compare(salary, other.salary);  // 使用静态的compare方法,大于等于小于时分别返回1,-1,0
       }
    }

      为什么不可以直接在Employee类中直接提供compareTo方法而不实现Comparable接口呢:这是因为Java是一种强类型(strongly typed)语言。在调用方法的时候,编译器会检查这个方法是否存在。

      Array类中的sort方法中的ComparableTimSort限制了必须有compareTo方法,从而限制了必须实现Comparable接口。

        public static void sort(Object[] a) {
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a);
            else
                ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
        }

      2.接口的特性

      (1)接口不是类,不能使用new实例化一个接口

      (2)尽管不能构造接口的对象,但能声明接口的变量,接口变量必须引用实现了接口的类对象。也可以使用instanceof检查一个对象是否实现了某个特定的接口。

    Comparable x;
    x = new Employee(...);
    if (x instanceOf Comparable) ...

      (3)与建立类的继承关系一样,接口也可以被扩展。允许存在多条从具有较高通用性的接口道较高专用性的接口的链。

      例如:首先建立一个称为Moveable的接口

    package test;
    
    public interface Moveable {
    
        void move(double x, double y);
    }

      然后建立一个称为Powered的接口,使得这个接口继承Moveable接口:这里注意的是,虽然接口中不能包含实例域,但是却可以包含常量,与接口中的方法自动地被设置成public一样,接口中的域将被自动地设置为public static final。任何实现Powered接口的类都自动地继承了这些常量,并且可在方法中直接引用SPEED_LIMIT这个常量,而不用写成Powered.SPEED_LIMIT这种形式。

    package test;
    
    public interface Powered extends Moveable{
    
        double SPEED_LIMIT = 95;
        double milesPerGallon();
    }

      任何实现了Powered 接口的类都必须实现move方法和milesPerGallon方法:

    package test;
    
    public class Imp implements Powered{
    
        @Override
        public void move(double x, double y) {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public double milesPerGallon() {
            // TODO Auto-generated method stub
            return 0;
        }
    
    }

      3.接口的好处

      前面提到过的Comparable接口也可以用抽象类来表示,接口实现关系也可以用继承来实现,例如:

    package test;
    
    public abstract class Comparable<T> {
        
        public abstract int compareTo(T o);
    }

      Employee类来继承Comparable抽象方法后必须也必须实现compareTo方法:

    package test;
    
    public class Employee extends Comparable<Employee>{
    
        @Override
        public int compareTo(Employee o) {
            // TODO Auto-generated method stub
            return 0;
        }
    
    }

      这看起来似乎没有什么问题,但是,使用抽象类表示通用属性的时候,每个类只能扩展于一个类,即每个类只能单继承。而接口的好处是,每个类可以同时实现很多个接口。接口可以提供多重继承的大多数好处,同时还能避免多重继承的复杂性和低效性。

      4.在接口中增加静态方法和默认方法

      (1)在接口中增加静态方法

      Java SE 8 允许在接口中增加静态方法:例如,在Moveable接口中提供了静态方法move,

    package test;
    
    public interface Moveable {
    
        static void move(double x, double y) {
            System.out.println(x*y);
        };
    }

      任何继承Moveable的类不用去实现move静态方法,并且可以直接调用move方法:

    package test;
    
    public class Imp implements Moveable{
    
        public static void main(String[] args) {
            Moveable.move(10.0, 10.0);      // 打印:100.0
        }
    }

      (2)在接口中增加默认方法

      可以为接口中的方法提供一个默认实现,用default修饰符标记这样一个方法,例如,Moveable接口中有两个方法,其中move方法标记为默认方法并且实现:

    package test;
    
    public interface Moveable {
    
        int size();
        default double move(double x, double y) {
            return x*y;
        }
    }

      任何继承Moveable接口的方法,如果没有重写move方法,那么就默认该类具有接口中的默认方法。

    package test;
    
    public class Imp implements Moveable{
    
        @Override
        public int size() {
            // TODO Auto-generated method stub
            return 0;
        }
    
        public static void main(String[] args) {
            Imp test = new Imp();
            System.out.println(test.move(10.0, 10.0));  // 打印:100.0
        }
    
    }

      如果在继承Moveable接口的方法中重写了默认方法,则以重写的方法为准:

    package test;
    
    public class Imp implements Moveable{
    
        @Override
        public int size() {
            // TODO Auto-generated method stub
            return 0;
        }
        
        @Override
        public double move(double x, double y) {
            // TODO Auto-generated method stub
            return x + y;
        }
    
        public static void main(String[] args) {
            Imp test = new Imp();
            System.out.println(test.move(10.0, 10.0));  // 打印:20.0
        }
    
    }

      默认方法还可以调用任何其他方法,例如,调用同一个接口中的其他方法:

    package test;
    
    public interface Moveable {
    
        int size();
        default boolean move(double x, double y) {
            return size() == 0;
        }
    }

      任何实现Moveable接口的方法都必须实现size方法,并且还拥有move方法的默认实现:

    package test;
    
    public class Imp implements Moveable{
    
        @Override
        public int size() {
            // TODO Auto-generated method stub
            return 0;
        }
    
        public static void main(String[] args) {
            Imp test = new Imp();
            System.out.println(test.move(0.0, 100.0));  // 打印:true
        }
    
    }

      5.默认方法冲突的解决方法

      如果先在一个接口中将一个方法定义为默认方法,然后又在父类或者另一个接口中定义了同样的方法,那么该如何选择:

      (1)父类优先。如果父类提供了一个具体方法,同时接口中提供了相同的默认方法,则接口中的默认方法会被忽略。

      (2)接口冲突时要重写。如果两个接口都提供一个相同的默认方法,则同时实现这两个接口的类必须重写这个方法。

  • 相关阅读:
    堆栈学习
    需要阅读的书籍
    Rust Book Lang Ch.19 Fully Qualified Syntax, Supertraits, Newtype Pattern, type aliases, never type, dynamic sized type
    Rust Lang Book Ch.19 Placeholder type, Default generic type parameter, operator overloading
    Rust Lang Book Ch.19 Unsafe
    Rust Lang Book Ch.18 Patterns and Matching
    Rust Lang Book Ch.17 OOP
    Rust Lang Book Ch.16 Concurrency
    Rust Lang Book Ch.15 Smart Pointers
    HDU3966-Aragorn's Story-树链剖分-点权
  • 原文地址:https://www.cnblogs.com/BigJunOba/p/9329516.html
Copyright © 2011-2022 走看看