JAVA对象转型分为两种:一种叫向下转型,而另外一种是向上转型(父类对象的引用或者叫基类对象的引用指向子类对象,这就是向上转型)。那什么叫转型呢?好比把double类型转成float类型,把float类型转成int类型,把long类型转成int类型,这些都叫转型。把一种形式转成另一种形式就叫转型。除了基础数据类型的转型以外(基础数据类型的转型:小的能够转成大的,大的也能够转成小的。),对象领域里面也有对象之间的转型。java
1.1.对象转型实例一编程
1 package javastudy.summary; 2 3 /** 4 * 父类Animal 5 * @author gacl 6 * 7 */ 8 class Animal { 9 10 public String name; 11 12 public Animal(String name) { 13 this.name = name; 14 } 15 } 16 17 /** 18 * 子类Cat继承Animal 19 * @author gacl 20 * 21 */ 22 class Cat extends Animal { 23 24 /** 25 * Cat添加本身独有的属性 26 */ 27 public String eyeColor; 28 29 public Cat(String n, String c) { 30 super(n);//调用父类Animal的构造方法 31 this.eyeColor = c; 32 } 33 } 34 35 /** 36 * 子类Dog继承Animal 37 * @author gacl 38 * 39 */ 40 class Dog extends Animal { 41 /** 42 * Dog类添加本身特有的属性 43 */ 44 public String furColor; 45 46 public Dog(String n, String c) { 47 super(n);//调用父类Animal的构造方法 48 this.furColor = c; 49 } 50 51 } 52 53 /** 4 * 下面是这三个类的测试程序 55 * @author gacl 56 * 57 */ 58 public class TestClassCast { 59 60 /** 61 * @param args 62 */ 63 public static void main(String[] args) { 64 65 Animal a = new Animal("name"); 66 Cat c = new Cat("catname","blue"); 67 Dog d = new Dog("dogname", "black"); 68 /** 69 * a instanceof Animal这句话的意思是a是一只动物吗? 70 * a是Animal这个类里面的是一个实例对象,因此a固然是一只动物,其结果为true。 71 */ 72 System.out.println(String.format("a instanceof Animal的结果是%s",a instanceof Animal));//true 73 /** 74 * c是Cat类的实例对象的引用,即c表明的就是这个实例对象, 75 * 因此“c是一只动物”打印出来的结果也是true。 76 * d也同样,因此“d是一只动物”打印出来的结果也是true。 77 */ 78 System.out.println(String.format("c instanceof Animal的结果是%s",c instanceof Animal));//true 79 System.out.println(String.format("d instanceof Animal的结果是%s",d instanceof Animal));//true 80 /** 81 * 这里判断说“动物是一只猫”,不符合逻辑,因此打印出来的结果是false。 82 */ 83 System.out.println(String.format("a instanceof Cat的结果是%s",a instanceof Cat)); 84 /** 85 * 这句话比较有意思了,a自己是Animal类的实例对象的引用, 86 * 但如今这个引用不指向Animal类的实例对象了,而是指向了Dog这个类的一个实例对象了, 87 * 这里也就是父类对象的引用指向了子类的一个实例对象。 88 */ 89 a = new Dog("bigyellow", "yellow"); 90 System.out.println(a.name);//bigyellow 91 /** 92 * 这里的furColor属性是子类在继承父类的基础上新增长的一个属性,是父类没有的。 93 * 所以这里使用父类的引用对象a去访问子类对象里面新增长的成员变量是不容许的, 94 * 由于在编译器眼里,你a就是Animal类对象的一个引用对象,你只能去访问Animal类对象里面所具备的name属性, 95 * 除了Animal类里面的属性能够访问之外,其它类里面的成员变量a都没办法访问。 96 * 这里furColor属性是Dog类里面的属性,所以你一个Animal类的引用是没法去访问Dog类里面的成员变量的, 97 * 尽管你a指向的是子类Dog的一个实例对象,但由于子类Dog从父类Animal继承下来, 98 * 因此new出一个子类对象的时候,这个子类对象里面会包含有一个父类对象, 99 * 所以这个a指向的正是这个子类对象里面的父类对象,所以尽管a是指向Dog类对象的一个引用, 100 * 可是在编译器眼里你a就是只是一个Animal类的引用对象,你a就是只能访问Animal类里面所具备的成员变量, 101 * 别的你都访问不了。 102 * 所以一个父类(基类)对象的引用是不能够访问其子类对象新增长的成员(属性和方法)的。 103 */ 104 //System.out.println(a.furColor); 105 System.out.println(String.format("a指向了Dog,a instanceof Animal的结果是%s",a instanceof Animal));//true 106 /** 107 * 这里判断说“a是一只Dog”是true。 108 * 由于instanceof探索的是实际当中你整个对象究竟是什么东西, 109 * 并非根据你的引用把对象看出什么样来判断的。 110 */ 111 System.out.println(String.format("a instanceof Dog的结果是%s",a instanceof Dog));//true112 /** 113 * 这里使用强制转换,把指向Animal类的引用对象a转型成指向Dog类对象的引用, 114 * 这样转型后的引用对象d1就能够直接访问Dog类对象里面的新增的成员了。115 */ 116 Dog d1 = (Dog)a; 117 System.out.println(d1.furColor);//yellow 118 } 119 120 }
运行结果:ide
a instanceof Animal的结果是ture测试
c instanceof Animal的结果是turethis
d instanceof Animal的结果是turespa
a instanceof Cat的结果是flase设计
bigyelloworm
a指向了Dog,instanceof Animal的结果是true对象
a instanceof Dog的结果是ture继承
内存分析:
在内存中能够看到,指向Dog类实例对象的引用对象a是一个Animal类型的引用类型,这就变得颇有意思l,Animal类型指向了Dog这个对象,那么,程序会把这只Dog当成一只普通的Animal,既然是把Dog当成一只普通的Animal,那么Dog类里面声明的成员变量furColor就不能访问了,由于Animal类里面没有这个成员变量。因此,从严格来讲,这个a眼里只看到了这个子类对象里面的父类对象Animal,所以能访问获得的也只是这个Animal对象里面的name属性,而这个Animal对象外面的furColor属性是访问不到的,虽然Dog对象确实有这个属性存在,但a就是看不到,a门缝里看Dog——把Dog看扁了,不知道Dog还有furColor这个属性存在,所以a访问不了furColor属性,所以从严格意义上来说,a指向的只是这个Dog对象里面的Animal对象,也就是***箭头指向的那部分,a就只看到了Dog里面这部分,而Dog外面的部分都看不到了。这就是父类引用指向子类对象,父类引用指向子类对象的时候,它看到的只是做为父类的那部分所拥有的属性和方法,至于做为子类的那部分它没有看到。
如真的想访问Dog对象的furColor属性,那就采用对象转型的办法,把父类对象的引用转型成子类对象的引用。Dog d1 = (Dog)a;这里采用的就是对象转型的办法,把a强制转换成一只Dog对象的引用,而后将这个引用赋值给Dog型的引用变量d1,这样d1和a都是指向堆内存里面的Dog对象了,并且d1指向的就是这只Dog全部的部分了,经过这个d1就能够访问Dog对象里面全部的成员了。
1.2对象转型实例二
1 public class TestClassCast { 2 3 public void f(Animal a) { 4 System.out.println(a.name); 5 if (a instanceof Cat) { 6 Cat cat = (Cat)a; 7 System.out.println(cat.eyeColor+" eye"); 8 }else if (a instanceof Dog) { 9 Dog dog = (Dog)a; 10 System.out.println(dog.furColor+" fur"); 11 } 12 } 13 14 /** 15 * @param args 16 */ 17 public static void main(String[] args) { 18 Animal a = new Animal("name"); 19 Cat c = new Cat("catname","blue"); 20 Dog d = new Dog("dogname", "black"); 21 TestClassCast testClassCast = new TestClassCast(); 22 testClassCast.f(a); 23 testClassCast.f(c); 24 testClassCast.f(d); 25 } 26 }
上面的代码是对前面声明的三个类Animal,Dog,Cat测试的延续,这里咱们在TestClassCast这里类里面测试这个三个类,这里咱们在TestClassCast类里面new了一个testClassCast对象,为的是调用TestClassCast类里面声明的f(Animal a)这个方法,这个f()方法里面的参数类型是Animal类型,若是是Animal类型的参数,那么咱们能够把这个Animal类型的子类对象做为参数传进去,这是能够的。如把一只Dog或者是一只Cat丢进f()方法里面这都是能够的,由于Dog和Cat也是Animal。所以当程序执行到testClassCast.f(a);,testClassCast.f(c);,testClassCast.f(d);的时候,由于f()方法里面的参数是Animal类型的,因此咱们能够把一个Animal对象传进去,除此以外,咱们还能够直接把从Animal类继承下来的Dog类和Cat类里面的Dog对象和Cat对象做为实参传递过去,便是把Animal类型的子类对象做为参数传进去。这里就体现出了继承和父类对象的引用能够指向子类对象的好处了,若是说没有继承关系的存在,若是说父类的引用不能够指向子类对象,那么咱们就得要在Test类里面定义三个f()方法了,即要定义这样的f()方法:f(Animal a)、f(Dog d)、f(Cat c)分别用来处理Animal、Dog和Cat,使用三个方法来处理,未来程序的扩展起来就不是简单的事了,由于面向对象可以帮助咱们这些年来编程苦苦追求的一个境界是可扩展性比较好。可扩展性比较好的一个典型例子就是说当你建好一个建筑以后或者是你写好这个程序以后,把这个主建筑给建好了,未来你要加一些其余的功能的时候,尽可能不要去修改主结构,这叫可扩展性好,你盖了一座大楼,你如今要在大楼的旁边添加一个厨房,那你在它旁边一盖就好了,若是有人告诉你,我添加一个厨房我须要把你整个大楼的主要柱子都给拆了而后再盖一遍,这你干嘛,确定不干。若是结构设计成这样,那就是设计得很差,可扩展性很差。因此这里若是要把f()方法写成三个重载的f()方法,那么未来我输出一只鸟的时候又得要添加一个f(Bird b)方法来处理鸟。这样扩展起来就太麻烦了,由于每处理一只动物都要添加一个新的方法,可是若是存在继承关系,若是父类对象的引用能够指向子类对象,那扩展起来就简单了,你能够把处理动物的方法写在一个方法f(Animal a)里面就够了,由于全部动物的种类都是从Animal类继承下来,所以给f()方法传递Animal类型的参数的时候能够直接把这个Animal类的子类对象传进去,这样不论是要增长什么动物的输出,我均可以调用f(Animal a)方法去处理,这种扩展性比每次都要增长一个新的处理方法的扩展性要好得多,这就是继承的一个好处,这就是对象转型对于可扩展性来的好处:“对象的引用能够指向子类对象”,是由于面向对象的编程里面存在这样的继承关系,使得程序的可扩展性比较好。
对象转型可使父类对象的引用能够指向子类对象,给程序带来了比较好的可扩展性:咱们能够在一个方法的参数里面定义父类的引用,而后在实际当中传的时候传的是子类的对象,而后咱们再在方法里面判断这个传过来的子类对象到底属于哪个子类,而后再去执行这个子类里面的方法或者调用这个子类里面的成员变量,所以程序的可扩展性要比单独定义好多个方法好得多得多。不过这个可扩展性尚未达到最好,使用多态就可让程序的扩展性达到极致。
PS:JAVA交流群:457036818