继承是Java中常用的一项特性,通过继承我们可以省去很多麻烦。
而Java中超类和子类对象之间的转换则是很多新手的常遇见的难题,要是处理不好,恐怕会因为这个很特殊的问题导致一些潜在的危险,让你整整一个晚上都在调试程序以解决一个让人抓狂的java.lang.ArrayStoreException异常。
哈哈,所谓救人一bug胜造七级浮屠,今天我们就来理一理Java中超类和子类对象之间的转换,看看它到底有什么不一样!
首先我们要了解一下转换的概念。
从子类向父类的转换称为向上转换(upcasting),通过向上转换,我们能够在编写程序时采用通用程序设计的思想,在需要使用子类对象的时候,通过把变量定义为父类型,我们可以通过一个变量,使用该父类型的所有子类型实例;从父类型向子类型的转换称为向下转换(downcasting),通过向下转换,我们能在必要的时候,将父类型变量转换成子类型变量,使用一些通过子类型才能够使用的方法。
那什么时候可以进行转换呢?
我们先来说一说向上转换,这个比较简单,而且限制还少。
还是老规矩,我们下面来看一段代码~~
来呀!!阿福,放代码~~~
class Father
{
};
class Son extends publc Father
{
};
在上面的程序中Father为超类,son是father的子类
那如何将子类转换为超类呢?
Father f = new Son(); //父类引用指向子类对象
显然,这样就可以了。需要注意,new Son()表示在在堆中分配了一段空间来存放类Son中的数据,并返回一个Son的对象,并赋值给Father的引用f,即f指向子类的对象,此时,子类的对象并没有定义一个名字。
也就是说上面的语句等价于:
Son s = new Son();
Father f = s;
注:父类不可调用子类新增的方法,即f不可调用s新增的方法。
好啦,子类转父类就是这样简单,接下来该重点看看父类转子类啦。
按理论上分析的话,父类转子类是不可以实现的。因为子类继承于父类,并新增了一些父类并没有的东西,也就是说,子类对象一般都比父类对象包含更多的东西。这样的话,子类如果访问子类新增的内容, 而这些内容父类并没有,所以就会报错。
那Java里面父类到底可不可以转子类呢?
可以!但是需要满足一个前提,即该父类对象已经指向了子类对象。
如:
Father f = new Son(); //父类引用指向子类对象
Son s2 = (Son)f; //可以
因为当子类强制转换为父类对象时,并没有实际丢失它原有内存空间(比父类多的那些部分)
只是暂时不可访问,所以能再转回来。
此外,当该父类是调用子类构造器创建的时候,它也可以转换为子类。
如:
Employee b=new Manager("a",1000,2,1,225);//父类调用子类的构造器 创建了一个父类对象
这个原理其实和上面的情况一样,因为它也是父类引用指向了子类对象,因此也可以进行转换。
当然,为了防止报ClassCastExcept异常,一般可以在前面加一条判断句 if(father instanceof Son);
如:
Father f = new Son(); //父类引用指向子类对象
if(father instanceof Son)
{
Son s2 = (Son)f;
}
这样就可以避免出错。
通过上文的了解,大家可能心里已经有了一些理解,最后再提一下对象在继承关系中的改变
对象的赋值是地址标识的传递,即两个对象名共同使用同一段内存地址。在Java中,对父类与子类对象之间的赋值作了如下规定:
1、子类对象名可以赋值给父类对象名;但父类对象名不可以赋值给子类对象名。
即:父类对象名=子类对象名;
2、如果一个父类对象名已经被子类对象名所赋值,那可以将父类对象名经强制转换赋值给子类对象名。
即:子类对象名=(子类类名)父类对象名;
常用的一种形式:方法中形参用父类型,实参用子类的对象名.
总结
对类进行造型转换的应参考以下原则:
1.总是可以“父=子”赋值。此时不需要类型转换。
2.可以执行类型转换“子=(子)父”,但需要运行时进行检查。如果父类变量引用的是正确的子类型,赋值将执行。如果父类变量引用的是不相关的子类型,将会生成class castException异常。
即:如果父类的实例是在子类的实例上塑造的,“子=(子)父”时就不会抛出异常。
如:
A 是B的父类。
A a= new B(); //父类A的对象a是在子类B的对象上塑造的。
就可以:
B b= (B)a;
3.决不能在不相关的任何类之间执行类的赋值或者类型转换。即类的造型转换仅限于有继承关系的俩个类的对象之间。
好啦,如果大家还是不太明白,可以试一试下面的程序,亲自上手试一试会了解得更透彻一些。
package inheritance;
public class test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Employee e;
Manager boss =new Manager("Searchin",52000,2018,10,25);
Employee[] staff=new Employee[3];
staff[0]=boss;//子类转父类
Employee b=new Manager("a",1000,2,1,225);//父类调用子类的构造器 创建了一个父类对象
//Manager b=new Employee("a",1000,2,1,225);
Manager a=(Manager)staff[0];//强制类型转换
System.out.println(staff[0].getName());
System.out.println(a.getName());
boss.setBonus(5000);
//staff[0].setBonus(5000);
}
}
package inheritance;
import java.time.*;
public class Employee
{
private String name;
private double salary;
private LocalDate hireDay;
public Employee(String name, double salary, int year, int month, int day)
{
this.name = name;
this.salary = salary;
hireDay = LocalDate.of(year, month, day);
}
public String getName()
{
return name;
}
public double getSalary()
{
return salary;
}
public LocalDate getHireDay()
{
return hireDay;
}
public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
}
package inheritance;
public class Manager extends Employee
{
private double bonus;
public Manager(String name, double salary, int year, int month, int day)
{
super(name, salary, year, month, day);
bonus = 0;
}
public double getSalary()
{
double baseSalary = super.getSalary();
return baseSalary + bonus;
}
public void setBonus(double b)
{
bonus = b;
}
}