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

相关文章:java

  1. 《面向对象再探究》:介绍了面向对象的基本概念
  2. 《详解Java的对象建立》:介绍了对象的建立、构造器的使用
  3. 《一文打尽Java继承的相关问题》:介绍了继承的使用方式和注意事项

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

1. 抽象类

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

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

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()方法。code

动物是一个很宽泛的概念,若是写代码表示,咱们日常见到的大部分生物均可以继承该类。以下图:对象

有这么多类继承Animal类,那Animal类的say()方法这样写合适吗?由于每种动物说话的方式都不一样,而动物又是这么宽泛的一个概念,咱们一般会new Dog()new People(),但不多会去new Animal()blog

因此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. 关于我

若有错误,还请指正。

相关文章
相关标签/搜索