教你在Java接口中定义方法

基本上所有的Java教程都会告诉我们Java接口的方法都是public、abstract类型的,没有方法体的。

一、abstract和接口初认识

但是在JDK8里面,你是可以突破这个界限的哦。

abstract
class和interface是Java语言中对于抽象类定义进行支持的两种机制。abstract
class和interface之间在对于抽象类定义的支持方面具有很大的相似性,甚至可以相互替换,因此很多开发者在进行抽象类定义时对于abstract
class和interface的选择显得比较随意。其实,两者之间还是有很大的区别的,对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意图的理解是否正确、合理。

假设我们现在有一个接口:TimeClient,其代码结构如下:

abstract 关键字可以修饰类或方法。

import java.time.*;

public interface TimeClient {
    void setTime(int hour, int minute, int second);
    void setDate(int day, int month, int year);
    void setDateAndTime(int day, int month, int year,
                               int hour, int minute, int second);
    LocalDateTime getLocalDateTime();
}

抽象方法Java中可以利用abstract关键字定义一些不包括方法体的方法,没有方法体就没有实现,具体实现交给子类,这样的方法称为
抽象方法

接下来,SimpleTimeClient类实现了TimeClient接口,具体代码如下:

抽象类有抽象方法的类就是抽象类

package defaultmethods;

import java.time.*;
import java.lang.*;
import java.util.*;

public class SimpleTimeClient implements TimeClient {

    private LocalDateTime dateAndTime;

    public SimpleTimeClient() {
        dateAndTime = LocalDateTime.now();
    }

    public void setTime(int hour, int minute, int second) {
        LocalDate currentDate = LocalDate.from(dateAndTime);
        LocalTime timeToSet = LocalTime.of(hour, minute, second);
        dateAndTime = LocalDateTime.of(currentDate, timeToSet);
    }

    public void setDate(int day, int month, int year) {
        LocalDate dateToSet = LocalDate.of(day, month, year);
        LocalTime currentTime = LocalTime.from(dateAndTime);
        dateAndTime = LocalDateTime.of(dateToSet, currentTime);
    }

    public void setDateAndTime(int day, int month, int year,
                               int hour, int minute, int second) {
        LocalDate dateToSet = LocalDate.of(day, month, year);
        LocalTime timeToSet = LocalTime.of(hour, minute, second);
        dateAndTime = LocalDateTime.of(dateToSet, timeToSet);
    }

    public LocalDateTime getLocalDateTime() {
        return dateAndTime;
    }

    public String toString() {
        return dateAndTime.toString();
    }

    public static void main(String... args) {
        TimeClient myTimeClient = new SimpleTimeClient();
        System.out.println(myTimeClient.toString());
    }
}

接口一个类中如果所有方法都是abstract 方法,那么这个类我们可以利用
interface 定义成接口。

现在假设你想在接口TimeClient中添加一个新功能,通过这个功能我们可以指定我们所在的时区。

什么是抽象方法澳门新葡亰网站注册,声明为 abstract 的方法就是抽象方法。

public interface TimeClient {
    void setTime(int hour, int minute, int second);
    void setDate(int day, int month, int year);
    void setDateAndTime(int day, int month, int year,
        int hour, int minute, int second);
    LocalDateTime getLocalDateTime();                           
 ZonedDateTime getZonedDateTime(String zoneString); }

抽象方法的写法

随着TimeClient的变化,你不得不修改你的SimpleTimeClient类,实现getZonedDateTime方法。一般来说,设置时区这个功能会是各个TimeClient实现类中通用的一个功能。这个时候,你通常会选择再定义一个AbstractTimeClient类来实现getZonedDateTime方法。而在JDK8中,你可以选择直接在接口中来实现该方法(interface已经把手伸到abstract
class的地盘了)。

abstract 返回值类型 方法名;

package defaultmethods;

import java.time.*;

public interface TimeClient {
    void setTime(int hour, int minute, int second);
    void setDate(int day, int month, int year);
    void setDateAndTime(int day, int month, int year,
                               int hour, int minute, int second);
    LocalDateTime getLocalDateTime();

    static ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }

    default ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }
}

抽象方法的特点

从上面的例子,我们可以看到通过static和default修饰符我们可以直接在接口中实现方法体,同时不要忘记,任何在接口中方法声明都是public类型的哦。

  • 抽象方法只有声明,没有实现,抽象方法必须由子类进行重写实现没有实现就是没有方法体(方法体就是方法后面的花括号),意味着这是一个没有完成的方法,抽象的。抽象方法只能由子类去重写实现

  • abstract 关键字不能应用于 static、private 或 final
    方法,因为这些方法不能被重写。

OK,现在我们需要一个新的接口:AnotherTimeClient,它得继承TimeClient接口。那么,对于TimeClient接口中定义的getZonedDateTime方法,你可以做如下三种处理:

