JavaSE基础语法之抽象类和接口

目录

前言

一、抽象类

1.概念

2.语法

3.作用

二、接口

1.接口的概念

2.语法规则

3.接口使用

4.接口的特性

5.实现多个接口

6.接口间的继承

7.Clonable 接口和深拷贝

8.抽象类和接口的区别

三、Object 类

总结


前言

抽象类和接口这一章非常重要,这一章才真正体现出了Java面向对象的继承和多态

一、抽象类

1.概念

抽象类:没有包含足够的信息来描绘一个具体的对象的类

2.语法

相比较普通类,抽象类增加了 abstract 的修饰符

abstract class Shape{
    //抽象类也是类,也可以增加属性和普通方法,甚至是构造方法
    double area;
    public void getArea(){
        return this.area;    
    } 
    //抽象方法没有具体的实现,不能是private
    //抽象方法没有加访问限定符时,默认是public
    public abstract void draw();
}

注意:

  1. 抽象类必须被 abstract 修饰,即使抽象类中没有抽象方法,只要加 abstract 都是抽象类,有抽象方法的类一定是抽象类
  2. 抽象类也是类,也可以增加属性和普通方法,甚至是构造方法(毕竟当我们用普通类继承抽象类并且实例化时,我们要先调用父类的构造方法,并且一定情况下可以调用父类的属性)
  3. 抽象类不能直接实例化对象
  4. 抽象方法没有具体的实现,不能是private,当抽象方法没有加访问限定符时,默认是public
  5. 抽象方法不能被 final 和 static 修饰,因为抽象方法要被子类重写
  6. 抽象类必须被继承,并且继承后子类要重写父类中的抽象方法,否则子类也是抽象类,必须要使用 abstract 修饰

3.作用

由于普通类继承了抽象类之后,普通类必须重写抽象类的抽象方法,否则就会编译错误,相当于多了一层编译器的校验,预防程序员运行时出错,把 bug 扼杀在编写代码的过程

二、接口

1.接口的概念

在 Java 中,接口可以看作是多个类的公共规范,是一种引用数据类型

2.语法规则

接口的定义格式与定义类的格式基本相同,将class关键字换成 interface 关键字,就定义了一个接口

public interface 接口名称{
    // 抽象方法
    public abstract void method1(); // public abstract 是固定搭配,可以不写
    public void method2();
    abstract void method3();
    void method4();
    // 注意:在接口中上述写法都是抽象方法,推荐方式4,代码更简洁
}

提示:

1. 创建接口时, 接口的命名一般以大写字母 I 开头.

2. 接口的命名一般使用 "形容词" 词性的单词.

3. 阿里编码规范中约定, 接口中的方法和属性不要加任何修饰符号, 保持代码的简洁性

3.接口使用

接口不能直接使用,必须要有一个“实现类”来“实现”该接口,实现接口中的所有抽象方法

类实现接口的格式:

public class 类名称 implements 接口名称 {
    //...
}

注意:子类和父类之间是 extends 继承关系,类和接口之间是 implements 实现关系

4.接口的特性

  1. 接口类型是一种引用类型,但是不能直接 new 接口的对象
  2. 接口中每一个方法都是 public 的抽象方法,即接口中的方法会被隐式的指定为 public abstract (只能是public abstract,其他修饰符都会报错)
  3. 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现
  4. 重写接口中方法时,不能使用 default 访问权限修饰(因为接口中的方法都是 public 的访问权限)
  5. 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量
  6. 接口中不能有静态代码块和构造方法
  7. 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是 .class
  8. 如果类没有实现接口中所有的抽象方法,则类必须设置为抽象类
  9. jdk8中:接口中还可以包含 default 方法

5.实现多个接口

类与抽象类类似,但最大的不同就是在 Java 中,类和类之间是单继承的关系,即Java中不支持多继承,而一个类却可以同时实现多个接口

代码示例:

//以下是定义的三个接口
//飞翔的接口
interface IFlying{
    void flying();
}
//游泳的接口
interface ISwimming{
    void swimming();
}
//奔跑的接口
interface IRunning{
    void running();
}

//这是定义的一个动物类
class Animal{
    public String name;
    public int age;
    public Animal(){
        this.name = "xiao";
        this.age = 10;
    }

    public Animal(String name,int age){
            this.name = name;
            this.age = age;
    }
    public void eat(){
        System.out.println(name + "在吃饭");
    }
}

//这是鸟类继承了动物类并且实现了 IFlying 接口
class Bird extends Animal implements IFlying{
    public Bird(String name,int age){
        super(name,age);
    }

    //对接口中 flying() 方法的实现,必须写明public的权限
    @Override
    public void flying() {
        System.out.println(super.name + "在天空翱翔");
    }
}

//这是鸭类继承了动物类并且实现了 IFlying,ISwimming,IRuning 接口
class Duck extends Animal implements IFlying,ISwimming,IRunning{
    public Duck(String name,int age){
        super(name,age);
    }

    @Override
    public void flying() {
        System.out.println(name + "在天空翱翔");
    }

    @Override
    public void swimming() {
        System.out.println(name + "在游泳");
    }

    @Override
    public void running() {
        System.out.println(name + "在跑");
    }
}

//这是狗类继承了动物类并且实现了 ISwimming 接口
class Dog extends Animal implements ISwimming{
    public Dog(String name, int age) {
        super(name, age);
    }

