今日学习目标:抽象类和接口
创作者:颜颜yan_
✨个人主页:颜颜yan_的个人主页
⏰本期期数:第二期
专栏系列:JAVA
定义一个类时常常需要定义一些成员方法用于描述类的行为特征,但有时这些方法的实现方式是无法确定的。例如上期定义的 Animal类中的 shout()方法用于描述动物的叫声,但是不同的动物叫声也不相同,因此在 shout()方法中无法准确描述动物的叫声。
针对上面描述的情况,Java 提供了抽象方法来满足这种需求。抽象方法是使用abstract 关键字修饰的成员方法,抽象方法在定义时不需要实现方法体。
抽象方法的语法格式如下:
abstract 返回值类型 方法名称(参数列表);
当一个类包含了抽象方法,该类就是抽象类。抽象类和抽象方法一样,必须使用abstract 关键字进行修饰。抽象类的语法格式如下:
abstract class 抽象类名称{
属性;
访问权限 返回值类型 方法名称(参数){ //普通方法
return [返回值];
}
访问权限 abstract 返回值类型 抽象方法名称(参数); //抽象方法,无方法体
}
从上面抽象类的语法格式中可以发现,抽象类的定义比普通类多了一个或多个抽象方法,其他地方与普通类的组成基本相同。
(1)包含抽象方法的类必须是抽象类
(2)声明抽象类和抽象方法时都要使用== abstract== 关键修饰。
(3)抽象方法只需要声明而不需要实现。
(4)如果一个非抽象类继承了抽象类之后,那么该类必须重写抽象类中的全部抽象方法。
Animal类:
//定义抽象类Animal
abstract class Animal {
//定义抽象方法shout()
abstract void shout();
}
Dog类:
//定义Dog类继承抽象类Animal
class Dog extends Animal{
//重写抽象方法shout()
@Override
void shout() {
System.out.println("汪汪汪……");
}
}
测试类:
//定义测试类
public class Main {
public static void main(String[] args) {
Dog dog = new Dog(); //创建Dog类的对象
dog.shout(); //通过dog对象调用shout()方法
}
}
在上述代码中,声明了Animal抽象类,在Animal中定义了抽象方法shout();在Dog类中重写了父类Animal类的抽象方法shout();在测试类中创建了Dog对象,并使用Dog对象调用shout()方法,实现控制台输出的“汪汪汪……”信息。
控制台输出信息如下图:
由上图可知,控制台输出“汪汪汪……”,说明了dog对象调用了Dog类中重写的父类Animal的抽象方法shout()。
使用 abstract 关键字修饰的抽象方法不能使用 private 关键字修饰,因为抽象方法必须被子类实现,如果使用了 private 关键字修饰抽象方法,则子类无法实现该方法。
==接口是一种用来定义程序的协议,它用于描述类或结构的一组相关行为。==接口是由抽象类衍生的一个概念,并由此产生了一种编程方式,可以称这种编程方式为面向接口编程。面向接口编程就是将程序的不同的业务逻辑分离,以接口的形式对接不同的业务模块。按口中不实现任何业务逻辑,业务逻辑由接口的实现类完成。当业务需求变更时,只需要修改实现类中的业务逻辑,而不需要修改接口中的内容,以减少需求变更对系统产生的影响。
下面通过现实生活中的例子来类比面向接口编程。例如,鼠标、U 盘等外部设备通过USB 接口来连接计算机,即插即用,非常灵活。如果需要更换与计算机连接的外部设备,只需要拔掉当前 USB 接口上的设备,把新的设备插入即可,这就是面向接口编程的思想。
在Java 中,使用接口的目的是克服单继承的限制,因为一个类只能有一个父类,而一个类可以同时实现多个父接口。在JDK 8之前,接口是由全局常量和抽象方法组成的。JDK 8对接口进行了重新定义,接口中除了抽象方法外,还可以定义默认方法和静态方法,默认方法使用 default 关键字修饰,静态方法使用 static 关键字修饰,而且这两种方法都允许有法体。
接口使用 interface 关键字声明,语法格式如下:
[public] interface 接口名 [extends 接口1,接口2,..]{
[public][static] [final] 数据类型 常量名 =常量;
[public] [abstract] 返回值的数据类型 方法名(参数列表);
[public] static 返回值的数据类型 方法名(参数列表){}
[public] default 返回值的数据类型 方法(参数列表){}
}
上述语法格式中,“extends 接口1,接口2,…”表示一个接口可以有多个父接口,父接口之间使用逗号分隔。接口中的变量默认使用 public static final 进行修饰,即全局常量。接口中定义的抽象方法默认使用 public abstract 进行修饰。
在很多的 Java 程序中,经常看到编写接口中的方法时省略了 public,有很多读者认为它的访问权限是 default,这实际上是错误的。不管写不写访问权限,接口中方法的访问权限永远是 public。
接口本身不能直接实例化,接口中的抽象方法和默认方法只能通过接口实现类的实例对象进行调用。实现类通过== implements== 关键字实现接口,并且实现类必须重写接口中所有的抽象方法。需要注意的是,一个类可以同时实现多个接口,实现多个接口时,多个接口名需要使用英文逗号(,)分隔。
定义接口实现类的语法格式如下:
修饰符 class 类名 implements 接口 1,接口 2,……{
……
}
Animal接口:
//定义接口Animal
interface Animal {
int ID = 1; //定义全局常量,编号
String NAME ="牧羊犬"; //定义全局常量,名称
void shout(); //定义抽象方法 shout()
public void info(); //定义抽象方法 info()
static int getID(){ //定义静态方法 getID(),用于返回 ID值
return Animal.ID;
}
}
Action接口:
interface Action {
public void eat();
}
Dog类:
//定义Dog类实现抽象类Animal和Action
class Dog implements Animal,Action{
//重写抽象方法shout()
@Override
public void shout() {
System.out.println("汪汪汪……");
}
//重写Animal接口中的抽象方法info()
@Override
public void info() {
System.out.println("名称:"+NAME);
}
//重写Action接口中的抽象方法eat()
@Override
public void eat() {
System.out.println("喜欢吃骨头");
}
}
测试类:
//定义测试类
public class Main {
public static void main(String[] args) {
System.out.println("编号:"+Animal.getID());
Dog dog = new Dog(); //创建Dog类的对象
dog.info(); //调用Dog中重写的info()方法
dog.shout(); //调用Dog中重写的shout()方法
dog.eat(); //调用Dog中重写的eat()方法
}
}
在上述代码中,定义了 Animal接口,在Animal接口中定义了全局常量ID和NAME、抽象方法 shout()、info()和静态方法 getID()。定义了Action接口,在Action 接口中定义了抽象方法 eat(),用于输出信息“喜欢吃骨头”。定义了Dog类,Dog 类通过implements关键字实现了Animal接口和Actio接口,并重写了这两个接口中的抽象方法。使用 Animal 接口名直接访问了Animal接口中的静态方法 getID(),输出编号信息。测试代码中创建了 Dog 类的象 dog,并通过 dog 对象调用重写的 info()方法、shout()方法以及 eat()方法。
需要注意的是,接口的实现类必须实现接口中的所有抽象方法,否则程序编译报错。
上述代码演示的是类与接口之间的实现关系。如果在开发中一个子类既要实现接口又要继承抽象类,则可以按照以下语法格式定义子类
修饰符 class 类名 extends 父类名 implements 接口 1,接日2,……{
……
}
下面对上述代码稍加修改,演示一个类既可以实现接口又可以继承抽象类的情况。修改后的代码如下:
Animal接口:
//定义接口Animal
interface Animal {
public String NAME ="牧羊犬"; //定义全局常量,名称
public void shout(); //定义抽象方法 shout()
public void info(); //定义抽象方法 info()
}
}
Action接口:
//定义抽象类Action
interface Action {
ppublic abstract void eat(); //定义抽象方法eat()
}
Dog类:
//定义Dog类继承Action抽象类,并且实现Animal接口
class Dog extends Animal,Action{
//重写Action接口中的抽象方法eat()
@Override
public void eat() {
System.out.println("喜欢吃骨头");
}
//重写Animal中的抽象方法shout()
@Override
public void shout() {
System.out.println("汪汪汪……");
}
//重写Animal接口中的抽象方法info()
@Override
public void info() {
System.out.println("名称:"+NAME);
}
}
测试类:
//定义测试类
public class Main {
public static void main(String[] args) {
System.out.println("编号:"+Animal.getID());
Dog dog = new Dog(); //创建Dog类的对象
dog.info(); //调用Dog中重写的info()方法
dog.shout(); //调用Dog中重写的shout()方法
dog.eat(); //调用Dog中重写的eat()方法
}
}
在上述的代码中,定义了Animal接口,其中声明了全局变量NAME(名称)和抽象方法 shout()info()。定义了抽象类 Action,其中定义了抽象方法 eat()。定义了 Dog 类,它通过 extends 关键字继承了 Action 抽象类同时通过 implements 重写了 Animal接口。Dog 类重写了 Animal 接口和 Action 抽象类中的所有抽象方法,包括 shout()方法、info()方法和 eat()方法。测试类代码创建了Dog 类对象 dog,通过该对象分别调用了 ino()、shout()和 eat()方法。
运行结果如图所示:
由图 可知,控制台输出“名称: 牧羊犬”和“汪汪…”,证明 Dog 类成功重写Animal接口的 info()方法和shout()方法;控制台输出“喜欢吃骨头”,证明 Dog 类成功Action 抽象类的 eat()方法。这说明,Dog 类的实例化对象可以访问该类实现的接F抽象类的方法。
在 Java 中,接口不允许继承抽象类,但是允许接口继承接口,并且一个接口可以同时继承多个接口。
Animal接口
//定义接口Animal
interface Animal {
public String NAME ="牧羊犬"; //定义全局常量,名称
public void info(); //定义抽象方法 info()
}
Action接口:
//定义Action接口,同时继承Animal接口和Color接口
interface Action extends Animal,Color {
public abstract void shout();
}
Dog类:
//定义Dog类实现Action接口
class Dog implements Action{
//重写Animal接口中的抽象方法info()
@Override
public void info() {
System.out.println("名称:"+NAME);
}
//重写抽象方法shout()
@Override
public void shout() {
System.out.println("汪汪汪……");
}
//重写Color接口中的抽象方法black
@Override
public void black() {
System.out.println("黑色");
}
}
测试类:
//定义测试类
public class Main {
public static void main(String[] args) {
Dog dog = new Dog(); //创建Dog类的对象
dog.info(); //调用Dog中重写的info()方法
dog.shout(); //调用Dog中重写的shout()方法
dog.black(); //调用Dog中重写的black()方法
}
}
上述代码中,定义了 Action 接口并继承 Animal 接口和Color接口,这样 Action 接口中就同时拥有 Animal 接口中的 info()方法、NAME属性和 Color接口中的 black()方法以及本接口中的 shout()方法。
定义了 Dog 类并实现了 Action 接口,这样 Dog 类就必须同时重写Animal 接口中的抽象方法 info()、Color 接口中的抽象方法 black()和 Action 接口中的抽象方法 shout()。
测试代码创建了 Dog 类的对象 dog,通过 dog 对象调用重写的 shout()方法info()方法和 black()方法。
代码的运行结果如图:
由图 可知,控制台输出“名称:牧羊犬”,证明 Dog 类成功重写了 Action 接口继承自Animal接口的抽象方法 info();控制台输出“汪汪…”,证明 Dog 类成功重写了 Action接口的抽象方法 shout();控制台输出“黑色”,证明 Dog 类成功重写了 Ation 接口继承自Color 接口的抽象方法 black()。
以上就是今天的学习内容啦~
如果有兴趣的话可以订阅专栏,持续更新呢~
咱们下期再见~