一、抽象类
class Shape {
public void draw() {
}
}
class Rect extends Shape{
@Override
public void draw() {
System.out.println("♦");
}
}
class Circle extends Shape {
@Override
public void draw() {
System.out.println("○");
}
}
class Flower extends Shape {
@Override
public void draw() {
System.out.println("❀");
}
}
class Triangle extends Shape {
@Override
public void draw() {
System.out.println("△");
}
}
1.1 语法规则
我们从以上的代码可以发现,父类Shape中的draw方法是一个空方法,没有什么实际的功能,具体的实现都是通过子类重写draw方法来实现的,因此像这种没有什么实际功能的方法可以将其设计为抽象方法,而包含抽象方法的类叫抽象类。
abstract class Shape {
abstract public void draw();
}
- 在方法前加abstrcat关键字,表示这是一个抽象方法,同时抽象方法没有方法体;
- 在类名前面加abstract关键字,表示这是一个抽象类
1.2 注意事项
- 抽象类不能直接实例化.
Shape shape = new Shape();
// 编译出错
像这样的代码会报错,抽象类不能直接实例化
- 抽象类中可以和普通类一样拥有成员变量和方法,这个非抽象方法和普通方法的规则都是一样的, 可以被重写,也可以被子类直接调用
abstract class shape{
public int age;
public static int count;
public void func() {
}
public abstract void draw();
}
- 抽象类是可以被继承的,并且可以发生向上转型
public class TestDemo {
public static void drawMap(Shape shape) {
shape.draw();
}
public static void main(String[] args) {
drawMap(new Rect());
drawMap(new Circle());
}
}
- 当一个普通类继承的抽象类,当前普通类一定要重写抽象类当中的抽象方法
class Shape {
public void draw() {
}
}
class Rect extends Shape{
@Override
public void draw() {
System.out.println("♦");
}
}
- 抽象方法不能是私有的,因为抽象方法就是通过继承来实现细节的,而将抽象方法设置为私有的,将不能被继承
abstract class Shape {
abstract private void draw();
}
// 编译出错
1.3 抽象类的作用
抽象类存在的最大意义就是为了被继承。
使用抽象类的场景就如上面的代码, 实际工作不应该由父类完成, 而应由子类完成. 那么此时如果不小心误用成父类了,使用普通类编译器是不会报错的. 但是父类是抽象类就会在实例化的时候提示错误, 因此可以让我们尽早发现问题.充分利用编译器的校验, 在实际开发中是非常有意义的。
二、接口
接口是抽象类的更进一步. 抽象类中还可以包含非抽象方法, 和字段. 而接口中包含的方法都是抽象方法, 字段只能包含静态常量.
2.1 语法规则
我们可以将刚才的抽象类Shape设计为一个接口
interface IShape {
void draw();
}
class Cycle implements IShape {
@Override
public void draw() {
System.out.println("○");
}
}
使用关键字interface 来标记为一个接口
2.2 注意事项
- 接口当中的方法 一定是抽象方法,因此不能有具体实现,接口当中的方法默认是:public abstract
interface IShape {
public abstract void draw();
//也可以简写为
void draw();
}
- 接口当中的成员变量,默认是 public static final,在定义的时候必须赋初值。
interface Ishape{
public static final int age=10;
//也可以简写为
int age=10;
}
- 使用default修饰的方法可以有具体的实现
interface IShape {
default void func() {
System.out.println("hahaha!");
}
}
- 接口不可以进行实例化
public class TestDemo {
public static void main(String[] args) {
IShape shape = new IShape();
// 编译出错
}
}
- 类和接口之间通过implements实现
interface Ishape{
void draw();
}
class Rect implements Ishape{
@Override
public void draw() {
System.out.println("♦");
}
}
class Circle implements Ishape{
@Override
public void draw() {
System.out.println("⚪");
}
}
- 一个类可以继承类,同时实现多个接口
interface A{
void funcA();
}
interface B{
void funcB();
}
interface C{
void funcC();
}
abstract class TestAbstract{
public abstract void funcTestAbstract();
}
class Test extends TestAbstract implements A,B,C{
@Override
public void funcA() {
}
@Override
public void funcB() {
}
@Override
public void funcC() {
}
@Override
public void funcTestAbstract() {
}
}
- 一个接口可以扩展多个接口,解决了多继承的问题
interface A{
void funcA();
}
interface B{
void funcB();
}
interface C{
void funcC();
}
interface D extends A,B,C{
void funcD();
}
2.3 常用的三个接口
class Student {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
@Override
public String toString() {
return "[" + this.name + ":" + this.score + "]";
}
}
Student[] students = new Student[] {
new Student("张三", 95),
new Student("李四", 96),
new Student("王五", 97),
new Student("赵六", 92),
};
现在想要给这个学生对象数组排序,而在数组中我们有一个现成的 sort 方法, 能否直接使用这个方法呢?
Arrays.sort(students);
System.out.println(Arrays.toString(students));
// 运行出错, 抛出异常.
Exception in thread "main" java.lang.ClassCastException: Student cannot be cast to
java.lang.Comparable
- Comparable接口
让Student 类实现 Comparable 接口, 并实现其中的 compareTo 方法
class Student implements Comparable {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
@Override
public String toString() {
return "[" + this.name + ":" + this.score + "]";
}
@Override
public int compareTo(Object o) {
Student s = (Student)o;
if (this.score > s.score) {
return -1;
} else if (this.score < s.score) {
return 1;
} else {
return 0;
}
}
}
当实现Comparable接口并重写compareTo方法后,在 sort 方法中会自动调用 compareTo 方法. compareTo 的参数是 Object , 其实传入的就是 Student 类型的对象.然后比较当前对象和参数对象的大小关系(按分数来算)
// 执行结果
[[王五:97], [李四:96], [张三:95], [赵六:92]]
- Comparator接口
class Student2 {
public String name;
public int score;
public Student2(String name, int score) {
this.name = name;
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", score=" + score +
'}';
}
}
public class TestDemo2 {
public static void main(String[] args) {
Student2[] students = new Student2[3];
students[0] = new Student2("aaa",89);
students[1] = new Student2("abc",19);
students[2] = new Student2("def",59);
System.out.println(Arrays.toString(students));
System.out.println("===============根据分数排序==============");
ScoreComparator scoreComparator = new ScoreComparator();
Arrays.sort(students,scoreComparator);
System.out.println(Arrays.toString(students));
}
}
在类外写一个分数比较的接口实现Comparator接口,并重写Compare方法
public class ScoreComparator implements Comparator<Student2> {
@Override
public int compare(Student2 o1, Student2 o2) {
if(o1.score > o2.score) {
return 1;
}else if(o1.score == o2.score) {
return 0;
}else {
return -1;
}
}
}
// 执行结果
[[aaa:89], [def:59], [abc:19]]
- Cloneable接口
在Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 “拷贝”. 但是要想合法调用 clone 方法, 必须要先实现 Clonable 接口, 否则就会抛出 CloneNotSupportedException 异常.
如何使用Cloneable 接口实现 “深拷贝”?
class Money implements Cloneable{
public double money = 12.8;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Person implements Cloneable{
public String name;
public Money m = new Money();
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person person2 = (Person)super.clone();
person2.m = (Money) this.m.clone();
return person2;
}
}
public class TestDemo3 {
public static void main(String[] args) throws CloneNotSupportedException {
Person person1 = new Person("张三");
Person person2 = (Person)person1.clone();
System.out.println(person1.m.money);
System.out.println(person2.m.money);
person2.m.money = 99.99;
System.out.println(person1.m.money);
System.out.println(person2.m.money);
}
// 执行结果
12.8
12.8
12.8
99.99
在重写clone方法的时候,首先需要将person1克隆一份得到person2,然后再将当前对象的m克隆一份给person2.m,此时就实现了深拷贝。