6. 快速掌握抽象类及接口

目录

  • [1. 抽象类](#1. 抽象类)
      • [1.1 抽象类语法](#1.1 抽象类语法)
      • [1.2 抽象类特性](#1.2 抽象类特性)
      • [1.3 抽象类的作用](#1.3 抽象类的作用)
  • [2. 接口](#2. 接口)
      • [2.1 接口语法](#2.1 接口语法)
      • [2.2 接口的特性](#2.2 接口的特性)
  • [3. 接口案例](#3. 接口案例)
  • [4. 常用接口](#4. 常用接口)
      • [4.1 Comparable接口---compareTo()方法](#4.1 Comparable接口---compareTo()方法)
      • [4.2 clonable接口---clone方法](#4.2 clonable接口---clone方法)
      • [4.2 深拷贝和浅拷贝](#4.2 深拷贝和浅拷贝)
  • [5. Object类](#5. Object类)
      • [5.1 equals()方法](#5.1 equals()方法)
      • [5.2 toString()方法](#5.2 toString()方法)
      • [5.3 hashCode()方法](#5.3 hashCode()方法)
  • [6. 内部类](#6. 内部类)
      • [6.1 内部类分类](#6.1 内部类分类)

1. 抽象类

并不是所有的类都用来描述对象,如果一个类中没有足够的信息来描述一个具体的对象,那这个类就是抽象类。一个方法没有方法体,这就是抽象方法。

1.1 抽象类语法

被abstract修饰的类称为抽象类,被abstract修饰的方法称为抽象方法,abstract不修饰成员变量。

【代码演示】

java 复制代码
abstract class Animal{
    //普通方法
    public void fun(){

    }
    //抽象方法  有抽象方法后,当前类必须也变成抽象类
    public abstract void fun1();
}

1.2 抽象类特性

  1. 抽象类中可以包含普通方法和成员
  2. 抽象方法不能被private,final和static修饰(因为抽象方法生来就是要被继承并重写的,被private修饰虽能被继承,但不能被重写。重写的条件就是使用抽象类的条件)
  3. 抽象类不能实例化,必需由子类继承并重写抽象类的全部抽象方法。若继承的子类也是抽象类,该子类也不能实例化,想使用,必须让普通类继承抽象类
  4. 抽象类中不一定有抽象方法,但有抽象方法的类一定是抽象类
  5. 抽象类可以提供构造方法,供子类创建对象时,初始化父类的成员变量

1.3 抽象类的作用

普通类也可以做到抽象类能做到的,而且抽象类使用起来不方便,为什么要有抽象类?

答:和final一样,是为了充分利用编译器的校验功能。让编译器来检查,以防不留神就作出更改。

2. 接口

接口,属于引用数据类型,是一种公共的行为规范。在实现时只要符合规范标准,就可以用。在java中,接口可以看做多个类的公共规范,比抽象类更抽象

2.1 接口语法

定义接口跟定义一个类基本相同

java 复制代码
修饰符 interface I形容词{
	//抽象方法
    void draw(); //等价于public abstract void draw();
    
}

【定义规则】

  1. 接口的命名以I开头,词性为形容词
  2. 根据阿里代码规范,接口中的方法和属性不要加任何修饰(因为加不加都一样),保持代码简洁

2.2 接口的特性

  1. 接口不能直接实例化
  2. 接口也有字节码文件
  3. 使用接口需要重写接口中的所有抽象方法
  4. 接口中方法必须是抽象方法,但方法可以被static和default修饰,这两个方法都不是抽象方法,需要实现方法细节
  5. 接口之间继承用extends,实现接口用implements。一个类若是同时用extends和implements,先extends后implements
  6. 接口中不能有静态/实例代码块和构造方法
  7. 接口解决了多继承的问题。因为把所有的方法都放到一个类会导致该类没有功能的专一性,但java有不支持继承多个类,但接口就可以。
  8. 接口可以被abstract修饰

3. 接口案例

【案例一】使用单接口写接口和电脑的功能

java 复制代码
/**
 * 1. USB接口:包含打开设备、关闭设备功能
 * 2. 笔记本类:包含开机功能、关机功能、使用USB设备功能
 * 3. 鼠标类:实现USB接口,并具备点击功能
 * 4. 键盘类:实现USB接口,并具备输入功能
 */

interface USB{
    void openDevice();
    void closeDevice();
}
class Mouse implements USB{
    public void click(){
        System.out.println("鼠标点击");
    }

    @Override
    public void openDevice() {
        System.out.println("打开鼠标");
    }

    @Override
    public void closeDevice() {
        System.out.println("关闭鼠标");
    }
}
class keyBoard implements USB{

    public void input(){
        System.out.println("键盘输入");
    }

    @Override
    public void closeDevice() {
        System.out.println("关闭键盘");
    }

    @Override
    public void openDevice() {
        System.out.println("打开键盘");
    }
}
class Computer implements USB{
    public void powerOn(){
        System.out.println("打开电脑");
    }
    public void powerOff(){
        System.out.println("关闭电脑");
    }

    public void useDevice(USB usb){
        if(usb instanceof Mouse){
            Mouse mouse = (Mouse)usb;
            mouse.click();
        } else if (usb instanceof keyBoard) {
            keyBoard keyBoard = (keyBoard)usb;
            keyBoard.input();
        }
    }
    
    @Override
    public void openDevice() {
        System.out.println("电脑开机");
    }
    @Override
    public void closeDevice() {
        System.out.println("电脑关机");
    }
}

public class MyInterface {
    public static void fun(USB usb){
        usb.closeDevice();
    }
    public static void main(String[] args) {
        fun(new keyBoard());
    }
}

【案例二】使用实现多接口写动物能跑 能游泳

java 复制代码
class Animal1 {
    public int age;
}
interface run{
    void run();
}
interface swim{
    void swim();
}
class Dog extends Animal1 implements run,swim{
    @Override
    public void run() {
        System.out.println("狗狗跑步");
    }

    @Override
    public void swim() {
        System.out.println("狗狗游泳");
    }
}
public class MyInterface {

    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.run();
    }
}

4. 常用接口

4.1 Comparable接口---compareTo()方法

sort方法中调用了compareTo()方法

【代码演示】

java 复制代码
class Student{
    public int age;

    public Student(int age){
        this.age = age;
    }
}
public class Test {

    /**
     * 之前整型数组调用sort方法,进行排序
     * 现在要求:把几个学生对象排序
     */

    public static void main(String[] args) {
        Student[] students = {
                new Student(20),
                new Student(18),
                new Student(25),
        };
        Arrays.sort(students);
        System.out.println(Arrays.toString(students));
    }
}

//运行结果
Exception in thread "main" java.lang.ClassCastException: Student cannot be cast to java.lang.Comparable

【代码改正】

java 复制代码
class Student implements Comparable{
    public int age;

    //重写compareTo方法,指定 到底比较引用类型的哪个变量
    @Override
    public int compareTo(Object o) {
        Student student = (Student) o;
        if (this.age > student.age)
            return 1;
        else if (this.age == student.age)
            return 0;
        else
            return -1;
    }

    //重写toString方法,改变打印效果
    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                '}';
    }

    public Student(int age){
        this.age = age;
    }
}
public class Test {

    public static void main(String[] args) {
        Student[] students = {
                new Student(20),
                new Student(18),
                new Student(25),
        };
        Arrays.sort(students);
        System.out.println(Arrays.toString(students));
    }
}

//运行结果
[Student{age=18}, Student{age=20}, Student{age=25}]

4.2 clonable接口---clone方法

拷贝的是对象,不是类

Object类是所有类的子类,且有clone方法,为什么自己写的类不能调用?为什么要重写?

  1. 因为clone方法是protected修饰的,在不同包的子类中访问需要用super关键字,所以调用不了。
  2. 想调用clone方法,官方规定必须重写。
  3. 而且自己写的类必须实现Cloneable接口(空接口/标志接口),标志着该类有比较功能。

【代码演示】

java 复制代码
/**
 * 克隆一个对象:
 * 1. 先实现Cloneable接口
 * 2. 重写Object类的clone方法
 * 3. 由于clone方法是protected方法,要用super关键字访问Object类的clone方法
 *
 */
class Animal implements Cloneable{
    public int age;
    public String name;


    //1.可以让编译器自动生成,但需要将父类强转为当前对象
//    @Override
//    protected Object clone() throws CloneNotSupportedException {
//        return super.clone();
//    }
    //2. 也可以自己重写clone方法
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

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

}
public class Test {

    public static void main(String[] args) throws CloneNotSupportedException {
        Animal animal = new Animal(20,"西西");
        Animal animal1 = (Animal) animal.clone();
        System.out.println(
                "animal.age="+animal.age
                        +"  animal1.age="+animal1.age
        );
    }
}

//运行结果
animal.age=20  animal1.age=20

4.2 深拷贝和浅拷贝

拷贝分深拷贝和浅拷贝,辨别深浅拷贝在于代码实现方式,而不是方法。

java 复制代码
演示浅拷贝

class Person{
    int num = 7;
}
class Animal implements Cloneable{
    public int age;
    public String name;
    public Person person = new Person();

    //1.可以让编译器自动生成,但需要将父类强转为当前对象
//    @Override
//    protected Object clone() throws CloneNotSupportedException {
//        return super.clone();
//    }
    //2. 也可以自己重写clone方法
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

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

public class Test {

    public static void main(String[] args) throws CloneNotSupportedException {
        Animal animal = new Animal(20,"西西");
        Animal animal1 = (Animal) animal.clone();
        animal.person.num = 10;
        System.out.println(
                "animal.person.num="+animal.person.num 
                        +"  animal.person.num="+animal1.person.num
        );
    }
}

//运行结果,我只改了animal对象的值,
//两个对象的值却都变了
animal.person.num=10  animal.person.num=10

5. Object类

Object类需要掌握下面这些方法,可以根据图标🔒,🔓来判断该方法是否能被重写,有🔒标志的就是被private修饰的,不能重写

5.1 equals()方法

简单数据类型比较相等用==,引用数据类型比较相等用equals方法

java 复制代码
/**
 * equals方法 比较引用类型
 * 和 == 不同
 */
class P{
    public int age;
    public P(){

    }
    public P(int age){
        this.age = age;
    }

//查看equals方法的源代码发现和person==person1一样的效果
//重写equals方法自己定义
    @Override
    public boolean equals(Object obj) {
        P p = (P)obj;
        if (this.age == p.age)
            return true;
        else
            return false;
    }
}
public class Test1 {
    
    public static void main(String[] args) {
        P person = new P(18);
        P person1 = new P(18);
        
        System.out.println(person==person1); //false
        System.out.println(person.equals(person1));//true
    }
}

5.2 toString()方法

上面已演示

5.3 hashCode()方法

主要是获取"地址",先不讲,后期会仔细讲

6. 内部类

外部类:类A中定义了一个类B,类A就是外部类

内部类:类B就是内部类

6.1 内部类分类

1.实例内部类

  1. 非静态类,无论是内部类还是外部类,其内部不能有static。若想定义静态的必须加final,而且该变量必须就地初始化。
  2. 如何实例化 实例内部类?先创建外部类对象。外部类.内部类 变量名 = 外部类对象引用.内部类();
  3. 内部类中访问外部类成员,不论访问权限。类内部和类外部同名变量时,优先看内部类。若非要访问外部类的同名变量,用外部类类名.成员变量。
  4. 外部类访问内部类,实例化内部类再调用即可
  5. 内部类也有字节码文件,命名格式为外部类类名$内部类类名.class

【代码演示】

java 复制代码
class Out{
    public int a;
    public static int b; //报错
    public static final int b;
    private int c;

    //静态内部类
    class InnerClass{
        public int a = 2;
        public int d;
        public static final int e = 2;
        private int f;

        public void test(){
            //在内部类中访问外部类成员
            System.out.println(a); //优先访问内部类 2
            System.out.println(b); //访问外部类 0
            Out out = new Out();
            System.out.println(out.c);//访问外部类 0

            System.out.println(d);//优先访问内部类 0
            System.out.println(e);//优先访问内部类 2
            System.out.println(f);//优先访问内部类 0
            System.out.println("InnerClass");
        }

    }
    public void test(){
        //在外部类中访问内部类成员
        InnerClass innerClass = new InnerClass();
        System.out.println(innerClass.d);
        System.out.println(InnerClass.e);
        System.out.println(innerClass.f);
        System.out.println(a);

        System.out.println("Out");
    }
}

public class test {
    public static void main(String[] args) {
    //创建 实例内部类对象
        //1.创建父类对象
        OutClass outClass = new OutClass();
        //2.通过 外部类对象 引用创建 内部类对象   外部类.内部类 变量名 = 外部类对象引用.内部类();
        OutClass.InnerClass innerClass = outClass.new InnerClass();
        innerClass.test();
    }
}

2.静态内部类(工作中用的较多)

  1. 如何实例化?不需要创建外部类对象。外部类.内部类
  2. 在内部类中访问只能访问外部类的静态成员,若要访问非静态成员,需要创建一个外部类对象,通过对象引用来调用

【代码演示】

java 复制代码
class Out{
    public int a;
    public static int b;
    private int c;

    //静态内部类
    static class InnerClass{
        public int a = 2;
        public int d;
        public static final int e = 2;
        private int f;

        public void test(){
            System.out.println(a);
            System.out.println(b);
            Out out = new Out();
            System.out.println(out.c);
            System.out.println(d);
            System.out.println(e);
            System.out.println(f);
            System.out.println("InnerClass");
        }
    }
}

public class test {
    public static void main(String[] args) {
    //创建 静态内部类对象
        Out.InnerClass innerClass1 = new Out.InnerClass();
        innerClass1.test();
    }
}

3.匿名内部类(多线程常用)

【代码演示】

java 复制代码
interface A{
    void func();
}
public class test {
    public static void main(String[] args) {
    //创建 匿名内部类对象
        A a = new A(){
            @Override
            public void func() {

            }
            
        };
    }
}

4.局部内部类(不常用,了解即可)

  1. 只能定义在外部类方法内部,只能在方法体内部使用。
  2. 不能被public,static等访问修饰限定符修饰
  3. 有自己的字节码文件,格式为外部类类名$数字内部类类名.class

【代码演示】

java 复制代码
public class test {

    public static void fun(){
        class Inner{
            public int a = 89;
        }
        Inner inner = new Inner();
        System.out.println(inner.a);
    }

    public static void main(String[] args) {
        fun();
    }
相关推荐
王老师青少年编程几秒前
gesp(C++五级)(8)洛谷:B3969:[GESP202403 五级] B-smooth 数
开发语言·c++·算法·gesp·csp·信奥赛
stormjun1 分钟前
2025 年 Java 最新学习资料与学习路线——从零基础到高手的成长之路
java·开发语言·学习·java学习路线·java 学习教程·2025java 学习路线
你回到了你的家10 分钟前
4 常量和C预处理器
c语言·开发语言·c++
_.Switch12 分钟前
高级Python Web开发:FastAPI前后端通信与跨域资源共享(CORS)实现详解
开发语言·前端·数据库·后端·python·中间件·fastapi
计算机学姐14 分钟前
基于SpringBoot的装修公司管理系统
java·vue.js·spring boot·后端·spring·intellij-idea·mybatis
NiNg_1_23416 分钟前
解决Spring+Vue的跨域问题
java·vue.js·spring
m0_6632340116 分钟前
【框架篇】Spring MVC 介绍及使用(详细教程)
java·spring·mvc
laopeng30121 分钟前
1.Spring AI 从入门到实践
java·人工智能·spring
机器视觉知识推荐、就业指导25 分钟前
Qt/C++ 基于 QGraphicsView 的绘图软件 (附源码下载链接)
开发语言·c++·qt
2401_8979156528 分钟前
冒泡排序 选择排序 插入排序
java·算法·排序算法