Java入门——抽象类与接口,6千字攻略

目录

抽象类

引言

概念

 Java中定义抽象类或者抽象方法使用 abstract 关键字声明

1. 抽象方法所在的类必须使用 abstract 声明为抽象类。

2. 若一个类使用 abstract 声明为抽象类,无法直接通过该类实例化对象。

3. 子类继承了抽象类,就必须强制子类覆写抽象类中的所有抽象方法(子类是普通类)。子类若是抽象类,可以选择性的覆写父类的抽象方法。

4. 抽象类是普通类的超集

5. 在定义抽象方法时,abstract和final能否同时出现?

6. 在定义抽象类时,abstract和final能否同时出现?

接口

引言

概念

1. 接口表示一种规范或者标准

2. 接口表示具备某种能力或行为

3. 接口和类之间的关系

接口的命名规范


抽象类

引言

现在有这样的需求∶描述形状的类Sharp。子类:三角形,正方形,圆形。
要求:创建一个方法可以接受 Sharp 以及其所有子类的对象,调用print()

向上转型用在方法参数 

//Crycle.java   Crycle类单独的java文件
public class Crycle extends Sharp {
    // 快速覆写的快捷键
    // alt + insert 或者直接写方法名
    @Override
    public void print() {
        System.out.println("⚫");
    }
}
//Triangle.java   Triangle类单独的java文件
public class Triangle extends Sharp {
    public void print() {
        System.out.println("🔺");
    }
}
//Square.java   Square类单独的java文件
public class Square extends Sharp {
    @Override
    public void print() {
        System.out.println("⬛");
    }
}
//Test.java   Test类单独的java文件
public class Test {
    public static void main(String[] args) {
        fun(new Crycle());
        fun(new Square());
        fun(new Triangle());
    }
    public static void fun(Sharp sharp) {
        //这个方法可以接受所有Sharp类,调用其print打印图形
        sharp.print();
    }
}

若新建子类 Diamond,子类没有覆写 print 方法。

执行 fun(new Diamond()); 则不会打印。

package interface_Test.sharp;
public class Diamond extends Sharp{
}

概念

若需要强制要求子类覆写方法,就要用到抽象类
现实生活中有很多的抽象类,这些类都是概念化的,没法具体到某个实例。这类抽象类可以描述这一类对象共同的属性和行为。

例如:人类——>抽象类,没法对应到具体某个或者某一类人。中国人,日本人,印第安人,智人等都是人类。

此时 Sharp 类,包括 Sharp 类的 print() 方法都是抽象概念,应该设置为抽象类。


抽象类是普通类的"超集",只是比普通类多了一些抽象方法(0~n个)。换言之,普通类有的抽象类全有。

抽象方法所在的类必须是抽象类,子类若继承了抽象类,必须覆写所有抽象方法(前提:子类是普通类)。

 Java中定义抽象类或者抽象方法使用 abstract 关键字声明

1. 抽象方法所在的类必须使用 abstract 声明为抽象类。

抽象方法指的是使用 abstract 关键字声明(只有方法声明,没有方法体)。它在抽象类中没有实现,延迟到子类实现。

//一个类若存在抽象方法,必须使用 abstract 声明为抽象类
public abstract class Sharp {    
    public abstract void print();//只有方法声明,没有方法体{}
}

问题:Java中没有方法体的方法就是抽象方法。
答:错误,本地方法不是抽象方法它也没有方法体。

本地方法,不是抽象方法,这个方法由 JVM 实现,JVM是C++写的。
本地方法指的就是Java 通过JNDI(本地方法平台)调用C++的同名方法。

2. 若一个类使用 abstract 声明为抽象类,无法直接通过该类实例化对象。

当一个类是抽象类,不管他有没有抽象方法,这个类本身就是一个抽象的概念,没法具体到某个特定的实例。

只能通过子类向上转型变为抽象父类的引用。

例如:形状 Sharp 是抽象类,无法创建对象。

Sharp sharp = new Sharp(); //错误

例如:人类 Person 是抽象类,China 类为其普通子类。
 

Person per = new Person(); //错误
Person per = new China();  //正确,向上转型

3. 子类继承了抽象类,就必须强制子类覆写抽象类中的所有抽象方法(子类是普通类)。子类若是抽象类,可以选择性的覆写父类的抽象方法。

此时满足单继承局限,一个子类只能 extends 一个抽象类。 

abstract class A {
    abstract void printA();
}

//B是抽象类,可以选择性的覆写父类A的抽象方法
abstract class B extends A {
    abstract void printB();
}

//普通类 C 是抽象类 B 的子类,必须覆写B中所有的抽象方法(包括继承来的方法)
public class C extends B {
    @Override
    void printB() {}
    @Override
    void printA() {}
}

4. 抽象类是普通类的超集

