【Java】抽象类和接口

目录

抽象类

1.什么是抽象类?

2.抽象类的格式

3.抽象方法

4.抽象类的特性

5.抽象类的作用

接口

1.什么是接口?

2.如何使用接口?

3.接口的特性

4.实现多个接口 

5.接口与接口

6.自定义类型的比较

Compareable接口

Comparator接口

8.Cloneable接口

浅拷贝

深拷贝

9.抽象类和接口的区别


抽象类

1.什么是抽象类?

抽象类:并不是所有对象的类都是用来描述对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类叫做抽象类。比如:Animal类,他是一个动物类,而动物有很多中,有猫有狗,你不知道他到底是具体哪一种动物。

2.抽象类的格式

//抽象类:被abstract修饰的类
public abstract class Animal {
    //抽象方法:被abstract修饰的方法,没有方法体
    // 如果一个方法你不想写具体的实现可以使用抽象方法
    public abstract void eat();
    abstract public void play();
    //第二种方法,abstract写在访问权限符前面,可能编译器不会报错,但可读性不好,推荐第一种
    //普通方法
    public void sleep(){
        System.out.println("在睡觉");
    }
    //属性
    public String name;
}

3.抽象方法

  • 抽象类也是类,内部也可以包含普通方法和属性,甚至构造方法;
  • 抽象类和普通类的区别:
  1.  抽象类中可以包含抽象方法;
  2. 抽象类不可以表示一个确定的对象,其不可以进行实例化。

4.抽象类的特性

1.抽象类不可以实例化自己;

虽然抽象类不可以实例化自己,但是他和普通类一样依然可以进行向上转型

public class Test {
    public static void Eat(Animal animal){
        animal.eat();
    }
    public static void main(String[] args) {
        Dog dog1 = new Dog();
        Animal animal=dog1;
        Dog dog2 = new Dog();
        Eat(dog2);
        Eat(dog2);
        //匿名对象
        Eat(new Dog());
        Eat(new Dog());
    }
}

2.抽象类必须被继承,并且继承后子类要重写父类中的抽象方法,否则编译器会报错,但如果子类也是抽象类,那么其子类可以不对父类中的抽象类进行重写

3.抽象类和抽象方法不能被private,抽象类就是用来被继承的并且子类要对抽象方法进行重写,如果被private修饰,那么抽象类将无法被继承,这没有意义,子类也不能重写抽象方法;

4.同理,抽象类和抽象方法也不能被static和final修饰,但抽象类中的普通方法可以被这些修饰 

5. 抽象类中不一定包含抽象方法,但是有抽象方法一定是抽象类;

6.抽象类中可以有构造方法,供子类对象时,初始化父类成员变量。 

5.抽象类的作用

既然抽象类本身不可以实例化,那么他有什么作用?

  • 抽象类就是用来被继承的

但是普通类也是可以被继承的?为什么还要用抽象类和抽象方法呢?

  • 抽象类相当于多了一层编译器的校验,可以起提醒作用“预防出错”。

接口

1.什么是接口?

接口:公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用。在java中,接口可以看成是:多个类的公共规范,是一种引用数据类型。例如:电源插座插孔上,可以插:电脑、电风扇、充电器等所有符合规范的设备。

语法规则

将class关键字换成interface来定义一个接口

public interface 接口名称{

      .....

}

  •  接口的命名一般以大写字母I开头;
  • 接口的命名一般使用“形容词”词性的单词;
  • 阿里编码规范中约定,接口中的方法和属性不要加任何修饰符号,保持代码间接性。

2.如何使用接口?

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

通过implements来实现类与接口的关系

public class 类名称 implements 接口名称{

        ....

}

代码示例:

实现笔记本电脑使用USB鼠标、USB键盘:

1.USB接口:包含打开、关闭设备;

2.鼠标接口:实现USB接口,并具备点击功能;

3.键盘类:实现USB接口,并具备输入功能;

4.笔记本类:包含开机、关机功能,使用USB设备。

//USB接口
public interface USB {
    void openDevice();
    void closeDevice();
}
//鼠标类,实现接口
public class Mouse implements USB{
    @Override
    public void openDevice() {
        System.out.println("打开鼠标");
    }

    @Override
    public void closeDevice() {
        System.out.println("关闭鼠标");
    }
    public void click(){
        System.out.println("点击鼠标");
    }
}
//键盘类,实现接口

