[Java初学]Java上溯造型(upcasting)与下溯造型(Downcasting)

Java上溯造型(upcasting)与下溯造型(Downcasting)

上溯造型(upcasting)

这个术语缘于继承关系图的传统画法:将基类至于顶部,而向下发展的就是派生类。

文章使用的完整代码如下


public class Main {
	public static void main(String[] args) {
		Dog dog=new Dog();
		upcasting(dog);//汪汪汪。。。
		dog.tail();//摇尾巴...
		dog.speak();//汪汪汪。。。
		
		Animal animal=new Dog();
		animal.speak();//汪汪汪。。。
//		animal.tail();//The method tail() is undefined for the type Animal
	
		
		//下溯
		Dog d =(Dog)animal;
		d.tail();
	
		//错误的下溯
//		Animal a2=new Animal();
//		Dog d2=(Dog)a2;
//		d2.tail();
//		运行时报错:Exception in thread "main" java.lang.ClassCastException: class shangsu.Animal cannot be cast to class shangsu.Dog (shangsu.Animal and shangsu.Dog are in unnamed module of loader 'app')
//		at shangsu.Main.main(Main.java:16)	
	}
	
    public static void upcasting(Animal animal){  
        animal.speak();  
//        animal.tail();//编译错误:The method tail() is undefined for the type Animal
        return;
    }  
    
}

 class Animal {
	public void speak(){
//		System.out.println("阿巴阿巴。。。");
	}
}
 
 
 class Dog extends Animal{
 
	@Override
	public void speak() {
		System.out.println("汪汪汪。。。");
	}
	
	public void tail(){
		System.out.println("摇尾巴...");
	}
	
}

由于upcasting(Animal animal)方法的参数是 Animal类型的,因此如果传入的参数是Animal的子类,传入的参数就会被转换成父类Animal类型,这样你创建的 Dog对象 能使用的方法只是Animal中的签名方法;也就是说,在上溯的过程中,Dog的接口变窄了,它本身的一些方法(例如tail方法)就不可见

如果你 想使用Dog中存在而Animal中不存在的方法 (比如tail方法),编译时不能通过。由此可见,上溯造型是安全的类型转换。另一方面,虽然upcasting(Animal animal)方法的参数是 Animal类型,但传入的参数可以是 Animal的派生类 (这也是OO编程中惯用的编程方法),这里面就有个对象的类型识别问题,也就是运行时类型识别(run-time type identification,缩写为RTTI) 。RTTI的功能主要是由Class类实现的。

简单来说,上溯造型就是把子类向上转换为父类类型Animal animal=new Dog();,这样转型后只能使用父类中已经声明过的方法(叫)而不能通过转换后的父类调用子类特有的方法(摇尾巴)

下溯造型(Downcasting)

不一定安全,在编译时检测不到,运行时会抛出ClassCastException异常,对于测试来说,这样的错误也是很难检测的。

  • 将父类对象显示的转换成子类类型。
  • 曾经向上转换过的对象,才能再向下转换。对象不允许不经过上溯造型而直接下溯造型。
Animal animal=new Dog();
Dog d =(Dog)animal;
d.tail();

不正确的下溯示例:

Animal a2=new Animal();//动物类对象a2
Dog d2=(Dog)a2;//下溯为Dog类对象
d2.tail();
//编译时无错误

运行时报错Exception in thread "main" java.lang.ClassCastException: class shangsu.Animal cannot be cast to class shangsu.Dog (shangsu.Animal and shangsu.Dog are in unnamed module of loader 'app') at shangsu.Main.main(Main.java:16)

正确示例:

public static void downcasting(Animal animal){
	if(animal instanceof Dog){
		Dog dog=(Dog)animal;
		dog.speak();
		dog.tail();
	}
}
Java类中重写equals()用到的下溯造型

(2021.9.15更新)

Q:为什么要重写equals() ?

A:引用类型比较,要使用equals()方法,如果使用==比较,它比较的是两个引用类型的变量是否是同一个对象。

同时,调用List的contains() indexOf()方法 都需要实现equals()方法

对于自己创造的一个类,本身并没有重写equals()方法,如果需要比较两个类实例是否相等 就必须要重写(调用List的contains() indexOf()方法 也需要重写)

在廖雪峰老师的JAVA教程的一个练习中就有重写equals()的练习,在编写时,我发现这个就是下溯造型,于是在这里写出。

class Person {
	String firstName;
	String lastName;
	int age;
public Person(String firstName, String lastName, int age) {
	this.firstName = firstName;
	this.lastName = lastName;
	this.age = age;
}

/**
 * TODO: 覆写equals方法
 */
@Override
public boolean equals(Object o) {
	if(this == o) {
		return true;
	}
	if(o instanceof Person) {
		Person pp=(Person)o;
		if(this.firstName.equals(pp.firstName) && this.lastName.equals(pp.lastName) &&this.age==pp.age) {
			return true;
		}
		
	}
	return false;
}

重写后即可完成main函数中的测试

public class Main {
	public static void main(String[] args) {
		List<Person> list = List.of(new Person("Xiao", "Ming", 18), new Person("Xiao", "Hong", 25),
				new Person("Bob", "Smith", 20));
		boolean exist = list.contains(new Person("Bob", "Smith", 20));
		System.out.println(exist ? "测试成功!" : "测试失败!");
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值