抽象类
顾名思义,一个类代表一个抽象体,本身没有足够的定义能使其成为能完全代表对象的类。
抽象类让其子类继承它的属性和方法,避免子类重复定义这些内容,抽象父类只声明方法的参数和返回类型,具体实现由子类完成。
在类名前面加上abstract关键字来声明一个抽象类。
-
本身没有足够的定义能使其成为能完全代表对象的类可以声明为抽象类,例如说把呼吸可以定义一个类,这本身太宽泛了,我们可以把它定义为抽象类,由狗尾草类、狮子类继承呼吸类,狗尾草类和狮子类具体实现各自如何呼吸的,动物和植物的呼吸作用有差异,但却可以继承自同一个父类,也是多态的一种表现。第二个例子:可以定义一个抽象父类万能遥控器类,由子类空调遥控器类和电视机遥控器类继承。
-
包含抽象方法的类必须声明为抽象类
-
继承抽象类的子类必须覆盖实现父类所有的抽象方法,如果没有实现抽象父类的所有抽象方法,则此子类也必须声明为抽象类。
-
抽象类不能实例化对象,不能用new来实例化对象
-
抽象类可以继承自非抽象类
抽象方法
在方法前加上abstract来声明一个抽象方法,抽象方法只有原型的声明没有具体的实现内容
-
不能用final修饰,因为子类不能重写final方法
-
不能用static修饰,因为static方法可以通过类名调用,但抽象方法没有实现代码,抽象的static方法没有任何意义。
-
构造方法不能声明为abstract,因为构造方法不能被继承
-
存取限制符必须为public或protected
代码是我自己写的可能有不太正确的地方,敬请批评指正
package pc;
public class demo1 {
public static void main(String[] args) {
master m = new master("jack", 22, "tut"); // 实例化类master
m.printInfo();
m.printB();
m.fun();
doctor d = new doctor("Smith", 23, "tut"); // 实例化类doctor
d.printInfo();
d.printB();
d.fun();
// 一种使用方法:使用指向父类的引用变量来存取子类对象
People p = new doctor("Smith", 23, "tut");
p = new master("jack", 22, "tut");
p.printInfo();
}
}
/*
结果:
我是master jack
抽象方法需要被覆盖
普通方法
我是doctor Smith
抽象方法需要被覆盖
普通方法
我是master jack
*/
abstract class People{ // 定义抽象基类People
String name;
People(String name){ // 构造函数
this.name=name;
}
abstract public void printInfo(); // 定义抽象方法 abstract和public的顺序 谁在前都可以 我习惯先写abstract
}
abstract class Student extends People{ // 定义抽象类Student继承抽象类People
int age;
Student(String name, int age){
super(name); // 调用父类的构造方法
this.age=age;
}
abstract public void printB();
public void fun(){ // 定义普通方法
System.out.println("普通方法");
}
}
class master extends Student{ // 定义普通类master继承抽象类
String college;
master(String name, int age, String college){
super(name, age);
this.college=college;
}
@Override
public void printInfo() { // 覆盖抽象类的抽象方法
System.out.println("我是master " + name);
}
@Override
public void printB() { // 覆盖抽象类的抽象方法
System.out.println("抽象方法需要被覆盖");
}
}
class doctor extends Student{ // 定义普通类doctor继承抽象类
String college;
doctor(String name, int age, String college){
super(name, age);
this.college=college;
}
@Override
public void printInfo() { // 覆盖抽象类的抽象方法
System.out.println("我是doctor " + name);
}
@Override
public void printB() { // 覆盖抽象类的抽象方法
System.out.println("抽象方法需要被覆盖");
}
}
接口
在实现语法上,接口与抽象类没有什么差别。
java只支持单继承机制,即一个类只能有一个父类,不支持c++语言中的多继承。但java提供了接口可用于实现多继承,一个类可以实现多个接口,一个接口可以继承多个接口。
-
接口不能被实例化
-
实现接口的类必须覆盖实现接口中的所有抽象方法,如果没有实现接口的所有抽象方法,则此子类也必须声明为抽象类
-
接口中所有抽象方法都隐含为public abstract方法
-
接口中所有常量都隐含为pubic static final,所以接口中的成员变量都必须先初始化,而且不能再被修改
-
jdk8以前,接口中只允许有常量和抽象方法,jdk8中允许定义非抽象方法,包括默认方法和静态方法,默认方法和静态方法有方法体且必须有方法体。
默认方法
默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法。
在方法前加上default来声明一个默认方法
-
默认方法有方法体且必须有方法体
-
默认方法又称为虚拟扩展方法或defender方法
-
接口中的默认方法实现类可以直接使用,也可以将其覆盖
-
如果一个类实现了两个接口,但这两个接口里有同名的default方法,就必须在实现类中覆盖冲突的方法
-
通过默认方法,可以方便的修改已经存在的接口而不影响现有的实现架构。
静态方法和默认方法的例子:
package pc;
public class demo2 {
public static void main(String[] args) {
boy b = new boy();
b.printInfo();
b.default_fun();
man.static_fun(); //静态方法的调用方式
}
}
/*
结果:
我是一个boy
这是children类中的default方法
这是man类中的static方法
*/
interface man {
// public static final String sex="男"; // 修饰符 'public' 'static' 'final' 对于接口字段是冗余的
String sex="男"; // 定义常量
// abstract public void printInfo(); //修饰符 'abstract' 'public' 对于接口方法是冗余的
void printInfo(); // 定义抽象方法
static void static_fun(){ // 定义static方法
System.out.println("这是man类中的static方法");
}
}
interface children {
String age = "Younger"; // 定义常量
default void default_fun(){ // 定义default方法
System.out.println("这是children类中的default方法");
}
}
class boy implements man, children{ // 实现man 和 children 两个接口。这还可以在实现接口的同时再继承一个类
@Override
public void printInfo() { // 重写抽象方法
System.out.println("我是一个boy");
}
}
// 下面是接口继承接口的形式
interface test extends man{
}
普通类 | 抽象类 | 接口 | |
---|---|---|---|
组成 | 不能有抽象方法 | 变量、抽象方法、普通方法、静态方法 | 常数、抽象方法、默认方法(jdk8+)、静态方法(jdk8+) |
非抽象子类必须覆盖实现抽象父类所有的抽象方法 | 实现接口的非抽象子类必须覆盖接口中的所有抽象方法 | ||
能被实例化 | 不能被实例化 | 不能被实例化 | |
有构造方法 | 有构造方法 | 没有构造方法 |
本文部分内容参考《深入浅出java程序设计》朱颢东 张志峰等编制、《java程序设计与计算思维》赵军 吴灿铭等编著、《java程序设计教程》(第九版)John Lewis William Loftus 著 洛基山 张君施等译