乐趣区

关于java:一文打尽Java抽象类和接口的相关问题

相干文章:

  1. 《面向对象再探索》:介绍了面向对象的基本概念
  2. 《详解 Java 的对象创立》:介绍了对象的创立、结构器的应用
  3. 《一文打尽 Java 继承的相干问题》:介绍了继承的应用形式和注意事项

本文来介绍 Java 的抽象类和接口的应用。

1. 抽象类

在后面的文章中提到过:父类比子类更加形象,子类比父类更加具体。

在《一文打尽 Java 继承的相干问题》这篇文章中举了动物和狗的例子:

public class Animal {
    private String name;
    private int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Animal() {}

    public void say() {System.out.println("我是" + name + ",往年" + age + "岁了");
    }

    //getters and setters ...
}
public class Dog extends Animal {

    private String address;

    public Dog(String name, int age, String address) {super(name, age);
        this.address = address;
    }

    public Dog() {}

    public void say() {System.out.println("我叫" + super.getName() + ",往年" + super.getAge() + "岁了,家住" + address + ",汪汪汪...");
    }

    public void watchDoor() {System.out.println("我在" + address +"看门...");
    }

    //getters and setters ...
}

下面 Dog 类很天然地继承了 Animal 类,没故障!然而认真推敲一下 Animal 类的 say() 办法。

动物是一个很宽泛的概念,如果写代码示意,咱们平时见到的大部分生物都能够继承该类。如下图:

有这么多类继承 Animal 类,那 Animal 类的 say() 办法这样写适合吗?因为每种动物谈话的形式都不同,而动物又是这么宽泛的一个概念,咱们通常会 new Dog()new People(),但很少会去new Animal()

所以 Animal 类的 say() 办法体对其来说就是鸡肋个别的存在,因为即便有办法体,也会被其子类重写。既然这样那就罗唆不要办法体了。

换句话说,咱们将 Animal 类再进行更高层次地形象,它具备各种动物都有的属性,比方 nameage,也有各种动物都有的行为,比方say 然而,Animal类并不具体实现该办法,具体的实现交给子类来做

这样一来,谁继承了 Animal 类,谁就有了它的属性和行为,子类不必管父类的行为是否适合,因为父类的行为“有名无实”,所以子类只需继承这些“名”,具体的“实”则由子类来实现。

这样的 Animal 类就是 抽象类

上面将上例中的 Animal 类批改为抽象类,Dog类无需改变:

public abstract class Animal {
    private String name;
    private int age;

    public Animal(String name, int age) {// 有参结构器
        this.name = name;
        this.age = age;
    }

    public Animal() {// 无参结构器}

    public abstract void say();// 形象办法

    
    public String getName() {// 被具体实现的办法
        return name;
    }

    public void setName(String name) {this.name = name;}
    
    //getters and setters..
}

上面是抽象类的特点:

(一)抽象类被 abstract 关键字润饰。

public abstract class Animal {//......}

(二)类中没有办法体的办法叫 形象办法 ,也须要应用abstract 关键字润饰。

public abstract void say();// 形象办法

(三)有形象办法的类肯定是抽象类。

(四)没有形象办法的类也能够是抽象类。

(五)抽象类中能够有成员变量、结构器、被具体实现的办法。结构器不能是形象的。

(六)抽象类不能被实例化,然而能够申明一个抽象类变量

Animal animal = new Animal();// 报错: 'Animal' is abstract; cannot be instantiated
Anima animal;// 抽象类变量,可行

咱们以前遇到的类,比方 Dog 类,是用来形容对象的,但抽象类的办法没有具体实现,所以它没有足够的信息来形容对象,所以抽象类只能被继承用来形容其子类而不能实例化。

(七)子类扩大形象父类有两种抉择:

  1. 当子类不是抽象类时,子类必须实现形象父类的形象办法:
public class Dog extends Animal {
    // 属性、结构器、其余办法
    
