前言:

        在Java面向对象编程中,抽象类,接口,内部类以及Object类是构建灵活,可拓展代码的核心工具。理解它们的区别与联系,掌握使用场景,是每一位Java开发者进阶的必经之路。

        本文将结合通俗易懂的案例,带你彻底搞懂:

抽象类的概念,语法和特性

接口的定义,多实现与继承

Object类的常用方法(toString,equals)

各种内部类的使用(静态内部类,实例内部类,局部内部类,匿名内部类)

抽象类与接口的核心区别

目录

前言:

一.抽象类

1.1为什么需要抽象类

1.2抽象类语法

1.3抽象类特性

1.4抽象类的作用

二.接口

2.1接口的概念

2.2接口语法

2.3接口的实现

2.4接口特性

2.5实现多个接口

2.6接口间的继承

2.7接口使用实例:对象比较

2.8Cloneable接口与深拷贝

三.抽象类VS接口

四.Object类

4.1toString()——获取对象信息

4.2equals()——对象比较

五.内部类

5.1静态内部类

5.2实例内部类(非静态)

5.3局部内部类

5.4匿名内部类

六,总结


一.抽象类

1.1为什么需要抽象类

        在面向对象的世界里,所有对象都是通过类来描述的。但有些类并不具体,无法描述一个真实对象。比如:

Shape(图形)——它只是一个概念,无法画出具体的形状

Animal(动物)——它只是一个统称,无法让动物发出具体的叫声

这些类缺少足够的信息来描述对象,因此应该被设计为抽象类

        抽象类就像一张设计图纸,不能直接拿来住人,但是可以知道建造具体的房子。

1.2抽象类语法

        使用abstract关键字修饰列和方法:

public abstract class Shape{
    //抽象方法;没有方法体,必须由子类实现
    public abstract void draw();

    //抽象类可以有自己的属性和普通方法
    private double area;

    public double getArea(){
        return area;
    }
}

1.3抽象类特性

        1.不能实例化:

Shape shape =new Shape();    //编译错误

        2.抽象方法不能是private ,fianl,static

abstract private void test();  // 错误
abstract final void test2();   // 错误
abstract static void test3();  // 错误

        3.子类必须重新给所有抽象方法,否则子类也必须声明为抽象类

public class Cricle extends Shape{
    @Override
    public void draw (){
        System.out.println("画一个圈");
}
}

        4.抽象类可以有构造方法,供子类调用初始化父类成员

        5.抽象类不一定包含抽象方法,但抽象方法的类一定是抽象类

1.4抽象类的作用

        抽象类存在的最大意义:多一层编译器的校验。

如果某个方法不应该由父类实现,而必须由子类实现,那么将其声明为抽象方法,父类声明为抽象类。这样一旦由人误用父类实例化,编译器立即就会报错,避免逻辑错误。

二.接口

2.1接口的概念

        接口是一种公共的行为规范。只要符合规范,不同设备都可以通用。再Java中,接口是一种引用数据类型,是多个类的公共规范

2.2接口语法

public interface USB{
//接口中的变量默认是 public static final
    double VERSION =3.0

//方法默认是public abstract
    void openDevice();
}

2.3接口的实现

        使用implements关键字,一个类可以实现多个接口。

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

2.4接口特性

        1.不能直接实例化

        2.所有方法默认public abstract(Java 8后可以有default和static方法)

        3.变量默认public static final

        4.没有构造方法

        5.一个类可以实现多个接口,弥补了单继承的不足

2.5实现多个接口

class Frog extends Animal implements IRunning, ISwimming {
    @Override
    public void run() {
        System.out.println(name + "正在跳");
    }
    @Override
    public void swim() {
        System.out.println(name + "正在游泳");
    }
}

2.6接口间的继承

        接口可以多继承,使用extends:

interface IAmphibious extends IRunning, ISwimming {
}

这样IAmphibious就合并了IRunning和ISwimming两个接口的方法。

2.7接口使用实例:对象比较

        方式一:实现Comparable接口

class Student implements Comparable<Student>{
    private String name;
    private int score;
    @Override
    public int compareTo(Student o){
        return this.score-o.score;
    }
}

        方式二:Comparator接口

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

2.8Cloneable接口与深拷贝

        Cloneable是一个标记接口(没有任何方法),用于告诉JVM该类可以安全地克隆

class Person implements Cloneable {
    public Money money = new Money();
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone(); // 浅拷贝
    }
}

浅拷贝:只拷贝对象本身,内部引用类型成员仍然指向同一个对象。

深拷贝:需要手动实现,拷贝递归所有类型成员

三.抽象类VS接口

对比项 抽象类 接口
关键字 abstract class interface
实例化 不能 不能
构造方法 可以有 不能有
不同方法 可以有

Java8前不能,之后可以有

default/static方法

成员变量 各种访问权限 默认private static final
继承/实现 单继承 多实现
使用场景 表示“是什么” 表示“能做什么”

核心区别:抽象类可以包含普通方法和成员变量,子类可以直接复用;接口只定义规范,子类必须全部实现。

四.Object类

        所有类都直接或间接继承Object,它是类层次结构的根

4.1toString()——获取对象信息

System.out.println(obj); // 默认调用 obj.toString()

默认实现:类名@哈希码的十六进制。通常需要重写以返回有意义的描述。

4.2equals()——对象比较

        默认比较地址(和==一样)。若要比较内容,必须重写:

@Override
public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null || getClass() != obj.getClass()) return false;
    Person person = (Person) obj;
    return age == person.age && Objects.equals(name, person.name);
}

五.内部类

        内部类是指定义在另一个内部的类。它也是一种封装形式。

5.1静态内部类

        被static修饰,只能访问外部类的静态成员。

public class OutClass {
    static class InnerClass {
        public void method() {
            // 只能访问外部类的静态成员
        }
    }
}
// 创建
OutClass.InnerClass inner = new OutClass.InnerClass();

5.2实例内部类(非静态)

        可以访问外部类的任何成员。创建时需要先有外部类实例。

public class OutClass {
    class InnerClass {
        public void method() {
            // 可以直接访问外部类成员
        }
    }
}
// 创建
OutClass out = new OutClass();
OutClass.InnerClass inner = out.new InnerClass();

5.3局部内部类

        定义在方法内部,只能再方法内使用,不能使用访问修饰符。

public void method() {
    class LocalClass {
        // ...
    }
    LocalClass lc = new LocalClass();
}

5.4匿名内部类

        没有名字,在创建的同时之间实现接口或继承类。常用于一次性使用的场景。

Greeting greeting = new Greeting() {
    @Override
    public void greet() {
        System.out.println("Hello!");
    }
};
greeting.greet();

匿名内部类可以访问外部类的成员,以及所在方法的final或effectively final的局部变量。

六,总结

        抽象类:用来表示“一种类型”,可以有部分实现,子类通过继承复用代码。

        接口:用来表示“能力/规范”,强调“能做什么”,实现类需要全部实现

        Object类:所有类的父类,牢记toSring,equals的重写规则。

        内部类:根据位置和修饰符分为四种,匿名内部类在GUI编程,事件监听中极为常用。

更多推荐