引入
在学习这两个新概念前,必须要了解继承,向上转型,向下转型等知识点Java面向对象之继承(extends) - 掘金
重写
- 而在每个子类中都有一个和基类Object中的toString方法重名的方法,并且在方法体上方都标注了
@Override,这时就是在子类中对父类方法进行了重写。 - 重写会受到访问修饰符的影响,在重写方法时,访问修饰符的访问权限不能降低,即
public>protected>default>private
多态
-
我们之前举得例子中,遍历输出
Arraylist<People> peoples中的内容,内容中既持有Student类的对象,又有持有Teacher类的对象,而且我们输出的对象并不是一串对象所在的地址,而是对象的内容,这是因为我们在People的子类Student和Teacher中都创建了toString方法,在输出时持有子类对象的父类引用调用了子类的toString方法,那么对于People类的Arraylist<People> peoples容器中的Student对象和Teacher对象来说,遍历出的内容会自动匹配相对应的其类中toString方法进行输出,当子类中没有该方法的重写才会去调用基类中的toString方法,也就是输出对象所在的地址,这种特性就叫做多态。 -
多态是java的一种特性,持有子类对象的父类引用访问子类中的方法,在不同的子类中如果有同名的方法会自动匹配,也就是持有子类的父类对象调用和父类的同名的子类方法,此时会根据调用对象的特征(持有的是哪个类型的子类)呈现多种状态。
// 定义抽象类
abstract class Animal {
public abstract void makeSound();
}
// 定义具体子类
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Woof!");
}
}
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Meow!");
}
}
// 使用抽象类引用
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog(); // 使用抽象类引用指向具体子类对象
Animal myCat = new Cat();
myDog.makeSound(); // 输出 "Woof!"
myCat.makeSound(); // 输出 "Meow!"
}
}
多态形成条件
- 实现多态,必须要存在继承的关系
- 父类变量必须持有了子类的对象
方法的重写
- 对于抽象类子类中必须重写父类的方法(即为必须都要有这个方法),没有只需return null即可,但子类必须有,重写即为子类中方法的名字,参数列表必须时相同的,这样才可以达成覆盖父类的方法。这一过程就是方法的重写
多态中的转型
- 向上转型
- 父类持有子类的对象
- 向下转型
- 父类引用持有父类对象不能向下转型,即使是强制类型转换也不行
Student stu1 = (Student)(new People());//这行代码是无法运行的,只有父类引用持有子类对象的对象引用才能向下转型 - 即为,我们可以将向上转型的对象,重新向下转型,以便于访问该对象原本类中的属性和方法
- 父类引用持有父类对象不能向下转型,即使是强制类型转换也不行
- 多态中的转型问题
- 在向下转型时,如果被转的引用类型变量,对应的实际类型和目标类型不是同一种类型,那么在转换的时候就会出现ClassCastException
- 可以使用instanceof来做转型前的校验
- 使用格式:
- 对象名 instanceof 类型
- 判断一个对象是否是一个类的实例,是向下转型操作的安全员
- 通俗的理解:判断关键字左边的对象,是否是右边的类型,返回boolean类型结果
// 父类
class Animal {
public void eat() {
System.out.println("动物吃东西");
}
}
// 子类1
class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃骨头");
}
// 子类特有方法
public void watchHouse() {
System.out.println("狗看家");
}
}
// 子类2
class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
// 子类特有方法
public void catchMouse() {
System.out.println("猫抓老鼠");
}
}
// 测试类
public class InstanceofExample {
public static void main(String[] args) {
System.out.println("=== instanceof 关键字使用示例 ===");
// 1. 创建对象
Animal animal1 = new Dog(); // 向上转型
Animal animal2 = new Cat(); // 向上转型
Animal animal3 = new Animal();
// 2. 使用 instanceof 进行类型判断
System.out.println("\n=== 类型检查 ===");
System.out.println("animal1 instanceof Animal: " + (animal1 instanceof Animal)); // true
System.out.println("animal1 instanceof Dog: " + (animal1 instanceof Dog)); // true
System.out.println("animal1 instanceof Cat: " + (animal1 instanceof Cat)); // false
System.out.println("animal2 instanceof Animal: " + (animal2 instanceof Animal)); // true
System.out.println("animal2 instanceof Dog: " + (animal2 instanceof Dog)); // false
System.out.println("animal2 instanceof Cat: " + (animal2 instanceof Cat)); // true
// 3. 安全向下转型(先判断再转型)
System.out.println("\n=== 安全向下转型 ===");
// 处理 animal1
if (animal1 instanceof Dog) {
Dog dog = (Dog) animal1; // 向下转型
dog.eat(); // 调用重写的方法
dog.watchHouse(); // 调用Dog特有的方法
} else {
System.out.println("animal1 不是 Dog 类型");
}
// 处理 animal2
if (animal2 instanceof Cat) {
Cat cat = (Cat) animal2; // 向下转型
cat.eat(); // 调用重写的方法
cat.catchMouse(); // 调用Cat特有的方法
} else {
System.out.println("animal2 不是 Cat 类型");
}
// 4. 多态集合处理
System.out.println("\n=== 多态集合处理 ===");
Animal[] animals = {new Dog(), new Cat(), new Dog(), new Animal(), new Cat()};
int dogCount = 0;
int catCount = 0;
int animalCount = 0;
for (Animal animal : animals) {
if (animal instanceof Dog) {
dogCount++;
Dog dog = (Dog) animal;
dog.watchHouse();
} else if (animal instanceof Cat) {
catCount++;
Cat cat = (Cat) animal;
cat.catchMouse();
} else if (animal instanceof Animal) {
animalCount++;
System.out.println("这是一个普通动物");
}
}
System.out.println("狗的数量: " + dogCount);
System.out.println("猫的数量: " + catCount);
System.out.println("普通动物的数量: " + animalCount);
// 通用处理方法:根据不同类型执行不同操作
public static void processAnimal(Animal animal) {
System.out.println("\n处理动物:");
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
System.out.println("这是一只狗");
dog.watchHouse();
} else if (animal instanceof Cat) {
Cat cat = (Cat) animal;
System.out.println("这是一只猫");
cat.catchMouse();
} else if (animal instanceof Animal) {
System.out.println("这是一个普通动物");
}
// 所有动物都会吃东西
animal.eat();
}
}
注释@Override的重要性
- 注意被重写的方法最好加上注释
@Override,这样ide可以帮我们检查父类中有没有该方法,没有会提醒我们要加上。