protected String name;
public Animal(String name) {
this.name = name;
}
}
另外我们再提供一组接口, 分别表示 “会飞的”, “会跑的”, "会游泳的
interface IFlying {
void fly();
}
interface IRunning {
void run();
}
interface ISwimming {
void swim();
}
接下来我们创建几个具体的动物
猫, 是会跑的
class Cat extends Animal implements IRunning {
public Cat(String name) {
super(name);
}
@Override
public void run() {
System.out.println(this.name + “正在用四条腿跑”);
}
}
鱼, 是会游的
class Fish extends Animal implements ISwimming {
public Fish(String name) {
super(name);
}
@Override
public void swim() {
System.out.println(this.name + “正在用尾巴游泳”);
}
}
蛙, 既能跑, 又能游(两栖动物)
class Frog extends Animal implements IRunning, ISwimming {
public Frog(String name) {
super(name);
}
@Override
public void run() {
System.out.println(this.name + “正在往前跳”);
}
@Override
public void swim() {
System.out.println(this.name + “正在蹬腿游泳”);
}
}
还有一种神奇的动物, 水陆空三栖, 叫做 “鸭子”
class Duck extends Animal implements IRunning, ISwimming, IFlying {
public Duck(String name) {
super(name);
}
@Override
public void fly() {
System.out.println(this.name + “正在用翅膀飞”);
}
@Override
public void run() {
System.out.println(this.name + “正在用两条腿跑”);
}
@Override
public void swim() {
System.out.println(this.name + “正在漂在水上”);
}
}
上面的代码展示了 Java 面向对象编程中最常见的用法:
一个类继承一个父类, 同时实现多种接口.
继承表达的含义是 is - a 语义, 而接口表达的含义是 具有 xxx 特性
这样设计有什么好处呢? 时刻牢记多态的好处, 让程序猿忘记类型. 有了接口之后, 类的使用者就不必关注具体类型, 而 只关注某个类是否具备某种能力
接口间的继承
接口可以继承一个接口, 达到复用的效果. 使用 extends 关键字
interface IRunning {
void run();
}
interface ISwimming {
void swim();
}
// 两栖的动物, 既能跑, 也能游
interface IAmphibious extends IRunning, ISwimming {
}
class Frog implements IAmphibious {
…
}
Clonable 接口和深拷贝
Java 中内置了一些很有用的接口, Clonable 就是其中之一
Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 “拷贝”
但是要想合法调用 clone 方法, 必须要先 实现 Clonable 接口, 否则就会抛出 CloneNotSupportedException 异常
class Animal implements Cloneable {
private String name;
@Override
public Animal clone() {
Animal o = null;
try {
o = (Animal)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
}
public class Test {
public static void main(String[] args) {
Animal animal = new Animal();
Animal animal2 = animal.clone();
System.out.println(animal == animal2);
}
}
// 输出结果
// false
浅拷贝 VS 深拷贝
Cloneable 拷贝出的对象是一份 “浅拷贝” 观察以下代码:
public class Test {
static class A implements Cloneable {
public int num = 0;
@Override
public A clone() throws CloneNotSupportedException {
return (A)super.clone();
}
}
static class B implements Cloneable {
public A a = new A();
@Override
public B clone() throws CloneNotSupportedException {
return (B)super.clone();
}
}
public static void main(String[] args) throws CloneNotSupportedException {
B b = new B();
B b2 = b.clone();
b.a.num = 10;
System.out.println(b2.a.num);
}
}
// 执行结果
10
通过 clone 拷贝出的 b 对象只是拷贝了 b 自身, 而没有拷贝内部包含的 a 对象. 此时 b 和 b2 中包含的 a 引用仍 然是指向同一个对象. 此时修改一边, 另一边也会发生改变
总结
==
抽象类和接口都是 Java 中多态的常见使用方式
.同时又要认清两者的区别(重要!!! 常见面试题)
核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中不 能包含普通方法, 子类必须重写所有的抽象方法
如之前写的 Animal 例子. 此处的 Animal 中包含一个 name 这样的属性, 这个属性在任何子类中都是存在的. 因此此处的 Animal 只能作为一个抽象类, 而不应该成为一个接口
class Animal {
最后
金三银四马上就到了,希望大家能好好学习一下这些技术点
学习视频:
大厂面试真题:
见使用方式
.同时又要认清两者的区别(重要!!! 常见面试题)
核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中不 能包含普通方法, 子类必须重写所有的抽象方法
如之前写的 Animal 例子. 此处的 Animal 中包含一个 name 这样的属性, 这个属性在任何子类中都是存在的. 因此此处的 Animal 只能作为一个抽象类, 而不应该成为一个接口
class Animal {
最后
金三银四马上就到了,希望大家能好好学习一下这些技术点
学习视频:
[外链图片转存中…(img-r3ZQwzkt-1719275899568)]
大厂面试真题:
[外链图片转存中…(img-NE0u88lw-1719275899569)]