    // 实现形象父类的形象办法
    @Override
    public void say() {System.out.println("我叫" + super.getName() + ",往年" + super.getAge() + "岁了,家住" + address + ",汪汪汪...");
    }
    
}
  1. 当子类是抽象类时,子类能够实现形象父类的形象办法,也能够抉择不实现。
public abstract class Dog extends Animal {
    // 属性、结构器、其余办法
    
    // 能够抉择不实现父类的形象办法
}

2. 接口

2.1. 什么是接口?

生存中有一种接口是大家每天都在用的,那就是插座。

不论是什么样的电器,冰箱、电视、电脑、电风扇,只有买回来,就能插上通电。之所以这么便当,就是因为电器生产商和插座生产商都恪守了一个 生产标准:我把插座生产成这个模样,你把插头也生产成这个模样,我不论你电器外部是啥样,你也不必管我的插座外部是啥样,大家把产品生产好,各自卖给客户,合作愉快,一起赚钱。这些产品如果当前坏了,那就再买一个恪守标准的就能持续配套应用了。

想一想,如果没有这个标准,插座和插头生产的千奇百怪,买回来怎么用?只能把插座和冰箱拆开,用手接 220V 的电线了。

换句话说,接口就是生产标准 / 规范,或者单方恪守的协定,只有单方都恪守,那么就能欢快地交换、欢快地单干。

在 Java 开发中,一个软件系统必定不是由一个人实现的,而是由一个团队实现的。那如何防止甲写的类乙不能用,乙写的类丙不能用呢,最初导致甲改了乙的代码,乙改了丙的代码?当时定好标准(接口),大家都恪守接口,只有我晓得你的接口,那么我不须要晓得你的具体代码,就能调用你的类。

2.2. 接口的应用

把握对于接口几个特点就能欢快地写接口了:

(一)Java 中应用 inteface 关键字来申明一个接口,接口必须是 public 的,只有私有了能力让大家恪守:

public interface Runnable {}

(二)接口中通常写各种形象办法,但只申明,不能写办法体。

public interface Runnable {/*public abstract*/ void run();
}

(三)不用将办法申明为 public abstract,在接口中的所有办法都默认的是public abstract 润饰。

(四)接口中不能有成员变量、动态代码块。

(五)接口中能够含有常量,常量默认是 public static final 润饰。

public interface Runnable {
   /*public static final*/ int i = 1;
    void run();}

(六)类通过 implements 关键字 实现接口,必须同时实现接口中的所有办法。

public class Dog implements Runnable {
    @Override
    public void run() {System.out.println("跑得飞快");
    }
    
    //......
}

(七)如果实现接口的类是抽象类,能够不必实现接口中的办法。

(八)一个类能够同时继承类和实现接口。

public class Dog extends Animal implements Runnable {//......}

(九)一个类能够实现多个接口。

public class Dog implements Runnable, Flyable {//......}

(十)接口之间能够继承,并且容许多继承。

public interface A {//......}

public interface B extends A, Runnable{//......}

(十一)接口不能被实例化,然而能够申明一个接口变量。

Runnable runnable = new Runnable();//'Runnable' is abstract; cannot be instantiated
Runnable runnable;// 接口变量,可行

3. 总结

抽象类用 abstract 关键字申明,抽象类中除了能够有形象办法(用 abstract 关键字申明)外,还能够有一般类的成员变量、结构器、办法。不能被实例化,但能够申明抽象类的变量。子类继承抽象类要实现父类的形象办法(如果子类是形象的,则不必实现)。

接口用 interface 关键字申明,接口中只能有形象办法、常量(疏忽修饰符)。不能被实例化,但能够申明接口变量。接口之间能够继承,且容许多继承。类实现接口应用 implements 关键字,且必须实现接口中的形象办法(如果类是形象的,则不必实现)。

总结了抽象类和接口的特点,发现抽象类如同也能作为“接口”应用。那有了抽象类,为什么还要有接口?

类只能单继承,如果应用抽象类作为“接口”,这意味着一个类只能恪守一份“接口”,显然不符合实际。而接口则灵便多了。

4. 对于我

如有谬误,还请斧正。

退出移动版