
接口” 是一个在计算机科学、电子工程、软件工程等多个领域高频出现的核心概念,本质是 “不同系统 / 组件之间交互的规则与通道”。 接口就是公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用。 在Java中,接口可以看作:多个类的公共规范,是一种引用数据类型。
接口的定义和定义类的格式基本相同,将class关键字换成 interface 的关键字
public interface 接口名称{
//抽象方法
}1.接口不可包含 “方法的具体实现代码” 这是软件接口最核心的禁忌。接口只声明 “方法名、参数、返回值”(即 “方法签名”),不允许写方法体(即 “怎么做” 的逻辑) 错误示例(Java):接口中写方法实现,代码会直接报错
interface Payment {
// 错误:接口方法不能有方法体({}内的实现)
void pay(double money) {
System.out.println("支付" + money + "元");
}
}正确示例:只保留方法签名,实现交给具体类
interface Payment {
void pay(double money); // 仅声明方法,无实现
}
// 由WeChatPay类提供具体实现
class WeChatPay implements Payment {
@Override
void pay(double money) {
System.out.println("微信支付" + money + "元"); // 实现逻辑放在这里
}
}2.不可包含 “可修改的成员变量”(非常量) 接口中的成员变量默认是public static final(公共、静态、常量),不允许定义普通变量(如int count)。
interface Payment {
// 正确:常量名通常大写,必须初始化
double MIN_PAY_AMOUNT = 0.01;
public static final double MIN_PAY_AMOUNT2 = 0.01;
}3.不可包含 “构造方法” 构造方法是用于创建 “类的实例” 的,而接口本身不能被实例化(无法new Payment()),因此不需要也不允许定义构造方法.
注意: 1。创建接口时,接口的命名一般时以大写的 I 开头 2.接口的命名一般使用“形容词”的单词,比如在后面加上一个able 3.阿里的编码规范,接口的方法和属性最好不要加任何修饰符号,保持代码的简洁性
接口不可以直接使用,必须要有一个实现类来实现(implements)接口,实现接口中的所有抽象方法。
public class
类名称
implements
接⼝名称
{
// ...
}注意:子类和父类之间是extends 是继承关系,类和接口之间是implements 实现关系。
1.接口类型是一张引用类型,但是不能直接new接口的对象 2. 接⼝中每⼀个方法都是public的抽象⽅法,即接⼝中的方法会被隐式的指定为public abstract(只能是publicabstract,其他修饰符都会报错) 错误示范:
public interface USB {
// Error:(4, 18) java: 此处不允许使⽤修饰符private
private void openDevice();
void closeDevice();正确示范:
public interface USB {
public abstract void openDevice();
}3.接口的方法是不能在接口中实现的,只能由实现接口的类来实现
```java
public interface USB {
public abstract void openDevice();
}4.重写接口的方法时,不能使用默认的访问权限,重写接口方法时必须使用public权限。
5.接口中可以有变量,但是接口中的变量会被隐式指定为public static final
```java
interface MyInterface {
// 等价于:public static final int MAX_VALUE = 100;
int MAX_VALUE = 100;
}6.接口中不能有静态的代码和构造方法 7.接口不是类,但是接口编译完成后字节码文件的后缀也是,class 8.jdk8中,接口还可以包括default方法
在Java中,类和类之间是单继承的,⼀个类只能有⼀个父类,即Java中不⽀持多继承,但是⼀个类可以实现多个接口。
interface Flyable {
void fly();
}
interface Swimmable {
void swim();
}
// 鸭子既能飞也能游,实现两个接口
class Duck implements Flyable, Swimmable {
@Override
public void fly() {
System.out.println("鸭子飞起来了");
}
@Override
public void swim() {
System.out.println("鸭子游起来了");
}
}注意:在 Java 中,当一个类实现多个接口时,必须实现所有接口中的抽象方法;如果有任何一个抽象方法未实现,这个类就必须被声明为抽象类。
在 Java 中,接口之间支持多继承(一个接口可以同时继承多个接口),这与类之间的单继承形成鲜明对比,也让接口成为实现类似 “多继承” 功能的灵活方式。
// 父接口1
interface A {
void methodA();
}
// 父接口2
interface B {
void methodB();
}
// 子接口C同时继承A和B
interface C extends A, B { // 接口多继承,用逗号分隔多个父接口
void methodC(); // 子接口自己的方法
}对象之间进行大小比较关系
一、使用Comparable接口(“自然排序”) Comparable接口位于java.lang包下,包含一个抽象方法compareTo(T o),用于定义对象的 “自然排序规则”(如数字从小到大、字符串按字典序)。 核心特点: 类通过实现Comparable接口,自身定义比较规则(类似 “自带排序逻辑”); compareTo方法返回值: 正数:当前对象 > 目标对象; 0:当前对象 == 目标对象; 负数:当前对象 < 目标对象。 示例:比较学生对象的年龄
// 学生类实现Comparable接口,按年龄排序
class Student implements Comparable<Student> {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// 实现compareTo方法:按年龄比较
@Override
public int compareTo(Student other) {
// 返回当前对象年龄 - 目标对象年龄(从小到大排序)
return this.age - other.age;
}
// getter和toString方法
public int getAge() { return age; }
@Override
public String toString() { return name + "(" + age + ")"; }
}
// 测试比较
public class Test {
public static void main(String[] args) {
Student s1 = new Student("张三", 20);
Student s2 = new Student("李四", 18);
if (s1.compareTo(s2) > 0) {
System.out.println(s1 + " 年龄大于 " + s2); // 输出:张三(20) 年龄大于 李四(18)
}
}
}二、使用Comparator接口(“定制排序”) Comparator接口位于java.util包下,包含compare(T o1, T o2)方法,用于外部定义比较规则(不修改原类的代码,适合对已有类进行排序)。 核心特点: 无需修改被比较的类,通过 “比较器” 类实现比较规则; 可定义多种比较规则(如学生既可按年龄排,也可按姓名排); compare方法返回值规则同compareTo。 示例:为学生类定义多种比较规则
import java.util.Comparator;
// 学生类(未实现Comparable接口)
class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// getter和toString方法
public String getName() { return name; }
public int getAge() { return age; }
@Override
public String toString() { return name + "(" + age + ")"; }
}
// 比较器1:按年龄从小到大排序
class AgeComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
return s1.getAge() - s2.getAge();
}
}
// 比较器2:按姓名字典序排序
class NameComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
// 字符串的compareTo方法已实现Comparable接口
return s1.getName().compareTo(s2.getName());
}
}
// 测试比较
public class Test {
public static void main(String[] args) {
Student s1 = new Student("张三", 20);
Student s2 = new Student("李四", 18);
// 使用年龄比较器
AgeComparator ageComp = new AgeComparator();
if (ageComp.compare(s1, s2) > 0) {
System.out.println(s1 + " 年龄大于 " + s2); // 输出:张三(20) 年龄大于 李四(18)
}
// 使用姓名比较器
NameComparator nameComp = new NameComparator();
if (nameComp.compare(s1, s2) > 0) {
System.out.println(s1 + " 姓名在 " + s2 + " 之后"); // 输出:张三(20) 姓名在 李四(18) 之后(因"张"的拼音在"李"之后)
}
}
}两种的区别和应用场景

