Java抽象类与接口

一、抽象类的概念

通俗一点说,抽象类就是用abstract关键字进行修饰的类,不能直接实例化(为什么不能直接实例化?有些答案指出是因为抽象类中的抽象方法未实现,无法分配内存空间,为了安全,不允许直接实例化。但事实上,抽象类中可以只包含普通方法而不包含抽象方法,所以个人觉得这是由Java语法规定的,是一种设计上的需要,其目的是为了被子类继承)。一般情况下,抽象类会包含抽象方法,而抽象方法则是将普通方法的方法体去掉后并用关键字abstract修饰的方法。下面我们用一个例子来初步认识一下什么是抽象类。

abstract class Animal {//定义一个抽象类

	public void move() {//普通方法,即有方法体'{}'的方法
		System.out.println("动物都会移动");
	}
	
	public abstract void speak();//抽象方法,即没有方法体'{}'且被关键字abstract修饰的方法
}
二、抽象类的使用

既然抽象类无法直接实例化,那么该如何访问抽象类的非静态属性呢?答案是:当子类覆写父抽象类之中的全部抽象方法后(若没有全部覆写,则该子类也必须声明为抽象类),可通过实例化子类来间接的实例化父抽象类(调用父类构造方法),从而访问父抽象类中的非静态属性。如下示例展示了子类调用父抽象类构造方法的过程。

abstract class Animal {//定义一个抽象类

	public Animal() {
		System.out.println("Animal的构造方法");
	}
	
	public void move() {//普通方法,即有方法体'{}'的方法
		System.out.println("动物都会移动");
	}
	
	public abstract void speak();//抽象方法,即没有方法体'{}'且被关键字abstract修饰的方法
}

class Person extends Animal {//Person是抽象类Animal的子类,是一个普通类

	public Person() {
		System.out.println("Person的构造方法");
	}
	
	@Override
	public void speak() {//强制要求覆写
		System.out.println("人可以说话");
	}
}

public class Test {
	
	public static void main(String[] args) {
		Animal a = new Person();//在实例化子类的一个对象的同时也会实例化父抽象类
		a.move();
		a.speak();
	}
}

运行结果为:

Animal的构造方法
Person的构造方法
动物都会移动
人可以说话

此外,和普通类一样,顶级抽象类(外部抽象类)不能被private、protected和static关键字修饰,但内部抽象类可以被这些关键字修饰。同时,不管是顶级抽象类还是内部抽象类都不能被final关键字进行修饰(因为抽象类就是为了被继承而设计,若声明为final则表示不能被继承)。

三、接口的概念

在JAVA编程语言中,接口是一种抽象类型,以interface关键字来声明。接口没有构造方法,只包含常量和抽象方法,也就是说接口中的变量会被隐式地指定为public static final变量(并且只能是public static final变量),而方法则不能有方法体,并会被隐式地指定为public abstract方法(且只能是public abstract方法)。下面是接口定义的一个例子。

public interface DoorBell {//定义一个门铃接口

	double volume = 88.88;//会自动隐式的加上public static final,从而成为常量
	
	void ring();//不能有方法体,且会自动隐式的加上public abstract,从而成为抽象方法
}
四、接口的使用

接口的设计就是为了被子类实现或被其它接口继承,因此接口不能被final修饰。同时,private、protected和static关键字也不能修饰接口。子类可以实现多个接口,如下所示,首先我们增加一个Camera接口。

public interface Camera {//定义一个摄像头接口

	void film();
}

然后我们创建一个Door类来实现DoorBell和Camera接口。

public class Door implements DoorBell, Camera {//子类Door实现DoorBell和Camera两个接口

	@Override
	public void film() {//实现接口Camera的film()方法
		System.out.println("摄像功能");
	}

	@Override
	public void ring() {//实现接口DoorBell的ring()方法
		System.out.println("响铃功能");
	}
}

此外,接口可以继承多个接口。比如我们创建一个Attach接口来继承DoorBell和Camera接口,那么Attach接口将会继承DoorBell和Camera中的抽象方法。

public interface Attach extends Camera, DoorBell {//Attach接口继承Camera和 DoorBell两个接口
	
}

则原先Door类实现DoorBell和Camera两个接口就可以改为只实现Attach这个接口即可。

public class Door implements Attach {//子类Door实现Attach接口

	@Override
	public void film() {//实现接口Attach的film()方法
		System.out.println("摄像功能");
	}

	@Override
	public void ring() {//实现接口Attach的ring()方法
		System.out.println("响铃功能");
	}
}

五、抽象类与接口的区别

语言上的区别:

1、抽象类有构造方法,而接口没有构造方法

2、抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;

3、抽象类中可以包含普通方法,而接口中的方法只能是抽象方法

4、抽象类可以通过implements关键字继承接口,而接口不能继承抽象类

5、抽象类可以有静态代码块和静态方法,而接口中不能含有静态代码块以及静态方法

6、一个普通类只能继承一个抽象类,而一个普通类却可以实现多个接口

设计层面上的区别:

抽象类是对事物固有属性的一种抽象,而接口则是对附加行为的一种抽象。还是以Door(门)为例,所有的门都有形状和大小(面积),因此我们可以抽象出‘门’的共有属性(抽象类Property):形状和大小。

public abstract class Property {//定义一个抽象类表示'门'的共有属性

	abstract void shape();//形状
	
	abstract double getArea();//面积大小
}

可是,如果客户要求一张门需要门铃和摄像头怎么办呢?我们不能简单地把门铃和摄像头的功能方法写进抽象类Property中,因为并不是所有的门都有门铃和摄像头。正确的做法就是如前面描述的一样,把门铃和摄像头功能定义为Attach接口,表示附加功能。那么一张符合客户需求的Door就可以表示为:

public class Door extends Property implements Attach {//子类Door继承Property抽象类并实现Attach接口

	@Override
	void shape() {//继承并重写抽象类Property中的shape()方法
		System.out.println("我是长方形");
	}

	@Override
	double getArea() {//继承并重写抽象类Property中的getArea()方法
		return 1.88;
	}
	
	@Override
	public void film() {//实现接口Attach的film()方法
		System.out.println("摄像功能");
	}

	@Override
	public void ring() {//实现接口Attach的ring()方法
		System.out.println("响铃功能");
	}
}

你可能感兴趣的:(语言)