*向上转型:*子类对象转为父类,父类可以是接口。公式:Father f=new Son();Father是父类或接口,son是子类。
*向下转型:*父类对象转为子类。公式:Son s=(Son)f;
package demo2;
public class Human {
public void sleep(){
System.out.println("Human sleep..");
}
public static void main(String[] args) {
Human human=new Male();//向上转型
human.sleep();
Male male=new Male();
male.sleep();
// human.speak();此方法不能编译。报错human没有此方法
}
}
class Male extends Human{
@Override
public void sleep() {
// TODO Auto-generated method stub
System.out.println("Male sleep..");
}
public void speak(){
System.out.println("I am Male");
}
}
class Female extends Human{
@Override
public void sleep() {
// TODO Auto-generated method stub
System.out.println("Female sleep..");
}
public void speak(){
System.out.println("I am Female");
}
}
注意:向上转型不能强制转型。向上转型后父类的引用所指向的属性是父类的属性。如果子类重写了父类的方法,那么父类引用指向的或者调用的方法是子类的方法,这个叫做动态绑定。向上转型后父类引用不能调用子类自己的方法,就是父类没有但是子类有的方法。如果一定需要调用子类的属性呢?如果不适用向下转型就需要给需要的属性写getter方法。
例如:
package demo2;
public class Human {
String name="Human";
public String getName(){
return this.name;
}
public void sleep(){
System.out.println("Human sleep..");
}
public static void main(String[] args) {
Human human=new Male();//向上转型
System.out.println(human.getName());//Male
System.out.println(human.name);//Human
}
}
class Male extends Human{
String name="Male";
public String getName(){
return this.name;
}
@Override
public void sleep() {
// TODO Auto-generated method stub
System.out.println("Male sleep..");
}
public void speak(){
System.out.println("I am Male");
}
}
class Female extends Human{
String name="Female";
public String getName() {
return this.name;
}
@Override
public void sleep() {
// TODO Auto-generated method stub
System.out.println("Female sleep..");
}
public void speak(){
System.out.println("I am Female");
}
}
如果一定要使用子类扩展的方法,比如speak方法,就只能向下转型了。
向下转型需要考虑安全性,如果父类引用的对象是父类本身,那么在向下转型的过程中是不安全的,变异不会出错,但是运行时会出现java.lang.ClassCastException错误。它可以使用instanceof来避免出现此类错误既能否向下转型,只有先经过向上转型的对象才能继续向下转型。【instanceof是Java、php的一个二元操作符(运算符),和==,>,<是一类东西。作用是判断其左边对象是否为其右边类的实例,返回boolean类型的数据】
例子:
package demo2;
public class Human {
public void sleep(){
System.out.println("Human sleep..");
}
public static void main(String[] args) {
Human human=new Male();//向上转型
Human human2=new Human();
Male male=(Male)human;
male.speak();
// Male male2=(Male)human2;
// male2.speak();
//出现java.lang.ClassCastException
if (human2 instanceof Male) {
Male male2=(Male)human2;
male2.speak();
}
}
}
class Male extends Human{
@Override
public void sleep() {
// TODO Auto-generated method stub
System.out.println("Male sleep..");
}
public void speak(){
System.out.println("I am Male");
}
}
为什么不直接Son s=new Son();?? 原因是例子太简单,没有考虑过要把类的对象传递给其他函数的例子
例子:体现向上转型的好处,节省代码(多态性)
package demo2;
public class Human {
public void sleep(){
System.out.println("Human sleep..");
}
public static void doSleep(Human human) {
human.sleep();
}
public static void main(String[] args) {
doSleep(new Male());
doSleep(new Female());
}
}
class Male extends Human{
@Override
public void sleep() {
// TODO Auto-generated method stub
System.out.println("Male sleep..");
}
}
class Female extends Human{
@Override
public void sleep() {
// TODO Auto-generated method stub
System.out.println("Female sleep..");
}
}
假如不向上转型就必须写两个doSleep函数,一个传递Male类对象,一个传递Female类对象。一旦向上转型了,当需要用到子类的方法是,就需要向下转型。
总结
1.把子类直接赋值给父类引用叫做upcasting向上转型,向上转型不用强制转型。
2.把指向子类对象的父类引用赋值给子类引用叫做向下转型downcasting,需要强制类型转换,要向下转型,必须先向上转型,为了安全可以使用instanceof判断。
3.upcasting会丢失子类特有的方法,但是子类overriding父类的方法,子类方法邮箱,向上转型只能引用父类对象的属性,要引用子类对象的属性,则要写getter函数。
4.向上转型的作用,减少重复代码,父类为参数,调用是用子类作为参数,就是利用了向上转型。这样使代码变得简洁,体现了JAVA的抽象编程思想。