    @Override
    public void swimming() {
        System.out.println(name + "在游泳");
    }
}

//测试的类
public class Test3 {
    //通过这种方法,使得实际对象传进来之后是利用 IRunning 接口来调用特定类的实现了的本接口的方法
    //有点像多态性,但这里的形参类型是接口
    public static void walk(IRunning iRunning){
        iRunning.running();
    }

    public static void swim(ISwimming iSwimming){
        iSwimming.swimming();
    }

    public static void main(String[] args) {
        Bird bird = new Bird("麻雀",5);
        Duck duck = new Duck("鸭子",7);
        walk(duck);
        swim(duck);
    }

}

6.接口间的继承

在 Java 中,类和类之间是单继承的,一个类可以实现多个接口,接口和接口之间是多继承的。即:用接口可以达到多继承的目的

接口可以继承一个接口,达到复用的效果。只要是继承,都是使用 extends 关键字

代码示例:

/**
 * 接口的继承
 * A3接口拥有了ISwimming和IRunning两个接口的功能
 * 并且增加了自己的功能
 * 接口和接口之间用extends
 * 类和接口之间用implements
 */
interface A3 extends ISwimming,IRunning{
    void func();
}

接口间的继承相当于把多个接口合并在一起

7.Clonable 接口和深拷贝

Clonable 这个接口非常实用,Object 类中存在一个 clone 方法,调用这个方法可以创建一个对象的”拷贝“,但是要想合法调用 clone 方法,必须要先实现 Clonable 接口,否则就会抛出 CloneNotSupportedException 异常

浅拷贝代码示例:

//Cloneable 就相当于给这个类盖了一个章,表示它可以被拷贝
class Mary implements Cloneable{
    public double num = 12.5;

    public Mary() {
    }

    public Mary(double num) {
        this.num = num;
    }

    //之所以需要这样实现,很大的原因就是不同包的父类的成员方法,必须通过 super 来调用
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}

深拷贝代码示例:

/**
 * Cloneable 标记接口
 * 表示当前类可以被克隆
 */
class Person implements Cloneable{
    private int id;
    private Mary mary = new Mary();

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Mary getMary() {
        return mary;
    }

    public void setMary(Mary mary) {
        this.mary = mary;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person tmp = (Person) super.clone();
        tmp.mary = (Mary) this.mary.clone();
        return tmp;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", mary=" + mary +
                '}';
    }
}
public class Test2 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        person.setId(100);
        // 被 protected 修饰的在不同包中的子类调用父类方法时,需要用super
        Person person1 = (Person) person.clone();
        person1.getMary().num = 2;
        System.out.println(person.getMary().num);
        System.out.println(person1.getMary().num);
    }


}

浅拷贝与深拷贝之间的比较

浅拷贝与深拷贝的区别就是浅拷贝只会拷贝表层的东西

举例:在第二段代码的类的 clone() 方法中只有下面的一行代码,那么结果就是拷贝后新的 Person 对象中 Mary 成员类的对象的引用与被拷贝的 Person 类对象中的 Mary 成员类的引用指向相同,一旦新的 Person 对象中的 Mary 成员类对象中的成员变量值改变,也会导致原来的那个 Person 对象中的 Mary 成员类对象中的成员变量值改变,并不能算是完全拷贝,因此我们必须要在 clone() 方法内部重新为 Mary 对象进行拷贝,相应的下方代码也就会跟着修改

    return (Person) super.clone();

8.抽象类和接口的区别

抽象类和接口都是 Java 中多态的常见使用方式. 都需要重点掌握. 同时又要认清两者的区别

核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中不能包含普通方法, 子类必须重写所有的抽象方法.

如之前写的 Animal 例子. 此处的 Animal 中包含一个 name 这样的属性, 这个属性在任何子类中都是存在的. 因此此处的 Animal 只能作为一个抽象类, 而不应该成为一个接口

再次提醒:

抽象类存在的意义是为了让编译器更好的校验, 像 Animal 这样的类我们并不会直接使用, 而是使用它的子类.万一不小心创建了 Animal 的实例, 编译器会及时提醒我们

No

区别

抽象类(abstract)

接口(interface)

1

结构组成

普通类 + 抽象方法

抽象方法 + 全局常量

2

权限

各种权限

public

3

子类使用

使用 extends 关键字继承抽象类

使用 implements 关键字实现接口

4

关系

一个抽象类可以实现若干接口

接口不能继承抽象类,但接口可以使用 extends 关键字继承多个父接口

5

子类限制

一个子类只能继承一个抽象类

一个子类可以实现多个接口

三、Object 类

Object 是 Java 默认提供的一个类。Java里面除了Object类,所有的类都是存在继承关系的。默认会继承Object父类。即所有类的对象都可以使用Object的引用进行接收

所以在开发之中,Object类是参数的最高统一类型。Object类中存在有定义好的一些方法。如下:

尤其注意的是:Object 类中大多数的方法要是想实现的自己的功能,那么就要重写方法


总结

以上就是今天要讲的内容,本文仅仅简单介绍了抽象类和接口的使用,大家可以看到语法很简单,但是要真正利用这些实现多态,抽象类和接口的选择是至关重要的,而怎么选,需要我们在项目里多实战

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

求索1024

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

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

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

打赏作者

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

抵扣说明:

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

余额充值