学习笔记——《Java面向对象程序设计》-抽象和接口
参考教材:
Java面向对象程序设计(第3版)微课视频版 清华大学出版社
抽象方法
抽象方法是使用abstract关键字修饰的成员方法,抽象方法在定义时不需要实现方法体。
抽象方法的定义格式如下:
abstract void 方法名称(参数);
当一个类包含了抽象方法,该类必须是抽象类。抽象类和抽象方法一样,必须使用abstract关键字进行修饰。 不允许使用final和abstract同时修饰一个方法或类。
抽象类
抽象类的定义规则如下:
(1)包含一个以上抽象方法的类必须是抽象类。
(2)抽象类和抽象方法都要使用abstract关键字声明。
(3)抽象方法只需声明而不需要实现;abstract类不能用new运算符创建对象。
(4)如果一个非abstract类继承了抽象类,必须重写父类的abstract方法,即去掉abstract方法的abstract修饰,并给出方法体。
(5)如果一个abstract类继承了抽象类,也可以继承父类的方法。
// 定义抽象类Animal
abstract class Animal {
// 定义抽象方法shout()abstract void shout();
}
// 定义Dog类继承抽象类Animal
class Dog extends Animal {
// 实现抽象方法shout()void shout() {System.out.println("汪汪...");}
}public class Example10 {public static void main(String[] args) {Dog dog = new Dog(); // 创建Dog类的实例对象dog.shout(); // 调用dog对象的shout()方法}
}
注意:使用abstract关键字修饰的抽象方法不能使用private修饰,因为抽象方法必须被子类实现,如果使用了private声明,则子类无法实现该方法。
abstract类的对象作为上转型对象
抽象类可以抽象出重要的行为标准,该行为用抽象方法来表示。即抽象类封装了子类必需有的行为标准。
抽象类声明的对象可以作为其子类的对象的上转型对象,调用子类重写的方法,即体现子类根据抽象类里的行为标准给出的具体行为。
//抽象类定义女友行为标准
abstract class GirlFriend { abstract void speak(); abstract void cooking();
}//中国女友具体实现
class ChinaGirlFriend extends GirlFriend {void speak() {System.out.println("你好"); // 中文问候}void cooking() {System.out.println("水煮鱼"); // 中式菜品}
}//美国女友具体实现
class AmericanGirlFriend extends GirlFriend {void speak() {System.out.println("hello"); // 英文问候}void cooking() {System.out.println("roast beef"); // 西式菜品}
}class Boy {GirlFriend friend; //抽象类声明friend对象void setGirlfriend(GirlFriend f) {friend = f; }void showGirlFriend() {friend.speak(); friend.cooking(); }
}public class Example5_11 {public static void main(String args[]) {//抽象类声明的对象girl,成为子类ChinaGirlFriend的对象的上转型对象GirlFriend girl = new ChinaGirlFriend();//girl就可以调用子类中的重写方法Boy boy = new Boy(); // 设置中国女友并展示行为boy.setGirlfriend(girl);boy.showGirlFriend();// 切换为美国女友的上转型对象girl = new AmericanGirlFriend();boy.setGirlfriend(girl);boy.showGirlFriend();}
}
接口
Java不支持多继承,即一个类只能有一个父类。单继承性使得java简单,易于管理程序。为了克服单继承的缺点,Java使用了接口,一个类可以实现多个接口。
1、接口的定义
使用关键字interface来定义一个接口。接口的定义和类的定义很相似。分为接口声明和接口体。
interface Com{...
}
(1)接口体中的抽象方法和常量
interface Printable{public static final int MAX = 100; //等价于 int MAX = 100;public abstract void add(); //等价于 void add();public abstract float sum(float x,float y); //等价于 float sum(float x,float y);
}
接口里不会有变量
(2)接口里可以定义抽象方法,但是不能有方法体;
(3)Java8之后,接口体中的default实例方法,default方法一定是public方法(public可省略)
interface Printable{public static final int MAX = 100; //等价于 int MAX = 100;public abstract void add(); //等价于 void add();public abstract float sum(float x,float y); //等价于 float sum(float x,float y);default int max(int a,int b) {return a+b;}
}
(4)接口中的static方法,允许再接口体中定义static方法
static和default不能同时修饰一个方法;
static和abstract也不能同时修饰一个方法;
interface Printable{public static final int MAX = 100; //等价于 int MAX = 100;public abstract void add(); //等价于 void add();public abstract float sum(float x,float y); //等价于 float sum(float x,float y);default int max(int a,int b) {return a+b;}public static void f() {System.out.println("注意是从Java SE 8开始的");}
}
2、接口的使用
(1)可以用接口名访问接口的常量、调用接口中的static方法
(2)类实现接口
类通过使用关键字implements声明自己实现一个或多个接口
修饰符 class 类名 implements 接口1,接口2,...{...
}
一个类实现了某个接口,那么这个类就自然拥有了接口中的常量;
该类也可以重写接口中的default方法(注意,重写时需要去掉default关键字),但不自然拥有接口里的static方法
一个非abstract类实现了某个接口,那么这个类就必须重写该接口的所有abstract方法,去掉abstract修饰,并给出方法体;
一个abstract类实现了某个接口,该类可以重写接口的abstract方法,或直接拥有接口的abstract方法
要注意的是:接口中的方法的访问权限都是public的,重写时不可省略public
// 定义接口Animal
interface Animal {int ID = 1; // 定义全局常量String NAME = "牧羊犬";void shout(); // 定义抽象方法shout()static int getID(){ // 定义静态方法getID()return Animal.ID;
}public abstract void info(); // 定义抽象方法
}
// 定义接口Action
interface Action {public void eat(); // 定义抽象方法eat()
}
// 定义Dog类实现Animal接口和Action接口
class Dog implements Animal,Action{
// 重写Action接口中的抽象方法eat()public void eat() {System.out.println("喜欢吃骨头");}
// 重写Animal接口中的抽象方法shout()public void shout() {System.out.println("汪汪...");}
// 重写Animal接口中的抽象方法info()public void info() {System.out.println("名称:"+NAME);}
}
// 定义测试类
class Example11 {
public static void main(String[] args) {System.out.println("编号"+Animal.getID());Dog dog = new Dog(); // 创建Dog类的实例对象dog.info();dog.shout(); // 调用Dog类中重写的shout()方法dog.eat(); // 调用Dog类中重写的eat()方法}}
(3)如果在开发中一个子类既要实现接口又要继承抽象类,则可以按照以下格式定义子类。
修饰符class 类名 extends 父类名implements 接口1,接口2,... {...
}
在Java中,接口是不允许继承抽象类的,但是允许一个接口继承多个接口。
abstract类与接口的比较
(1)abstract类和接口都可以有abstract方法
(2)接口中只可以有常量,不能有变量;而abstract类中即可以有常量也可以有变量
(3)abstract类中也可以非abstract方法,但不可以有default实例方法。接口不可以有非abstract的方法(不是default方法,还带有方法体的方法),但可以有default实例方法。