(JavaSE)抽象类和接口

发布于:2023-01-20 ⋅ 阅读:(169) ⋅ 点赞:(0)

抽象类

如果一个类中没有足够的信息用来描述一个具体的对象,这样的类就是抽象类。

abstract class Shape{
    public void draw(){
        System.out.println("画图形!");
    }
}

如果不想写draw()方法的方法体:

abstract class Shape{
    public abstract void draw()}
//如果这样写那么类名前的abstract修饰符不能省略,有抽象方法的类一定是抽象类

抽象方法没有方法体,抽象类中可以有普通类中的成员

abstract class Shape{
    public static int a=10;
    public abstract void draw();
    public void func(){

    }
}

在这里插入图片描述
抽象类的最大意义是被继承。

普通类继承抽象类,必须重写抽象类的抽象方法;抽象类A继承抽象类B则不强制要求A重写B中的抽象方法。

抽象方法不能是private,final,static。要满足重写的规则。

final和abstract是矛盾的。

抽象类中可以有构造方法。

可以实现多态

接口

接口是多个类的公共规范,是一种引用数据类型
关键字:interface
接口中的方法不能有方法体,如果非要有具体实现,加default:

interface IShape{
    public abstract void draw();
    default public void func(){
        
    }
}

在这里插入图片描述
在这里插入图片描述
可以实现多态

接口不能被实例化

一个接口就是一个java文件

因为接口的抽象方法是public修饰,所以子类重写时只能是public

接口中不能有静态代码块和构造方法

如果类没有实现接口中所有的抽象方法,则类必须被设置为抽象类

实现多个接口

一个类可以实现多个接口,可以解决多继承问题

在这里插入图片描述

interface IFlying{
    void flying();
}
interface ISwimming{
    void swimming();
}
interface IRunning{
    void running();
}
class Animal{
    public String name;
    public int age;
    public Animal(String name,int age){
        this.name=name;
        this.age=age;
    }

    public void eat(){
        System.out.println("吃饭!");
    }
}
class Duck extends Animal implements IFlying,IRunning,ISwimming{
    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+"正在跑!");
    }
    @Override
    public void eat() {
        System.out.println(name+"正在吃鸭粮!");
    }
}
public class Test5 {
    public static void walk(IRunning iRunning){
        iRunning.running();
    }
    public static void eat(Animal animal){
        animal.eat();
    }
    public static void main(String[] args) {
        eat(new Duck("duck",2));
        walk(new Duck("duck",2));
    }
}

Object类

Object是所有类的父类,默认会继承Object类。

hashcode()

在这里插入图片描述

返回对象的哈希值

        Person person1=new Person("张三",18);
        Person person2=new Person("张三",18);
        System.out.println(person1.hashCode());
        System.out.println(person2.hashCode());
460141958
1163157884

hashCode()这个方法算了一个具体的对象位置

如果自己重写hashCode(),输出结果一样

@Override
    public int hashCode() {
        return Objects.hash(name,age);
    }
24022538
24022538

equals()

class Person{
    private String name ;
    private int age ;
    public Person(String name, int age) {
        this.age = age ;
        this.name = name ;
    }
}

public class Test6 {
    public static void main(String[] args) {
        Person person1=new Person("张三",18);
        Person person2=new Person("张三",18);
        System.out.println(person1.equals(person2));
    }
}

输出结果:

false

在这里插入图片描述

@Override
    public boolean equals(Object obj) {
    if (obj == null) {
            return false ;
        } if(this == obj) {
            return true ;
        }
        if (!(obj instanceof Person)) {
            return false ;
        }
        Person per=(Person) obj;
        if(this.name.equals(per.name)&&this.age== per.age){//字符串也是引用类型
            return true;
        }
        return false;
    }

我们可以重写一个equals(),让程序调用自己写的equals(),输出结果为true.

Object类里的equals()比较的是引用变量里存储的地址

写了自定义类型要重写equals()

在这里插入图片描述

接口使用示例

Comparable<>接口

import java.util.Arrays;
class Student{
    public String name;
    public int age;
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
public class Test {
    public static void main(String[] args) {
        Student[] students=new Student[3];
        students[0]=new Student("bit",10);
        students[1]=new Student("hello",40);
        students[2]=new Student("abc",5);
        Arrays.sort(students);
        System.out.println(Arrays.toString(students));
    }

在这里插入图片描述
学生类有姓名,年龄。自定义类型需要自己指定比较的方法。

class Student implements Comparable<Student>{

让学生类继承一个接口,并重写接口里的方法

@Override
    public int compareTo(Student o) {
        if(this.age-o.age>0){
            return 1;
        }else if(this.age-o.age<0){
            return -1;
        }else{
            return 0;
        }
    }

现在运行结果是:

[Student{name='abc', age=5}, Student{name='bit', age=10}, Student{name='hello', age=40}]

根据年龄排序

关于比较年龄,compareTo()方法的使用:

在这里插入图片描述

<Student>泛型

让 Student 类实现 Comparable 接口, 并实现其中的 compareTo 方法。在 sort 方法中会自动调用 compareTo 方法。

自定义类型比较大小,要让这个类具备可比较的功能,让这个类实现接口Comparable。

在这里插入图片描述

Comparator<>接口

实现另一种接口,Comparator<>:

“类优先原则”:一个类扩展了一个超类,同时实现了一个接口,并从超类和接口中继承了相同的方法,在这种情况下只会考虑超类的方法,接口无论是否提供默认方法都会被忽略。
在这里插入图片描述

class AgeComparator implements Comparator<Student>{

