接口(interface)
思考为什么接口不设计成抽象类?
使用抽象类每个类只能被扩展一次,假设实现类已经继承了某一个抽象类,则它就不能继续拓展其他类。
1 2 3 4 5 6 7 8 9 10
| abstract class Comparable {
} class People { }
class Employee extends Comparable,People {
}
|
接口则可以被实现多个,java设计过程中不允许多重继承,原因在于多重继承会让代码变得特别复杂。
1 2 3 4 5 6
| public interface class People { } public interface class Comparable { } public class Employee implements People,Comparable { }
|
静态和私有方法
接口允许含有静态方法,私有方法一般为接口自身使用,用法很有限,只能作为接口中其他方法中的辅助方法(辅助啥)。
默认方法
接口可以提供默认方法修饰(default),不过一般接口会被其他类实现,则默认方法一般来说会被覆盖。
接口与回调
回调是一种常见的程序设计模式,在这种模式中,可以指定某个特定事件发生时应该采取的动作。如Timer类中,你可以构建一个定时器,如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package com.jianfreespace;
import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.time.Instant;
public class TimePrinter implements ActionListener {
@Override public void actionPerformed(ActionEvent event) { System.out.println("At the tone,the time is" + Instant.ofEpochMilli(event.getWhen())); Toolkit.getDefaultToolkit().beep(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.jianfreespace;
import javax.swing.*;
public class StartMain {
public static void main(String[] args) {
var listener = new TimePrinter(); Timer t = new Timer(1000,listener); t.start(); JOptionPane.showMessageDialog(null,"Quit program?");
}
}
|
基于此代码会每一秒回调执行函数打印此语句,如图:

深拷贝与浅拷贝
java中深浅拷贝的概念属于需要了解的内容,java中的传递都是值传递,但如果你需要克隆一个对象时候,其默认的都是浅克隆。并且clone方法是protection,如果你需要克隆一个对象,需要先重写clone方法。值得一提的是,clone方法是作为Object基类的方法,那么可以确定的是,任意一个类都是默认继承了Object,事实上作为一个超类存在的,所以我们的对象都是有一个clone对象。我们重写的clone其实也就是重写Object的Clone。如果需要重写,那么需要类实现Cloneable接口。介绍说Cloneable是作为一个 标记接口
存在的。标记接口的唯一作用是运行类型在检查时使用instanceof。若你不实现这个接口类型,则编译器会报CloneNotSupportException的错误。
而clone默认是浅拷贝,这里写了一个例子,首先我定义了几个类为People、Employee
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| package com.jianfreespace;
public class People {
String name; int age;
People(String name,int age) { this.name = name; this.age = age; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
@Override public String toString() { return getClass().getName() + "[name=" + name + ",age=" + age +"]"; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| package com.jianfreespace;
import java.util.Date;
public class Employee implements Cloneable{
private String name; private Double salary; private Date hireDay; private People people;
Employee(String name, Double salary) { this.name = name; this.salary = salary; this.hireDay = new Date();
}
public People getPeople() { return people; }
public void setPeople(People people) { this.people = people; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Double getSalary() { return salary; }
public void setSalary(Double salary) { this.salary = salary; }
public Date getHireDay() { return hireDay; }
public void setHireDay(Date hireDay) { this.hireDay = hireDay; }
@Override public Employee clone() throws CloneNotSupportedException {
return (Employee) super.clone(); } }
|
这里我使用Employee引用了People对象,然后实现了clone方法。然后测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| package com.jianfreespace;
public class StartMain {
public static void main(String[] args) throws CloneNotSupportedException, InterruptedException {
Employee employee = new Employee("Jianfreespace",20000.0); employee.setPeople(new People("jian",23)); System.out.println("emplyee"); System.out.println(employee.getHireDay()); System.out.println(employee.getName()); System.out.println(employee.getSalary()); System.out.println(employee.getPeople()); Thread.sleep(3000); Employee employeeClone = employee.clone(); employeeClone.setSalary(30000.0); employeeClone.setName("hansJian"); employeeClone.getPeople().setAge(24); System.out.println("clone"); System.out.println(employeeClone.getHireDay()); System.out.println(employeeClone.getName()); System.out.println(employeeClone.getSalary()); System.out.println(employeeClone.getPeople());
System.out.println("emplyee"); System.out.println(employee.getHireDay()); System.out.println(employee.getName()); System.out.println(employee.getSalary()); System.out.println(employee.getPeople());
}
}
|
emplyee
Thu Sep 01 17:06:52 CST 2022
Jianfreespace
20000.0
com.jianfreespace.People[name=jian,age=23]
clone
Thu Sep 01 17:06:52 CST 2022
hansJian
30000.0
com.jianfreespace.People[name=jian,age=24]
emplyee
Thu Sep 01 17:06:52 CST 2022
Jianfreespace
20000.0
com.jianfreespace.People[name=jian,age=24]
结果就是,当我改变了people中的age时候,因为浅拷贝的原因,当你修改克隆对象中的people.age时,会改变原对象的值,这是因为clone是浅克隆,他们两个实际上引用的people是同一个对象,没有进行深层拷贝。这是存在的问题所在。若要进行深层拷贝,则需要重新clone方法时,克隆引用对象,即:
1 2 3 4 5 6
| @Override public Employee clone() throws CloneNotSupportedException { Employee employee = (Employee) super.clone(); employee.people = (People) people.clone(); return employee; }
|
emplyee
Thu Sep 01 17:44:26 CST 2022
Jianfreespace
20000.0
com.jianfreespace.People[name=jian,age=23]
clone
Thu Sep 01 17:44:26 CST 2022
hansJian
30000.0
com.jianfreespace.People[name=jian,age=24]
emplyee
Thu Sep 01 17:44:26 CST 2022
Jianfreespace
20000.0
com.jianfreespace.People[name=jian,age=23]
这样就完成了一次深拷贝的全部过程。