文章目录
抽象类和接口
技能目标:
掌握抽象类和抽象方法
掌握接口的用法
理解面向对象的设计原则
1.1初始抽象类和抽象方法
1.区分普通方法和抽象方法
在Java中,当一个类的方法被abstract关键字修饰的时候,被称为抽象方法。抽象方法所在的类必须定义为抽象类。
当一个方法被定义为抽象方法后,意味着该方法不会有具体的实现(没有方法体)。而是在抽象类的子类中通过方法重写进行实现,定义抽象方法的语法格式:
[访问修饰符] abstract<返回类型> <方法名>([参数列表]);
普通方法和抽象方法的相比,主要有两点区别:
a.抽象方法需要用abstract修饰,普通方法不需要
b.普通方法有方法体,抽象方法没有方法体
2.区分普通类和抽象类
在java中,当一个类被abstract关键字修饰时,该类被称为抽象类.
定义抽象类的语法格式:
abstract class <类名>{
}
普通类和抽象类的区别:
1.抽象类需要abstract 修饰,普通类不需要
2.普通类可以实例化,抽象类不能实例化
3.定义一个抽象类
当一个类被定义为抽象类,它可以包含各种类型的成员,包括属性、方法,其中方法又分为普通方法和抽象方法。
抽象类的结构:
public abstract class 类名称{
访问修饰符 返回类型 方法名(){
方法体
}
}
注意:
抽象方法只能定义在抽象类,但是抽象类中可以包含抽象方法,也可以包含普通方法,还可以包含普通类的一切成员
1.2使用抽象来描述抽象的事物
例:
分析:不可以直接实例化咱们的抽象类,但是它的子类是可以实例化,如果子类中没有重写pirnt(),子类将继承
父类Pet的该方法,默认调用父类的print()方法
package Test3;
/**
* @作者:Xem626
* @date: 2022/7/13 14:31
* @TODO
*/
public abstract class Pet {
private String name="无名氏";
private int health=100;
private int love=0;
public Pet(String name){
this.name=name;
}
// public void print(){
// System.out.println("宠物的自白:\n我的名字叫"+this.name+",健康值"+this.health+",和主人的亲密度"+love);
//
// }
public abstract void print();
}
package Test3;
/**
* @作者:Xem626
* @date: 2022/7/13 14:39
* @TODO
*/
public class Dog extends Pet {
private String strain;//品种
public Dog(String name, String strain) {
super(name);
this.strain = strain;
}
public void print() {
System.out.println("我是一只什么狗:" + strain);
}
}
package Test3;
/**
* @作者:Xem626
* @date: 2022/7/13 14:36
* @TODO
*/
public class Test1 {
public static void main(String[] args) {
// Pet pet=new Pet();抽象类不能实例化
Dog dog=new Dog("狗狗","小黄");
dog.print();
}
}
1.3初始接口
1.生活中的接口
在现实生活中,USB接口实际上是某些企业和组织制定的一种约定或标准,规定了接口的大小,形状等。按照该约定设计的各种设备,如U盘、USB风扇、USB键盘都可以插到USB接口上正常工作。USB接口相关工作是按照如下步骤进行的。
a.约定USB接口的标准
b.制作符合USB接口约定的各种具体设备
c.把USB设备插到USB接口上进行工作
Java中接口的作用和生活中的接口类似,它提供了一种约定,使得实现接口的类(或结构)在形式上保持一致。
如果抽象类中所得方法都是抽象方法,就可以使用Java提供的而接口来表示。从这个角度来讲,接口可以看作一种特殊的“抽象类”,但是采用与抽象类完全不同的语法表示,两者的设计理念也不同。
2.定义和实现一个简单的接口
通俗的来说,接口是一个不能实例化的类型,接口类型的定义的语法格式:
public interface 接口名{
//接口成员
}
和抽象类的不同:定义接口使用的关键是interface修饰,访问修饰符只能是public
接口中的成员可以是全局常量和公共的抽象方法。
实现接口的语法 :
public 类名 implements 接口名{
实现方法
普通方法
}
a.实现接口使用implements关键字
b.实现接口的类必须实现接口中定义的所有的抽象方法。接口的实现类允许包含普通的方法。
3.更复杂的接口
接口本身也可以继承接口
接口继承的语法格式:
【访问修饰符】 interfance 接口名 extends 父类接口1,父接接口2,...{
常量的定义
方法的定义
}
一个普通类只能继承一个父类,但是能同时实现多个接口,也可以同时继承抽象类和实现接口:
实现多接口的语法格式:
class 类名 extends 父类名 implements 接口1,接口2,...{
}
接口:
package Test3;
public interface UsbInterface {
public void service();
}
实现类:
package Test3;
/**
* @作者:Xem626
* @date: 2022/7/13 15:18
* @TODO
*/
public class UDisk implements UsbInterface{
@Override
public void service() {
System.out.println("连接数据接口,开始传输");
}
}
package Test3;
/**
* @作者:Xem626
* @date: 2022/7/13 15:22
* @TODO
*/
public class UsbFan implements UsbInterface {
@Override
public void service() {
System.out.println("连接成功,风扇开始转动");
}
}
测试:
package Test3;
/**
* @作者:Xem626
* @date: 2022/7/13 15:19
* @TODO
*/
public class Test2 {
public static void main(String[] args) {
//实例化接口的实现类(UDisk()),可以返回接口的实例化对象,
//这个也是Java多态的一种应用
UsbInterface usbInterface= new UDisk();
usbInterface.service();
UsbInterface usbInterface1=new UsbFan();
usbInterface1.service();
}
}
注意:
关于定义和实现接口所要注意的地方
1.接口和类、抽象类是一个层次的概念,命名规则相同
2.修饰符如果是public ,则该接口再整个项目中可见,如果省略修饰符,该接口只在当前包中可见
3.接口中可以定义常量,不能定义变量,接口中的属性都默认用"public static final",即接口中的属性都是静态全局常量,接口中的常量必须在定义时给定初始值:
public static final int =3.14
int PI =3.14//在接口中,这两个定义语句效果相同
int PI;// 在接口中定义必须赋值初始化
d.接口中所有的方法都是抽象方法,接口中的方法默认时public
c.和抽象类一样,接口不能实例化,接口中不能有构造方法
e.类中只能继承一个父类,但是可以通过implements实现多个接口,一个类必须实现接口的全部方法,
否则必须定义为抽象类,若一个类在继承父类的同时又实现了多个接口,extends必须位于implements之前
案例:实现愤怒的小鸟
鸟叫接口:
package Test3;
public interface ShoutAbility {
public void shout();
}
嗷嗷叫实现类
package Test3;
/**
* @作者:Xem626
* @date: 2022/7/13 15:34
* @TODO
*/
public class AoShout implements ShoutAbility{
@Override
public void shout() {
System.out.println("嗷嗷叫");
}
}
喳喳叫
package Test3;
/**
* @作者:Xem626
* @date: 2022/7/13 15:35
* @TODO
*/
public class ZhaShout implements ShoutAbility{
@Override
public void shout() {
System.out.println("喳喳叫");
}
}
鸟类
package Test3;
/**
* @作者:Xem626
* @date: 2022/7/13 15:36
* @TODO
*/
public abstract class Bird {
//接口也是一个引用类型
ShoutAbility shoutAbility;
public Bird(ShoutAbility shoutAbility) {
this.shoutAbility = shoutAbility;
}
//叫的行为
public void shout(){
shoutAbility.shout();
}
//飞行
public void fly(){
System.out.println("弹射");
}
public void attack(){
}
}
爆炸鸟:
package Test3;
/**
* @作者:Xem626
* @date: 2022/7/13 15:39
* @TODO
*/
public class BoomBird extends Bird{
public BoomBird(ShoutAbility shoutAbility) {
super(shoutAbility);
}
//重写攻击方法
public void attack(){
System.out.println("弹射攻击");
}
}
分裂鸟
package Test3;
/**
* @作者:Xem626
* @date: 2022/7/13 15:40
* @TODO
*/
public class SplitBird extends Bird{
public SplitBird(ShoutAbility shoutAbility) {
super(shoutAbility);
}
@Override
public void attack() {
System.out.println("分裂攻击");
}
}
测试
package Test3;
/**
* @作者:Xem626
* @date: 2022/7/13 15:40
* @TODO
*/
public class Test {
public static void main(String[] args) {
AoShout aoShout = new AoShout();
ZhaShout zhaShout = new ZhaShout();
BoomBird boomBird=new BoomBird(zhaShout);
SplitBird splitBird=new SplitBird(aoShout);
boomBird.shout();
boomBird.attack();
splitBird.shout();
splitBird.attack();
}
}
1.4面向对象设计的原则
在实际开发过程中,遵循以下原则,会让代码更具灵活性,更能适应变化。
1.摘取代码中变化的行为,形成接口
例如,在“愤怒的小鸟”游戏中,鸟叫的行为变化性很大,有的鸟叫,有的鸟不叫。各种鸟的叫声也不一样,这种行为最好定义为接口。
2.多用组合,少用继承
在“愤怒的小鸟”游戏中,通过在抽象类鸟中包含鸟叫的属性来实现组合,有效地减少了代码冗余。
3、针对接口编程,不依赖于具体实现
如果对一个类型有依赖,应该尽量依赖接口,尽量少依赖子类。因为子类一旦变化代码变动的可能性大,而接口要稳定得多。在具体的代码实现中,体现在方法参数尽量使用接口,方法的返回值尽量使用接口,属性类型尽量使用接口等。
4.针对扩展开放,针对改变关闭
如果项目中的需求发生了变化,应该添加一个新的接口或者类,而不要去修改原有的代码。
需要说明的是,这4个面向对象的原则比较抽象,可以先记住它,然后在实际的面向对象开发中尝试应用这些原则,然后加深对这些原则的理解。
本章总结:
1.抽象方法使用abstract 修饰符,没有方法体。
2.抽象类使用abstract 修饰,不能被实例化
3.类只能继承一个类,但是可以实现多个接口。一个类要实现接口的全部方法,否则必须定义为抽象类
Java通过实现多个接口达到多重继承效果
4.接口表示一定约定,也表示一种功能,体现了约定和实现分离的原则。通过面向接口编程,可以降低代码之间的耦合性,提高代码的可扩展性,可维护性