普通类有的内容,抽象类全都有,只是比普通类多了一些抽象方法而已

 

抽象类虽然没法直接实例化对象,但是也可以存在构造方法。子类在实例化时,仍然遵从继承的规则,先调用父类(抽象类)的构造方法,而后调用子类构造方法。


问题:求输出结果

abstract class BaseTest {
    public BaseTest() {
        this.print();
    }

    abstract void print();
}

public class Fun extends BaseTest {
    private int num = 10;

    @Override
    void print() {
        System.out.println("num = " + num);
    }

    public static void main(String[] args) {
        new Fun();
    }
}

答:

5. 在定义抽象方法时,abstract和final能否同时出现?

不能!抽象方法必须被覆写,final修饰的方法无法被覆写,二者相互矛盾。

6. 在定义抽象类时,abstract和final能否同时出现?

不能!抽象类必须得有子类,final修饰的类没有子类,二者相互矛盾。

接口

引言

抽象类虽然没法直接实例化对象,子类仍然满足 is a 原则,子类和抽象父类之间仍然是满足"继承树"的关系。

例如:Person 对于 China、Sharp 对于 Cycle 。


一般来说,接口的使用表示两种场景
1. 接口表示一种规范或者标准。例如:"USB接口",5G标准。
2. 接口表示具备某种能力或行为。子类实现接口时不是 is a,而是具备这种行为或者能力。
例如:"游泳"——>能力或者行为,Person 满足游泳接口,Dog 也能满足游泳接口,Duck 也能满足游泳接口。

概念

接口中只有全局常量和抽象方法——>更加纯粹的抽象概念。其他东西统统没有。

接口使用关键字 interface 声明接口,子类使用 implements 实现接口。

1. 接口表示一种规范或者标准

USB接口表示一种规范。

package interface_Test.usb;
//接口使用 interface 定义,只有全局常量、抽象方法
public interface USB {
    //插入
    public abstract void plugIn();
    //工作
    public abstract void work();
}

子类使用 implements 实现接口,必须覆写所有的抽象方法。

鼠标,键盘外设都属于USB接口的子类。

//Mouse.java   Mouse类单独的java文件
package interface_Test.usb;
public class Mouse implements USB{
    @Override
    public void plugIn() {
        System.out.println("安装鼠标驱动中");
    }
    @Override
    public void work() {
        System.out.println("鼠标可以正常工作了");
    }
}

//KetBoard.java   KeyBoard类单独的java文件
package interface_Test.usb;
public class KeyBoard implements USB{
    @Override
    public void plugIn() {
        System.out.println("安装键盘驱动中");
    }
    @Override
    public void work() {
        System.out.println("键盘可以正常工作了");
    }
}

电脑这个类算不算USB接口的子类?
所有带USB线插入到电脑的设备都应该满足USB规范。电脑是USB规范的使用者。

public class Computer {
    //参数为何使用USB引用?
    //fun方法模拟电脑的USB的插口
    //若fun方法参数为 Mouse 会如何?
    public void fun(USB usb) {
        usb.plugIn();    //插入
        usb.work();      //工作
    }
}

对于电脑的使用者生产者来说,根本不关心到底哪个具体设备插入到我的电脑上,只要这个设备满足了USB接口,就能被电脑识别。
实现了一个接口接受无数种设备,只要这个设备满足USB接口,就可以插入到电脑且被电脑识别,兼容所有的USB子类对象。

若fun方法参数为 Mouse 会如何?
fun(Mouse mouse) ——>这个插口只能插鼠标,键盘都无法识别,这是两个毫无关系的类。

运行测试

此时新增一个相机类

package interface_Test.usb;
public class Computer {
    public static void main(String[] args) {
        Computer computer = new Computer();
        Mouse mouse = new Mouse();
        //插入鼠标
        computer.fun(mouse);
        KetBoard ketBoard = new KetBoard();
        //插入键盘
        computer.fun(ketBoard);
        Camera camera = new Camera();
        //插入相机
        computer.fun(camera);
    }

    public void fun(USB usb) {
        usb.plugIn();
        usb.work();
    }
}

子类 Camera,对于 Computer 这个类来说,没有影响。

开闭原则——所有设计模式的核心思想,程序应当对扩展开放,对修改关闭。
即方便扩展,不能影响已经写好的程序。

2. 接口表示具备某种能力或行为

接口允许多实现,一个类可能具备多个能力,同时实现多个父接口。

例如:表示子类实现了多个父接口

public class Duck implements ISwim,IRun,IFly{
}

若实现多个父接口,子类普通类,需要覆写所有的抽象方法

package interface_Test.animal;
//飞,表示具有飞的行为或能力
public interface IFly {
    public abstract void fly();
}

package interface_Test.animal;
//跑步接口,表示具有跑步的行为或能力
public interface IRun {
    public abstract void run();
}

