zl程序教程

您现在的位置是:首页 >  后端

当前栏目

【Java SE】抽象类和接口

JAVA接口 抽象类 SE
2023-06-13 09:18:38 时间

1.抽象类

1.1抽象类的概念

在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。

像这种没有实际工作的方法, 我们可以把它设计成一个 抽象方法(abstract method), 包含抽象方法的类我们称为 抽象类(abstract class).

1.2抽象类语法

在Java中,一个类如果被 abstract 修饰称为抽象类,抽象类中被 abstract 修饰的方法称为抽象方法,抽象方法不用给出具体的实现体。

注意:抽象类也是类,内部可以包含普通方法和属性,甚至构造方法。

1.3抽象类的特点

我们可以先来看一段代码:

public abstract class Animal {
    public String name;
    public int age;
    abstract void eat();
}
class Dog extends Animal{
    Dog(String name,int age){
        this.name = name;
        this.age = age;
    }
    public void eat(){
        System.out.println(name +"吃狗粮!");
    }
}

class Cat extends Animal{
    Cat(String name,int age){
        this.name = name;
        this.age = age;
    }
    public void eat(){
        System.out.println(name +"吃猫粮!");
    }
}
class Test{
    public static void main(String[] args) {
        Dog dog1 = new Dog("旺旺",10);
        Cat cat1 = new Cat("喵喵",5);
        dog1.eat();
        cat1.eat();
    }
}
  1. 抽象类使用abstract修饰类
  2. 抽象类当中可以包含普通类所能包含的成员
  3. 抽象类和普通类不一样的是,抽象类当中可以包含抽象方法
  4. 抽象方法是使用abstract修饰的,这个方法没有具体的实现
  5. 不能实例化抽象类 new
  6. 抽象类存在的最大的意义就是为了被继承
  7. 如果一个普通类 继承了一个抽象类 此时必须重写抽象类当中的方法。
  8. 如果一个抽象类A继承了一个抽象类B,此时A当中,不需要重写B中的抽象方法。但是如果A再被普通类继承,就需要重写。
  9. 抽象方法不能是私有的。也不能是static的。太满足重写的规则。(即子类的修饰限定符大于等于父类的修饰限定符)
  10. final也不可以,他和abstract是矛盾的
  11. 抽象类当中 可以有构造方法,为了方便子类能够调用,来初始化抽象类当中的成员。

很多语法的出现,都是为了能够让程序员更早的发现错误。

2.接口

接口的定义格式与定义类的格式基本相同,将class关键字换成 interface 关键字,就定义了一个接口。 接口就是公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用。在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型。

2.1语法

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

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

提示:

  1. 创建接口时, 接口的命名一般以大写字母 I 开头.
  2. 接口的命名一般使用 “形容词” 词性的单词.

2.3接口使用

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

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

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

2.4接口特性

  1. 使用interface 来修饰接口
  2. 接口当中的成员方法,不能有具体的实现(public)
    1. 抽象方法:默认是public abstract 的方法
    2. JDK1.8开始,允许有可以实现的方法,但是这个方法只能是由default修饰的
    3. 可以实现静态方法。
  3. 成员变量默认是public static final 修饰的
  4. 接口不能被实例化
  5. 子类重写抽象方法,必须加上public
  6. 类和接口之间采用implements 来实现多个接口
  7. 接口中不能有静态代码块和构造方法
  8. 如果你不想实现接口的方法,那么久把这个类定义为抽象类,但是这个类被其他类继承,就必须重写。
  9. 一个类可以实现多个接口。使用implements 用逗号隔开。(可以解决多继承的问题)

2.7接口使用实例

package demo1;

import java.util.Arrays;

class Student{
    public String name;
    public int age;

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class Test {
    public static void main(String[] args) {
        Student[] students = new Student[3];
        students[0] = new Student("zhang",10);
        students[1] = new Student("huang",20);
        students[2] = new Student("li",30);

        Arrays.sort(students);

        System.out.println(Arrays.toString(students));
    }
}

可以看到代码报错了,在比较时要规定一下用什么来比较。姓名,年龄。 自定义的学生类需要具备可以比较的功能。

方法一:(根据年龄比较大小)

总结:如果我们以后自定义的类型,一定要记住,如果要比较大小,那么必须要让这个类具备可以比较的功能,此时可以选择实现接口Compara。

方法二:(根据姓名比较大小)

也可以这样写:

方法三:函数冒泡排序法

2.8Clonable接口和深拷贝

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

2.8.1Clonable接口

空接口、标记接口:当前类可以被克隆

以下以克隆为例再举一个接口的实例:

class Person implements Cloneable{
    public int id;

    @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();
    }
}

这就是浅拷贝。

2.8.2深拷贝

class Money implements Cloneable{
    public double m = 66.66;
    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 {
        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 =8888;
        System.out.println("person:"+person.money.m);
        System.out.println("person2 :"+person2.money.m);
    }
}

图解代码:

2.9抽象类和接口的区别

核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中不能包含普通方法, 子类必须重写所有的抽象方法. 抽象类存在的意义是为了让编译器更好的校验

3.Object类

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

3.1 获取对象信息

如果要打印对象中的内容,可以直接重写Object类中的toString()方法。

3.2对象比较equals方法

在Java中,== 进行比较时: a.如果左右两侧是基本类型变量,比较的是变量中值是否相同 b.如果左右两侧是引用类型变量,比较的是引用变量地址是否相同 c.如果要比较对象中内容,必须重写Object中的equals方法,因为equals方法默认也是按照地址比较的

3.3hashcode方法

涉及数据结构,后面我们再深入学习 hashcode方法源码:

public native int hashCode();

该方法是一个native方法,底层是由C/C++代码写的。我们看不到。

结论: 1、hashcode方法用来确定对象在内存中存储的位置是否相同 2、事实上hashCode() 在散列表中才有用,在其它情况下没用。在散列表中hashCode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。