• (JavaSE)抽象类和接口


    抽象类

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

    abstract class Shape{
        public void draw(){
            System.out.println("画图形!");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

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

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

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

    abstract class Shape{
        public static int a=10;
        public abstract void draw();
        public void func(){
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

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

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

    final和abstract是矛盾的。

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

    可以实现多态

    接口

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

    interface IShape{
        public abstract void draw();
        default public void func(){
            
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

    接口不能被实例化

    一个接口就是一个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));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    Object类

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

    hashcode()

    在这里插入图片描述

    返回对象的哈希值

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

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

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

    @Override
        public int hashCode() {
            return Objects.hash(name,age);
        }
    
    • 1
    • 2
    • 3
    • 4
    24022538
    24022538
    
    • 1
    • 2

    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));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    输出结果:

    false
    
    • 1

    在这里插入图片描述

    @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;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    我们可以重写一个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));
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

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

    class Student implements Comparable<Student>{
    
    • 1

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

    @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;
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    现在运行结果是:

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

    根据年龄排序

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

    在这里插入图片描述

    <Student>泛型
    
    • 1

    让 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));
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    输出结果

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

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

    模拟实现冒泡排序

    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));
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

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

    Clonable 接口和深拷贝

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

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

    class Person implements Cloneable{
    
    • 1

    在这里插入图片描述
    在这里插入图片描述
    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();
        }
    
    • 1
    • 2
    • 3
    • 4

    不同包中需要通过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);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    Person{id=99}
    Person{id=99}
    
    • 1
    • 2

    浅拷贝

    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);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    person 1999.0
    person2 1999.0
    
    • 1
    • 2

    在这里插入图片描述
    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);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    person 12.5
    person2 1999.0
    
    • 1
    • 2

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

  • 相关阅读:
    Android开发之百度地图定位打卡
    Python入门第一部分
    音乐在线教育解决方案,打造在线教育高品质教学体验
    【刷题系列】链表经典OJ题
    利用邮件营销提升电商营业额的策略与方法
    极米科技H6 Pro 4K、H6 4K高亮定焦版——开启家用投影4K普及时代
    基于篇章结构的英文作文自动评分方法(学习笔记)
    二叉树的最大深度(C++两种思路递归和层序)超详解小白入
    【路径规划】基于Dijkstra实现机器人二维路径规划附完整matlab代码
    【编译原理】Chapter1概述
  • 原文地址:https://blog.csdn.net/qq_63983125/article/details/126285441