在 Java 中,Cloneable接口和对象拷贝(深拷贝 / 浅拷贝)是实现对象复制的重要机制。Cloneable本身是一个标记接口(无任何抽象方法),仅用于标识 “该类允许被克隆”,而拷贝的深浅则取决于具体实现逻辑。 一、Cloneable接口的核心作用 标记作用:一个类只有实现Cloneable接口,才能调用Object类的clone()方法进行克隆;否则会抛出CloneNotSupportedException异常。 无抽象方法:与普通接口不同,Cloneable内部没有任何需要实现的方法,仅作为 “可克隆” 的标识。 基本使用步骤: 类实现Cloneable接口; 重写Object类的clone()方法(protected改为public); 在clone()方法中调用super.clone(),并处理可能的异常。
class Person implements Cloneable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 重写clone()方法
@Override
public Person clone() throws CloneNotSupportedException {
// 调用父类的clone()实现浅拷贝
return (Person) super.clone();
}
// getter、setter和toString
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}二、浅拷贝(Shallow Copy) super.clone()默认实现的是浅拷贝:
对于基本数据类型(int、double等),会复制其值; 对于引用数据类型(对象、数组等),仅复制引用地址(新对象与原对象共享同一个引用对象)。
class Address {
private String city;
public Address(String city) { this.city = city; }
// getter、setter和toString
public void setCity(String city) { this.city = city; }
@Override
public String toString() { return "Address{city='" + city + "'}"; }
}
class Person implements Cloneable {
private String name;
private Address address; // 引用类型
public Person(String name, Address address) {
this.name = name;
this.address = address;
}
@Override
public Person clone() throws CloneNotSupportedException {
return (Person) super.clone(); // 浅拷贝
}
// getter、setter和toString
@Override
public String toString() {
return "Person{name='" + name + "', address=" + address + "}";
}
}
// 测试浅拷贝
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Address addr = new Address("北京");
Person p1 = new Person("张三", addr);
Person p2 = p1.clone(); // 克隆p1
// 修改p2的地址,p1的地址也会被改变(共享引用)
p2.getAddress().setCity("上海");
System.out.println(p1); // 输出:Person{name='张三', address=Address{city='上海'}}
System.out.println(p2); // 输出:Person{name='张三', address=Address{city='上海'}}
}
}三、深拷贝(Deep Copy) 深拷贝会完全复制所有层级的对象,包括引用类型的成员变量,使得新对象与原对象完全独立(不共享任何引用)。 实现深拷贝的两种方式: 对引用类型也进行克隆 在clone()方法中,不仅克隆当前对象,还需手动克隆其引用类型的成员变量。
class Address implements Cloneable {
private String city;
public Address(String city) { this.city = city; }
// 地址类也实现克隆
@Override
public Address clone() throws CloneNotSupportedException {
return (Address) super.clone();
}
// getter、setter和toString(同上)
}
class Person implements Cloneable {
private String name;
private Address address;
public Person(String name, Address address) {
this.name = name;
this.address = address;
}
@Override
public Person clone() throws CloneNotSupportedException {
// 1. 先克隆当前对象(浅拷贝)
Person clone = (Person) super.clone();
// 2. 再克隆引用类型成员(深拷贝关键步骤)
clone.address = this.address.clone();
return clone;
}
// getter、setter和toString(同上)
}
// 测试深拷贝
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Address addr = new Address("北京");
Person p1 = new Person("张三", addr);
Person p2 = p1.clone();
// 修改p2的地址,p1不受影响(引用独立)
p2.getAddress().setCity("上海");
System.out.println(p1); // 输出:Person{name='张三', address=Address{city='北京'}}
System.out.println(p2); // 输出:Person{name='张三', address=Address{city='上海'}}
}
}通过序列化实现深拷贝 将对象序列化为字节流,再反序列化为新对象,可自动实现所有层级的复制(需所有类实现Serializable接口)。 四、Cloneable接口与深拷贝的关系 Cloneable仅开启克隆功能,本身不决定拷贝方式(浅 / 深); 浅拷贝是super.clone()的默认行为,适合仅包含基本类型的对象; 深拷贝需要手动实现(克隆所有引用类型成员),适合包含多层引用的复杂对象; 若类中包含final修饰的引用变量,无法通过clone()实现深拷贝(final变量不可重新赋值)。 总结 Cloneable接口是对象克隆的 “开关”,而深拷贝是在其基础上的增强实现:
浅拷贝:简单高效,但可能导致对象共享引用,存在副作用; 深拷贝:完全独立,但实现复杂(需递归克隆所有引用类型)。
选择哪种拷贝方式,需根据对象的结构(是否包含引用类型)和业务需求(是否允许共享引用)决定。
抽象类和接口都是Java中多态的常见使用方式,都需要重点掌握.同时又要认清两者的区别 核⼼区别:抽象类中可以包含普通方法和普通字段,这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中不能包含普通普通,子类必须重写所有的抽想方法. 抽象类(abstract class)和接口(interface)是 Java 中实现抽象设计的两大核心机制,虽然很多开发者容易混淆。它们都能定义抽象方法、都不能直接实例化,但在语法规则、设计目标和使用场景上有本质区别。以下从 10 个核心维度详细对比: 一、语法定义与结构 抽象类 用abstract class声明,可包含: 抽象方法(abstract void method();,无方法体); 非抽象方法(有完整方法体,可直接实现逻辑); 各种访问权限的成员变量(public/protected/ 默认 /private); 构造方法(用于子类初始化时调用)。
abstract class Animal {
// 成员变量(可带初始值)
protected String name;
// 构造方法
public Animal(String name) {
this.name = name;
}
// 抽象方法(无实现)
public abstract void shout();
// 非抽象方法(有实现)
public void eat() {
System.out.println(name + "在吃东西");
}
}用interface声明,Java 8+ 可包含: 抽象方法(默认public abstract,可省略修饰符); 默认方法(default void method() {},带方法体,子类可重写); 静态方法(static void method() {},属于接口本身); 成员变量(默认public static final,必须初始化,本质是常量)
interface Flyable {
// 常量(默认public static final)
int MAX_HEIGHT = 1000;
// 抽象方法(默认public abstract)
void fly();
// 默认方法(带实现)
default void land() {
System.out.println("降落");
}
// 静态方法
static void info() {
System.out.println("这是飞行接口");
}
}二、继承 / 实现方式 抽象类:子类用extends继承,单继承(一个类只能继承一个抽象类)。 接口:类用implements实现,多实现(一个类可实现多个接口);接口之间用extends多继承(一个接口可继承多个接口)。

五、构造方法 抽象类:有构造方法(用于子类继承时初始化父类成员),但不能直接new实例。 接口:无构造方法(接口不涉及实例状态,无需初始化)。 六、设计目标 抽象类: 核心是 “代码复用”,通过抽取多个子类的共性实现(如Animal的eat()方法),让子类继承后直接使用,减少重复代码。 体现 “is-a” 关系(子类是父类的一种,如Dog is a Animal)。 接口: 核心是 “规范定义”,通过声明多个类的共性行为(如Flyable的fly()),让不同类(如Bird、Plane)都能实现,无关乎它们的继承关系。 体现 “can-do” 关系(类具备某种能力,如Bird can fly)。