public class KeyBoard implements USB{
    @Override
    public void openDevice() {
        System.out.println("打开键盘");
    }
    @Override
    public void closeDevice() {
        System.out.println("关闭键盘");
    }
    public void inPut(){
        System.out.println("输入键盘");
    }
}
//笔记本类,使用接口
public class Computer {
     public void  open(){
         System.out.println("开机");
     }
     public void close(){
         System.out.println("关机");
     }
     //使用USB功能
    public void useUSBDevice(USB usb){
         usb.openDevice();
         //使用鼠标功能
        if(usb instanceof Mouse){
            //向下转型
            Mouse mouse=(Mouse)usb;
            mouse.click();
        } else{//使用键盘
            KeyBoard keyBoard=(KeyBoard)usb;
            keyBoard.inPut();
        }
        usb.closeDevice();
    }
}
//测试
public class Test {
    public static void main(String[] args) {
        Computer computer=new Computer();
        computer.open();
        computer.useUSBDevice(new KeyBoard());
        computer.useUSBDevice(new Mouse());
        computer.close();
    }
}

3.接口的特性

  •  在接口中的成员变量,默认是public static final 修饰的,所以其变量都会被修饰成常量;
public interface IAnimal {
    int a=3;
    public static final int b=3;
}

  • 接口中的每一个方法都是public的抽象方法,默认都是public abstract 修饰的并且在jdk8之前只能定义抽象方法,所以抽象方法可写可不写,所以可以有以下4中写法,更推荐第四种写法。但在抽象类中,抽象类是普通类的一个超集,抽象类中定义抽象方法,必须要写abstract,可以是前两种写法;
    public  abstract void eat();
    abstract void eat2();
    public void eat1();
    void eat4();//推荐这一种,更简洁
  • 重写接口方法是,不能使用默认访问权限,因为接口的方法是默认public修饰的,而重写其实现类的方法访问权限不能小于接口
  • 在接口中的普通方法,必须要用default修饰 ;
default void sleep(){
        System.out.println("在睡觉");
    }
  •  在接口中可以实现静态方法
 static void sleep1(){
        System.out.println("在睡觉");
    }
  •  接口是一种引用类型,但不能进行实例化,同样不能有构造方法和静态代码块

  • 类通过implements来实现接口,但是类中要重写接口中的抽象方法 
public class Cat implements IAnimal {
    @Override
    public void eat4() {
        System.out.println("吃猫粮");
    }
}
  • 接口虽然不是类,但是接口编译完成后的字节码文件的后缀格式也是.class
  •  如果类没有实现接口中的所有抽象方法,这类必须设置为抽象类,如果这个抽象类被继承,就得实现所有的没有被实现的方法
abstract class KeyBoard implements USB{
}

4.实现多个接口 

为什么要实现多个接口?

在下面的代码中,有父类:动物类,子类:狗类和鸟类。我们知道狗会跑,鸟会飞。那我们是否可以将跑和飞这项特性写到动物类中呢?

答案是:不可以。父类是他们共性的集合,而鸟不会跑,而狗又不会飞。那应该怎么办呢?

//父类:动物类
public abstract class Animal {
    public String name;
    public int age;
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public abstract void eat();
}
//子类:狗类
public class Dog extends Animal{
    public Dog(String name, int age) {
        super(name, age);
    }
    @Override
    public void eat() {
        System.out.println(this.name+"吃狗粮");
    }
    public void run(){
        System.out.println(this.name+"会跑");
    }
}

//子类:鸟类
public class Bird extends Animal{
    public Bird(String name, int age) {
        super(name, age);
    }
    @Override
    public void eat() {
        System.out.println(this.name+"吃虫子");
    }
    public void fly(){
        System.out.println(this.name+"会飞");
    }
}

我们知道,在Java中,类和类之间是单继承,一个类只能有一个父类,无法实现多继承,但是一个类可以实现多个接口。

//父类
public abstract class Animal {
    public String name;
    public int age;
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public abstract void eat();
}
//子类
public class Dog extends Animal implements IRun{
    public Dog(String name, int age) {
        super(name, age);
    }
    @Override
    public void eat() {
        System.out.println(this.name+"吃狗粮");
    }
    @Override
    public void run(){
        System.out.println(this.name+"会跑");
    }
}

public class Bird extends Animal implements IFly{
    public Bird(String name, int age) {
        super(name, age);
    }
    @Override
    public void eat() {
        System.out.println(this.name+"吃虫子");
    }
    public void fly(){
        System.out.println(this.name+"会飞");
    }
}
public class Duck extends Animal implements IRun,IFly{
    public Duck(String name, int age) {
        super(name, age);
    }
    @Override
    public void eat() {
        System.out.println(this.name+"吃鸭食");
    }

    @Override
    public void fly() {
        System.out.println(this.name+"会飞");
    }

    @Override
    public void run() {
        System.out.println(this.name+"会跑");
    }
}
//接口
public interface IFly {
    void fly();
}
public interface IRun {
    void run();
}

测试类

上述代码展现了一个类继承一个父类实现多个接口。 

  • 一个类实现多个接口,每一个接口的抽象方法都要实现否则类必须设置为抽象类;
  • IDEA中使用 ctrl+I 可以快速实现接口;
  • 在继承的同时实现接口,要先继承在实现接口,不可以先实现接口在继承;

 实现多个接口的好处:其解决了不能多继承的问题。有了接口之后,可以不必再关注类的使用者具体类型,而只关注某个类是否具备某种能力就好。

