定义
在之前我们使用c#中也会遇到这个问题,这里再次复习。加上内存分析,加深理解。首先来说下这个对象转型的意思。以及对象转型的对于扩展代码的好处。
背景:当子类继承父类对象时,子类中会拥有一些父类不存在的属性和方法的含义.这时候父类的对象是无法看到子类哪些没有和父类公共的属性的.
实例I
// public class TestConvertObject{ public static void main(String[] args){ Animal d=new Dog("dahuang","black"); //说明d是父类的一员 System.out.println(d instanceof Animal); System.out.println(d instanceof Dog); d.SuperMethod(); Dog d1=(Dog)d; d1.ChildMethod(); } } class Animal{ private String name; Animal(String name){ this.name=name; } protected void SuperMethod(){ System.out.println("父类方法"); } } class Dog extends Animal{ private String color; Dog(String name,String color){ super(name); this.color=color; } protected void ChildMethod(){ System.out.println("子类方法"); } }
结果
代码中定义了父类的引用,然后指向子类的对象。最后通过instanceof判断得到这个d对象既是父类对象也是子类对象。这个应该不难理解,就是子类既是dog,又是animal。当然需要说明的一点就是,父类引用指向子类对象的过程中是不可以访问父类中没有的属性的。就是这个d对象是无法访问到childmethod方法的,这时候需要的就是对象转型了。类似在c#中的数据类型的转换。Dog d1=(Dog)d;这个称谓向下转型。
实例II
public class TestConvertObjectDouble{ public static void main(String[] args){ Person p=new Person("cfl"); //实例化TestConvertObjectDouble类,以此来调用下面的Test方法 TestConvertObjectDouble t=new TestConvertObjectDouble(); //实例化子类student对象 Student s=new Student("sname","23"); //实例化子类Teacher对象 Teacher te=new Teacher("milaoshi","jiaoshou"); //通过调用统一的方法,不需要这样一个个的添加,更好的扩展,只需要传不同的子类对象就可以了。无需去关注怎么去实现 t.Test(s); t.Test(te); } public void Test(Person p){ System.out.println("name:"+p.name); //当子类为studnet是直接调用student的属性和方法 if(p instanceof Student){ Student s1=(Student)p; System.out.println(s1.name+s1.age); }else{ Teacher t1=(Teacher)p; System.out.println(t1.name+t1.position); } } } class Person{ protected String name; Person(String name){ this.name=name; } } class Student extends Person{ protected String age; Student(String name,String age){ super(name); this.age=age; } } class Teacher extends Person{ public String name; protected String position; Teacher(String name,String position){ super(name); this.position=position; } }
结果
这个实例中,利用父类引用指向子类对象和对象转型这样一个东西来在构造了Test方法。试想一下,如果一个对象就新建一个方法那么会出现很多冗余的情况;并且每次新增方法的时候都需要重新去添加。举个例子:利用转型和父类引用来指向子类对象就像是一个优秀的架构设计师,在产品开发的初期就已经将各种的接口抽象封装,等到下次再次需要扩展其他功能时就只用添加一点小的部分即可完成。而后一种就类似菜鸟我现在的水平,每次添加一个新的功能时,就把所有的接口和方法再次写一次。这样无论是效率和灵活性就大大的下降。说是面向对象,其实还是面向过程的开发。做了很多重复性且不利于后期人员维护。
内存分析
下面是针对父类引用指向子类对象和对象转型画的内存分析图
图中在栈中存放的是父类的引用,在堆中存放的是子类的对象。通过图我们可以发现,即使指向了子类的对象,父类也是无法看到子类区别与父类的属性和方法的。什么意思?举个例子:就是说dog可以有看家护院这个方法。但是动物不一定有,让一个猫去看家护院可以吗?估计家里的东西早就没了。这里也是这个意思。再看上面当对象转型后d对象转型为dog类对象后,这样就可以直接访问dog的属性和方法了。在实例中看到我们执行的结果。
总结
以上就是自己通过学习java对象转型学习到一些总结和体会。之前在c#中也有接触,但是理解和感觉也不是很深刻。这次马老师讲了"永恒的java"之后理解起来就清楚点。老师常说的盲人摸象,也切实体会了一把。加上最近维护ksxt的体会,确实在抽象和封装,还有设计理念上还存在很多问题。需要做的工作还很多。
君子不器,要学的不仅是敲代码,设计理念,代码的复用都很重要。以此自勉,前路漫漫其修远兮,上下求索。