    @Override
    public int compare(Student o1, Student o2) {
        return o1.age-o2.age;
    }
}
class NameComparator implements Comparator<Student>{

    @Override
    public int compare(Student o1, Student o2) {
        return o1.name.compareTo(o2.name);
    }
}
public static void main(String[] args) {
        Student[] students=new Student[3];
        students[0]=new Student("bit",10);
        students[1]=new Student("hello",40);
        students[2]=new Student("gbc",5);
        //AgeComparator ageComparator=new AgeComparator();
        NameComparator nameComparator=new NameComparator();
        Arrays.sort(students,nameComparator);
        //Arrays.sort(students,ageComparator);
        System.out.println(Arrays.toString(students));
    }

输出结果

[Student{name='bit', age=10}, Student{name='gbc', age=5}, Student{name='hello', age=40}]

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

模拟实现冒泡排序

class Student implements Comparable<Student>{
public int compareTo(Student o) {
        if(this.age-o.age>0){
            return 1;
        }else if(this.age-o.age<0){
            return -1;
        }else {
            return 0;
        }
    }
}
public class Test {
    public static void bubbleSort(Comparable[] array){
        for (int i = 0; i < array.length-1; i++) {
            for (int j = 0; j < array.length-1-i; j++) {
                if(array[j].compareTo(array[j+1])>0){
                    Comparable tmp=array[j];
                    array[j]=array[j+1];
                    array[j+1]=tmp;
                }
            }
        }
    }
    public static void main(String[] args) {
        Student[] students=new Student[3];
        students[0]=new Student("bit",10);
        students[1]=new Student("hello",40);
        students[2]=new Student("gbc",5);
        bubbleSort(students);
        System.out.println(Arrays.toString(students));

    }

自定义的类排序首先要保证每个对象都是可比较的,implements Comparable所以实现接口。然后调用compareTo()方法挨个进行比较

Clonable 接口和深拷贝

在这里插入图片描述
如果我想克隆person这个对象,Object超类中有clone()这个方法,但是person不能调用。

那么要让person具有可克隆的能力

class Person implements Cloneable{

在这里插入图片描述
在这里插入图片描述
Object类不是抽象类,却能容纳抽象方法,其实就是native在起作用,被native关键字修饰的方法属于本地方法,表示Java的作用范围已经无法达到,底层会去调用C/C++的库。

clone()方法是Object里面的protected方法,只允许在同包和子类内部调用。现在有一个类Cat,默认继承Object,所以假如你的调用测试写在Cat类里面,那么是可以调用的。但是假如你在和Cat同包的下面写了一个Test测试类,并尝试在Test里面实例化Cat,并调用clone(),是无法调用的。

@Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

不同包中需要通过super去访问,当前类中必须重写clone方法

在这里插入图片描述
在这里插入图片描述

class Person implements Cloneable{
    public int id;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();//调用Object的clone方法
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                '}';
    }
}
public class Test2 {
    public static void main(String[] args)throws CloneNotSupportedException {
        Person person=new Person();
        person.id=99;
        Person person2=(Person) person.clone();
        System.out.println(person);
        System.out.println(person2);
    }

}
Person{id=99}
Person{id=99}

浅拷贝

class Money{
    public double m=12.5;
}
class Person implements Cloneable{
    public int id;
    public Money money=new Money();//组合

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                '}';
    }
}
public class Test2 {
    public static void main(String[] args)throws CloneNotSupportedException {
        Person person=new Person();
        Person person2=(Person) person.clone();
        person2.money.m=1999;
        System.out.println("person "+person.money.m);
        System.out.println("person2 "+person2.money.m);
    }

}
person 1999.0
person2 1999.0

在这里插入图片描述
person2.money.m=1999,把person2指向的m改了,person指向的m也改了,因为m只有一份m,person和person2指向的是同一份,这就是浅拷贝。

如果想把m也拷贝一份?

深拷贝

在这里插入图片描述

class Money implements Cloneable{
    public double m=12.5;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}
class Person implements Cloneable{
    public int id;
    public Money money=new Money();

    @Override
    protected Object clone() throws CloneNotSupportedException {
        //return super.clone();
        Person tmp=(Person) super.clone();
        tmp.money=(Money) this.money.clone();
        return tmp;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                '}';
    }
}
public class Test2 {
    public static void main(String[] args)throws CloneNotSupportedException {
        Person person=new Person();
        Person person2=(Person) person.clone();
        person2.money.m=1999;
        System.out.println("person "+person.money.m);
        System.out.println("person2 "+person2.money.m);
    }

}
person 12.5
person2 1999.0

方法调用结束,tmp的值传给person2,tmp被销毁

本文含有隐藏内容,请 开通VIP 后查看