5.接口与接口

接口与接口之间也可以实现extends(扩展)关系

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

interface IA{
    void a();
}
 interface IB{
    void b();
}
 interface IC extends IA,IB{
    void c();
}
class ID implements IC{
    @Override
    public void a() {

    }
    @Override
    public void b() {

    }
    @Override
    public void c() {

    }
}
  • 其实现类要重写接口所扩展所有的抽象方法 

6.自定义类型的比较

Compareable接口

作用:自定义类的比较

public class Test {
    public static void main1(String[] args) {
        Student stu1=new Student(16,"张三");
        Student stu2=new Student(20,"李四");
        //compareTo的调用
        //stu1相当于compareTo中的this,stu2相当于o
        System.out.println(stu1.compareTo(stu2));
    }
}
public class Student implements Comparable<Student> {
    public int age;
    public String name;
    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }
    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
    //对Compareable接口中的compareTo方法进行重写
    //年龄的比较
    @Override
    public int compareTo(Student o) {
     /*   //比较年龄
        //大于返回1;
        if(this.age>o.age){
            return 1;
        }
        //小于返回-1
        else if(this.age<o.age){
            return -1;
        }
        //等于返回o
        else{
            return 0;
        }*/
      //简化
       return this.age-o.age;
      
    }
   ===========================================
   //如果进行姓名的比较,对上述重写方法需要进行改写

        @Override
    public int compareTo(Student o) {
        //姓名是引用类型
        return this.name.compareTo(o.name);
    }
}

缺陷:比较固定的比较,不够灵活 

这是用于两个自定义类之间的比较,如果是多个对象呢?

数组中有一个sort方法,是否可以直接使用?

public class Student implements Comparable<Student> {
    public int age;
    public String name;
    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }
    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
public class Test {
    public static void main(String[] args) {
        Student[] stus=new Student[3];
        stus[0]=new Student(16,"a");
        stus[1]=new Student(20,"b");
        stus[2]=new Student(14,"c");
        //排序
        Arrays.sort(stus);
        //打印排序后的数组内容
        System.out.println(Arrays.toString(stus));
    }

出现了类型转换异常的情况 

sort需要进行Comparable强制类型转换,并用到其中的compareTo方法 

正确代码如下:

public class Test {
    public static void main(String[] args) {
        Student[] stus=new Student[3];
        stus[0]=new Student(16,"b");
        stus[1]=new Student(20,"c");
        stus[2]=new Student(14,"a");
        //排序
        Arrays.sort(stus);
        //打印排序后的数组内容
        System.out.println(Arrays.toString(stus));
    }
}
public class Student implements Comparable<Student> {
    public int age;
    public String name;

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    public int compareTo(Student o) {
     //比较名字
        return this.name.compareTo(o.name);
    }
}

Comparator接口

作用: 解决CompareTo缺陷,可以根据不同属性进行比较,不用重新修改。

public class NameComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.name.compareTo(o2.name);
    }
}
public class AgeComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.age-o2.age;
    }
}
public class Test {
    public static void main(String[] args) {
        Student stu1=new Student(16,"张三");
        Student stu2=new Student(20,"李四");
        //两个之间
        //年龄
        AgeComparator age=new AgeComparator();
        System.out.println(age.compare(stu1,stu2));
        //姓名
        NameComparator name=new NameComparator();
        System.out.println(name.compare(stu1,stu2));
        //数组
        Student[] stus=new Student[3];
        stus[0]=new Student(16,"b");
        stus[1]=new Student(20,"c");
        stus[2]=new Student(28,"a");
        //年龄排序
        Arrays.sort(stus,age);
        System.out.println(Arrays.toString(stus));
        //姓名排序
        Arrays.sort(stus,name);
        System.out.println(Arrays.toString(stus));

    }
}

8.Cloneable接口

作用:对对象进行拷贝

//实现Cloneable接口
public class Animal implements Cloneable{
    public int age;
    public String name;
    public Animal(int age, String name) {
        this.age = age;
        this.name = name;
    }
    @Override
    public String toString() {
        return "Animal{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
    //重写clone方法
    @Override
    protected Object clone() 
            throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Test {
    public static void main(String[] args)
            //处理异常
            throws CloneNotSupportedException{
        Animal animal=new Animal(2,"动物");
        Animal animal2=(Animal) animal.clone();
        System.out.println(animal2.toString());
    }
}
克隆的实现:

浅拷贝

  • 浅拷贝是对基本类型数据的复制,如果是引用类型复制的则是地址; 

深拷贝

9.抽象类和接口的区别

 

  • 图中全局变量修改为全局常量 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值