目录
一、抽象类
1. 定义
2. 示例代码
3. 特点
4. 使用场景
二、接口
1. 定义
2. 示例代码
3. 特点
三、抽象类和接口的区别
四、接口与抽象类的结合
五、自定义排序方法
六、总结
在 Java 编程中,抽象类和接口是两个极为重要的概念,它们在代码设计和架构搭建中扮演着关键角色。合理运用抽象类和接口,能够提升代码的可维护性、可扩展性和可复用性。本文将深入探讨 Java 抽象类和接口的定义、特点、区别以及使用场景。
一、抽象类
1. 定义
抽象类是一种不能被实例化的类,它为子类提供了一个通用的模板。抽象类可以包含抽象方法和具体方法。抽象方法是没有方法体的方法,它只定义了方法的签名,具体的实现需要由子类来完成。在 Java 中,使用 abstract
关键字来定义抽象类和抽象方法。
2. 示例代码
// 定义抽象类
abstract class Animal {public abstract void run(); // 抽象方法public void sleep() { // 具体方法System.out.println("Animal is sleeping.");}
}
class Dog extends Animal { // 子类继承抽象类并实现抽象方法@Overridepublic void run() {System.out.println("Dog is running!");}
}
public class Main {public static void main(String[] args) {// Animal animal = new Animal(); // 不能实例化抽象类Dog dog = new Dog();dog.run();dog.sleep();}
}
3. 特点
- 不能实例化:抽象类不能直接创建对象,只能通过其子类进行实例化。这是因为抽象类是作为模板使用的,本身需要子类继承来实现抽象类中的方法,且抽象方法没有具体的实现,无法直接使用。
- 可以包含抽象方法和具体方法:抽象类中可以写抽象方法,也可以写普通方法。抽象方法用于定义子类必须实现的行为,而普通方法则提供了一些通用的实现,子类可以直接使用。
- 可以有构造方法:抽象类可以有构造方法,用于初始化子类对象。当子类创建对象时,会先调用抽象类的构造方法。
- 只能单继承:一个子类只能继承一个抽象类,因为抽象类也是父类。
4. 使用场景
当多个类具有共同的特征和行为,并且其中一些行为的实现是相同的,可以使用抽象类来提取这些共同的部分。例如,在一个动物抽象类中,不同的动物(如狗、猫、鸟等)都有睡觉的行为,这部分行为可以定义成普通方法在抽象类中实现,子类直接调用即可。而不同动物的叫声则可以定义为抽象方法,由不同的子类来重写。
二、接口
1. 定义
接口是一种完全抽象的类型,只包含抽象方法和常量。在 Java 8 及以后的版本中,接口还可以包含默认方法和静态方法。默认方法提供了接口方法的默认实现,子类可以选择是否重写;静态方法则可以直接通过接口名调用。使用 interface
关键字来定义接口。
2. 示例代码
interface Flyable { // 定义接口 void fly(); // 抽象方法 default void land() { // 默认方法System.out.println("Flying object is landing.");}static void info() { // 静态方法System.out.println("This is a flyable object.");}
}
class Bird implements Flyable { // 类实现接口@Overridepublic void fly() {System.out.println("Bird is flying.");}
}
public class Main {public static void main(String[] args) {Bird bird = new Bird();bird.fly(); //子类调用父类的抽象方法bird.land(); Flyable.info(); 通过类名直接调用接口中的静态方法}
}
3. 特点
- 不能实例化:接口不能直接创建对象,需要通过实现类来实现接口中的方法。
- 只能包含抽象方法、默认方法、静态方法和常量:接口中的方法默认是
public abstract
的,常量默认是public static final
的。 - 可以多实现:一个类可以实现多个接口,从而实现多重继承的效果。这使得类可以同时具备多个不同接口定义的行为。
- 没有构造方法:接口中不能有构造方法,因为接口不需要进行实例化。
三、抽象类和接口的区别
比较项 | 抽象类 | 接口 |
---|---|---|
实例化 | 不能实例化 | 不能实例化 |
方法类型 | 可以包含抽象方法和具体方法 | 主要包含抽象方法,Java 8 及以后可以有默认方法和静态方法 |
成员变量 | 可以有各种类型的成员变量 | 只能有 public static final 类型的常量 |
构造方法 | 可以有构造方法 | 没有构造方法 |
继承 / 实现 | 一个子类只能继承一个抽象类 | 一个类可以实现多个接口 |
设计目的 | 用于表示一组具有相似特征和行为的类的抽象 | 用于定义一组行为规范,实现不同类之间的行为约束 |
四、接口与抽象类的结合
在 Java 编程里,接口和抽象类各自具备独特的特性与用途,将它们结合使用能充分发挥二者的优势,设计出更灵活、可维护且可扩展的代码架构。以下会从结合使用的方式、示例以及使用场景展开详细阐述。
- 抽象类实现接口:抽象类可以实现接口,它既能够为接口中的部分方法提供默认实现,也可以把未实现的方法继续定义为抽象方法,让具体的子类去完成实现。这种方式有助于提取公共的实现逻辑,降低代码的重复度。
- 具体类继承抽象类并实现接口:具体类可以先继承一个抽象类,再实现多个接口。这样一来,具体类既能继承抽象类中的属性和方法,又能具备多个接口所定义的行为,实现多重特性的组合
五、自定义排序方法
重写 Arrays.sort()
方法,重写后的方法可以对特定对象进行排序,前提是对象实现了Comparable接口
package com.qcby;public class Arrays2 {/**** @param o*/public static void sort(Comparable[] o){ //入参是一个Comparable数组,数组中的值可以是任意对象类型,但前提是实现了Comparable类quickSort(o,0,o.length-1);}public static void quickSort(Comparable[] arr,int left,int right){ //利用快排对数组进行排序,排序比较的是值if(left>right){return;}int i = left;int j = right;//定义baseComparable base = arr[left];while (i!=j){while (arr[j].compareTo(base) >=0 && i<j){ //compareTo是在类中重写Comparable的方法,用于比较对象的年龄j--;}while (arr[i].compareTo(base) <=0 && i<j){i++;}Comparable temp = arr[j];arr[j] = arr[i];arr[i] = temp;}arr[left] = arr[i];arr[i] = base;quickSort(arr,left,i-1);quickSort(arr,i+1,right);}}
重写了Comparable接口的Person对象
public class Person implements Comparable<Person> {public String name;public int age;public double height;public Person(String name,int age,double height){this.name = name;this.age = age;this.height = height;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", height=" + height +'}';}@Override //重写了Comparable的compareTo方法public int compareTo(Person o) {return age - o.age; //指定 age 进行从小到大排序return o.age - age; //指定 age 进行从大到小排序return (int) (height - o.height);}
}
测试+输出结果
package com.qcby;import java.util.Arrays;public class Test {public static void main(String[] args) {Person p1 = new Person("小黑",18,185.0);Person p2 = new Person("小白",22,182.5);Person p3 = new Person("小黄",20,174.5);Person p4 = new Person("小何",24,178.5);Person[] arrPersons = new Person[]{p1,p2,p3,p4};//实现Comparable接口Arrays.sort(arrPersons);System.out.println(Arrays.toString(arrPersons));}
}
六、总结
抽象类和接口都是 Java 中实现抽象和多态的重要工具,但它们的设计目的和使用场景有所不同。在实际编程中,需要根据具体的需求来选择使用抽象类还是接口。如果多个类之间有共同的特征和行为,并且部分行为的实现是相同的,那么可以使用抽象类;如果需要定义一组行为规范,让不同的类来实现这些规范,或者需要实现多重继承的效果,那么可以使用接口。合理运用抽象类和接口,能够使代码更加清晰、灵活和可维护。