什么是抽象类

  1. 重新声明getZonedDateTime方法,使它变成abstract类型。
  2. 重新定义getZonedDateTime方法。
  3. 直接继承。

有抽象方法的类就是抽象类

而static方法和我们在类里面定义的static方法概念一致。

抽象类的写法public abstract class 类名{}

抽象类的特点

  • 1、抽象类不能被实例化,实例化就必须实现全部方法,实现全部方法后这个类就不是抽象类。,但可以有构造函数
  • 2、抽象方法必须由子类进行重写实现
  • 3、子类继承自抽象类,必须实现抽象类的全部抽象方法,这样的子类也叫具体类,具体类才可以被实例化(这个实现全部方法方法的子类不是抽象类,抽象类不能实例化)。如果没有实现全部抽象方法,那么这个子类必须也是抽象类。
  • 4、一个类只要出现了abstract方法,那么这个类就必须是abstract类
  • 5、抽象类中可以有非抽象方法,可以有变量

如果一个类中方法都是抽象方法,那么我们就可以把这个类定义成接口。(接口是一种特殊的类,接口也是类)

代码示例

接下看通过简单的代码,看一下抽象类和抽象方法

AbsPerson

public abstract class AbsPerson { public int number = 16; { System.out.println("抽象类的代码块"); } public AbsPerson(){ System.out.println("抽象类的构造函数"); } int maxAge = 200; public abstract void say(String str); public abstract void age(); public void absPersonNormal(){ System.out.println("抽象类的普通方法,或者叫 非抽象方法"); } }

..Student

public class Student extends AbsPerson{ { System.out.println("学生类的代码块"); } public Student() { System.out.println("学生类的构造函数"); } @Override public void say(String str) { System.out.println; } @Override public void age() { System.out.println; }}

..AbsPerson

// 没实现 AbsPerson 这个抽象类的所有方法,所以这个类也是抽象类public abstract class Worker extends AbsPerson{ @Override public void say(String str) { // TODO Auto-generated method stub }}

..TestClass

public class TestClass{ public static void main(String[] args) { Student student = new Student(); student.say("day day up");// 子类调用实现自抽象类的方法 student.age();// 子类调用实现自抽象类的方法 student.absPersonNormal();// 子类调用抽象类的 非抽象方法 System.out.println("子类调用抽象类的变量: "+student.number); }}

..运行结果:

抽象类的代码块抽象类的构造函数学生类的代码块学生类的构造函数day day up年龄18抽象类的普通方法,或者叫 非抽象方法子类调用抽象类的变量: 16

代码已经说得很清楚了。

如果一个类中方法都是抽象方法,那么我们就可以把这个类定义成接口。接口的出现让类不必受限于单一继承的束缚,可以灵活地继承一些共有的特性,间接实现类似多继承的目的。

接口里面只可能有两种东西

  • 1、抽象方法
  • 2、全局静态常量(接口中没有变量,默认都是用 public static
    final标识的,不过在interface中一般不定义属性成员,只定义抽象方法)

接口的特点:

  • 1、接口的访问修饰符只能是public,或者不写*
    2、interface中定义的方法和成员变量,默认为public访问权限,且仅能为public(声明为其他访问修饰符会报错)

  • 3、接口中的没有变量,只有全局静态常量。(看起来像常量,但是依然是静态全局常量)

  • 4、实现接口的非抽象类必须要实现该接口的所有方法。抽象类可以不用实现。(接口中的方法不能是static、final或者private,也好理解,毕竟带了这些就不能被@Override了)

  • 5、不能使用new操作符实例化一个接口,但可以声明一个接口变量,该变量必须引用一个实现该接口的类的对象。通过这个做回调接口,这也开发中特别常见的。

  • 6、可以使用 instanceof
    检查一个对象是否实现了某个特定的接口。例如:if(anObject instanceof
    Comparable){}。

  • 7、在java8中,接口里也可以定义默认方法:

注意点:在实现多接口的时候一定要避免方法名的重复。(多实现的时候,如果接口重名会比较麻烦,所以起名要有规范)

public interface java8{ //在接口里定义默认方法 default void test(){ System.out.println("java 新特性"); }}

基本特点如上,下面通过示例代码大概看一下:

示例代码

IStuent

public interface IStuent{ int minAge = 9; // 默认会加上 public static final ,全局静态常量 void iStudentDohomeWord(); // 接口中的方法默认就是 abstract方法 void iStudentGoToSchool();}

..IOther

interface IOther { void iOtherMethod();}

..AbsClass

// 抽象类实现接口,可以不复写接口中的 抽象方法public abstract class AbsClass implements IStudent{ // 这里不复写任何抽象方法没问题}