package interface_Test.animal;
//游泳接口,表示具有游泳的行为或能力
public interface ISwim {
    public abstract void swim();
}
//Rabbit.java   Rabbit类单独的java文件
package interface_Test.animal;
public class Rabbit implements IRun {
    @Override
    public void run() {
        System.out.println("兔子在跑");
    }
}
//Dog.java   Dog类单独的java文件
package interface_Test.animal;
public class Dog implements IRun,ISwim{
    @Override
    public void run() {
        System.out.println("狗在跑");
    }
    @Override
    public void swim() {
        System.out.println("狗在游泳");
    }
}
//Duck.java   Duck类单独的java文件
package interface_Test.animal;
public class Duck implements ISwim,IRun,IFly{
    @Override
    public void run() {
        System.out.println("鸭子在跑");
    }
    @Override
    public void swim() {
        System.out.println("鸭子在游泳");
    }
    @Override
    public void fly() {
        System.out.println("鸭子在飞");
    }
}
package interface_Test.animal;
public class Test {
    public static void main(String[] args) {
        //接口不能实例化对象,需要向上转型
        IRun iRun1 = new Rabbit();
        IRun iRun2 = new Dog();
        ISwim iSwim = new Dog();
        IFly iFly = new Duck();
        iRun1.run();
        iRun2.run();
        iSwim.swim();
        iFly.fly();
    }
}

由于接口中只有全局常量和抽象方法

因此接口中 public abstract(抽象方法)、static final(常量)全都可以省略。

package interface_Test.animal;
public interface IFly {
    //全局常量 static final
    String test = "飞飞飞";
    void fly();
}

在接口声明中,这些关键字都不用写,只保留最核心的方法返回值、方法参数列表、名称即可。

package interface_Test.animal;
//跑步接口,表示具有跑步的行为或能力
public interface IRun {
    String test = "跑跑跑";
    void run();
}

package interface_Test.animal;
public class Rabbit implements IRun {
    @Override
    public void run() {
        System.out.println(test);
        System.out.println("兔子在跑");
    }
}

package interface_Test.animal;
public class Test {
    public static void main(String[] args) {
        IRun iRun1 = new Rabbit();
        iRun1.run();
    }
}

3. 接口和类之间的关系

接口和接口之间也存在继承关系。接口坚决不能继承—个类。

interface IA {
    void testA();
}
interface IB {
    void testB();
}
interface IC extends IA, IB {
    @Override
    void testA();

    @Override
    void testB();
}

IC接口同时继承多个父接口,继承了所有的抽象方法,子类(普通类)在实现IC接口时,必须覆写所有的抽象方法。

class CImpl implements IC{
    @Override
    public void testA() {
    }
    @Override
    public void testB() {
    }
}

如果一个类既需要继承—个类,又要同时实现多个接口,如何实现?
先使用extends继承一个类,而后使用implements实现多个父接口。

abstract class Person{
}

class China extends Person implements IA,IB{
    @Override
    public void testA() {
    }

    @Override
    public void testB() {
    }
}

接口的命名规范

1. 为了区分接口和类,命名接口使用 l 开头,如:IRun,ISwim

2. 子类实现一个接口时,命名以相应的接口开头,以 Impl 结尾。
eg :如果是IRun的子类,Runlmpl(不是强制要求,尽量能做到以此命名);如果子类实现多个父接口,不需要使用此规范来命名。

在给定的代码中,我们可以看到一个抽象类Vehicle和它的两个子类Car和RaceCar。每个类都有一个名为speed()的方法,返回不同的速度值。在TestCar类的main方法中,创建了一个RaceCar对象、一个Car对象和一个Vehicle对象,并通过调用speed()方法分别获取它们的速度值,并将结果打印输出。输出结果为"150, 60, 60"。 抽象类的意义在于它提供了一种定义接口的方式,它可以包含抽象方法和具体方法。抽象方法是没有实现的方法,需要在具体的子类中实现。抽象类可以作为基类,被其他类继承,并在子类中实现抽象方法。它可以提供一些公共的方法和属性,以及规范子类的行为。通过使用抽象类,我们可以实现代码的重用和扩展性的增强。 编写建设银行接口CCB继承银联接口,并实现该接口,可以在建设银行接口CCB中定义燃气费支付的方法,并在实现该接口的类中实现该方法。接口可以为不同的类提供一种共同的协议或契约,使得这些类可以按照接口定义的方法进行操作。 正确的说法是接口定义了一组方法的规范,而抽象类可以包含方法的实现。接口可以被多个类实现,而抽象类只能被单继承。接口中的方法默认是公共的,而抽象类中的方法可以有不同的访问修饰符。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Java入门第67课——抽象类接口作业](https://blog.csdn.net/houjunkang363/article/details/90726776)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瘦皮猴117

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值