java基础学习之对象转型
对象转型(casting):
1)一个基类的引用类型变量可以指向其子类的对象
2)一个基类的引用不可以访问其子类对象新增加的成员(属性和方法)
3)可以使用引用变量instanceof类名,来判断该引用型变量所指向的对象是否属于该类或该类的子类
4)子类的对象可以当作基类的对象来使用称作向上转型(upcasting),反之称为向下转型(downcasting)
package javastudy.summary; /**
* 父类Animal
* @author gacl
*
*/
class Animal { public String name; public Animal(String name) {
this.name = name;
}
} /**
* 子类Cat继承Animal
* @author gacl
*
*/
class Cat extends Animal { /**
* Cat添加自己独有的属性
*/
public String eyeColor; public Cat(String n, String c) {
super(n);//调用父类Animal的构造方法
this.eyeColor = c;
}
} /**
* 子类Dog继承Animal
* @author gacl
*
*/
class Dog extends Animal {
/**
* Dog类添加自己特有的属性
*/
public String furColor; public Dog(String n, String c) {
super(n);//调用父类Animal的构造方法
this.furColor = c;
} } /**
* 下面是这三个类的测试程序
* @author gacl
*
*/
public class TestClassCast { /**
* @param args
*/
public static void main(String[] args) { Animal a = new Animal("name");
Cat c = new Cat("catname","blue");
Dog d = new Dog("dogname", "black");
/**
* a instanceof Animal这句话的意思是a是一只动物吗?
* a是Animal这个类里面的是一个实例对象,所以a当然是一只动物,其结果为true。
*/
System.out.println(String.format("a instanceof Animal的结果是%s",a instanceof Animal));//true
/**
* c是Cat类的实例对象的引用,即c代表的就是这个实例对象,
* 所以“c是一只动物”打印出来的结果也是true。
* d也一样,所以“d是一只动物”打印出来的结果也是true。
*/
System.out.println(String.format("c instanceof Animal的结果是%s",c instanceof Animal));//true
System.out.println(String.format("d instanceof Animal的结果是%s",d instanceof Animal));//true
/**
* 这里判断说“动物是一只猫”,不符合逻辑,所以打印出来的结果是false。
*/
System.out.println(String.format("a instanceof Cat的结果是%s",a instanceof Cat));
/**
* 这句话比较有意思了,a本身是Animal类的实例对象的引用,
* 但现在这个引用不指向Animal类的实例对象了,而是指向了Dog这个类的一个实例对象了,
* 这里也就是父类对象的引用指向了子类的一个实例对象。
*/
a = new Dog("bigyellow", "yellow");
System.out.println(a.name);//bigyellow
/**
* 这里的furColor属性是子类在继承父类的基础上新增加的一个属性,是父类没有的。
* 因此这里使用父类的引用对象a去访问子类对象里面新增加的成员变量是不允许的,
* 因为在编译器眼里,你a就是Animal类对象的一个引用对象,你只能去访问Animal类对象里面所具有的name属性,
* 除了Animal类里面的属性可以访问以外,其它类里面的成员变量a都没办法访问。
* 这里furColor属性是Dog类里面的属性,因此你一个Animal类的引用是无法去访问Dog类里面的成员变量的,
* 尽管你a指向的是子类Dog的一个实例对象,但因为子类Dog从父类Animal继承下来,
* 所以new出一个子类对象的时候,这个子类对象里面会包含有一个父类对象,
* 因此这个a指向的正是这个子类对象里面的父类对象,因此尽管a是指向Dog类对象的一个引用,
* 但是在编译器眼里你a就是只是一个Animal类的引用对象,你a就是只能访问Animal类里面所具有的成员变量,
* 别的你都访问不了。
* 因此一个父类(基类)对象的引用是不可以访问其子类对象新增加的成员(属性和方法)的。
*/
//System.out.println(a.furColor);
System.out.println(String.format("a指向了Dog,a instanceof Animal的结果是%s",a instanceof Animal));//true
/**
* 这里判断说“a是一只Dog”是true。
* 因为instanceof探索的是实际当中你整个对象到底是什么东西,
* 并不是根据你的引用把对象看出什么样来判断的。
*/
System.out.println(String.format("a instanceof Dog的结果是%s",a instanceof Dog));//true
/**
* 这里使用强制转换,把指向Animal类的引用对象a转型成指向Dog类对象的引用,
* 这样转型后的引用对象d1就可以直接访问Dog类对象里面的新增的成员了。
*/
Dog d1 = (Dog)a;
System.out.println(d1.furColor);//yellow
} } a instanceof Animal --true
c instanceof Animal --true
d instanceof Animal --true
a instanceof Cat --false
bigyellow
a 指向了Dog,a instanceof Animal 的结果是true
a instanceof Dog 的结果是true
yellow
内存分析:

在内存中可以看到,指向Dog类实例对象的引用对象a是一个Animal类型的引用类型,这就比较有意思了,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对象里面所有的成员了。
实例二:
public class TestClassCast {
public void f(Animal a) {
System.out.println(a.name);
if (a instanceof Cat) {
Cat cat = (Cat)a;
System.out.println(cat.eyeColor+" eye");
}else if (a instanceof Dog) {
Dog dog = (Dog)a;
System.out.println(dog.furColor+" fur");
}
}
/**
* @param args
*/
public static void main(String[] args) {
Animal a = new Animal("name");
Cat c = new Cat("catname","blue");
Dog d = new Dog("dogname", "black");
TestClassCast testClassCast = new TestClassCast();
testClassCast.f(a);
testClassCast.f(c);
testClassCast.f(d);
}
}
这里的这些代码是对前面声明的三个类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)方法去处理,这种扩展性比每次都要增加一个新的处理方法的扩展性要好得多,这就是继承的一个好处,这就是对象转型对于可扩展性来的好处:“对象的引用可以指向子类对象”,是因为面向对象的编程里面存在这样的继承关系,使得程序的可扩展性比较好。
对象转型可以使父类对象的引用可以指向子类对象,给程序带来了比较好的可扩展性:我们可以在一个方法的参数里面定义父类的引用,然后实际当中传的时候传的是子类的对象,然后我们再在方法里面判断这个传过来的子类对象到底属于哪个子类,然后再去执行这个子类里面的方法或者调用这个子类里面的成员变量,因此程序的可扩展性比单独定义好多个方法要好一些。不过这个可扩展性还没有达到最好,使用多态就可以让程序的扩展性达到极致。
java基础学习之对象转型的更多相关文章
- java基础学习总结——对象转型
一.对象转型介绍 对象转型分为两种:一种叫向上转型(父类对象的引用或者叫基类对象的引用指向子类对象,这就是向上转型),另一种叫向下转型.转型的意思是:如把float类型转成int类型,把double类 ...
- JAVA基础学习-多态 对象转型 final
一.多态的产生条件 1:继承 存在继承的类之间 2:方法重装 3:父类继承子类重装的方法 子类的对象 也是属于父类的 二:对象的转型 1:向上转型:当子类转型成父类时 例如:Animal a = n ...
- Java基础学习总结--对象容器
目录: ArrayList 顺序泛型容器 HashSet 集合容器 HashMap<Key,Value>容器 要用Java实现记事本的功能.首先列出记事本所需功能: 可以添加记录(字符串) ...
- 转载-java基础学习汇总
共2页: 1 2 下一页 Java制作证书的工具keytool用法总结 孤傲苍狼 2014-06-24 11:03 阅读:25751 评论:3 Java基础学习总结——Java对象的序列化和 ...
- 尚学堂JAVA基础学习笔记
目录 尚学堂JAVA基础学习笔记 写在前面 第1章 JAVA入门 第2章 数据类型和运算符 第3章 控制语句 第4章 Java面向对象基础 1. 面向对象基础 2. 面向对象的内存分析 3. 构造方法 ...
- 3.Java基础之Date对象
毕向东老师Java基础学习笔记——Date对象 今天学习Java中的Date对象后,感觉这个对象对我们主要有以下几点用处. 1.获取时间和日期并按照自己定义的格式显示. 2.网站设计时显示时间. 知 ...
- 2.Java基础之Runtime对象
毕向东老师Java基础学习笔记——Runtime对象 今天学习Java中的Runtime对象后,感觉这个对象对我们主要有以下几点用处. 1.使用java代码打开本地可执行文件,比如打开一个计算器. 2 ...
- 1.Java基础之System对象
毕向东老师Java基础学习笔记——System对象 今天学习Java中的System对象后,感觉这个对象对我们主要有以下几点用处. 1.获取当前操作系统版本和类型. 2.获取当前操作系统的path中的 ...
- Java基础学习笔记总结
Java基础学习笔记一 Java介绍 Java基础学习笔记二 Java基础语法之变量.数据类型 Java基础学习笔记三 Java基础语法之流程控制语句.循环 Java基础学习笔记四 Java基础语法之 ...
随机推荐
- 设计模式-观察者模式(Observer)
简介: 观察者模式,也称为订阅-发布模式,定义对象间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖他的对象都得到通知并被自动更新. 主要由以下几个部分组成: a.Subject目标对象. ...
- OpenStack实战(一)
OpenStack作为当前发展势头迅猛的云计算开源项目,去年进行了一些了解,现在有空回来进行一些补充记录,当时实战的版本是那会最新版本,当然现在已经更新了好几版了,不过还是那句话“这些丝毫不影响,了解 ...
- 消息推送之GCM
利用GCM进行消息推送 原理 1.接收端向GCM注册registerid 2.发送端发消息给GCM服务器 这个过程需要三个参数: (1)API Key (2)registerid (3)传递的数据 3 ...
- Javascript 模块模式
模块模式(Module Pattern)提供了一种代码封装的方式,可以优雅地创建非耦合的代码块. 它是利用即时函数为对象创建私有变量和特权方法.严格来说,Javascript中没有私有成员的概念,所有 ...
- ASP.NET中@Page指令中的AutoEventWireup
AutoEventWireup:指示控件的事件是否自动匹配 (Autowire).如果启用事件自动匹配,则为 true:否则为 false.默认值为 true.如果设为false,则事件不可用.有关更 ...
- map与set的遍历
map有四种方式: 1.直接遍历 keySet 2.使用Iterator //注意next放回的对象是map.Entry<K,V>,而使用的iterator是通过entrySet返回的一个 ...
- C++求斐波那契数
题目内容:斐波那契数定义为:f(0)=0,f(1)=1,f(n)=f(n-1)+f(n-2)(n>1且n为整数) 如果写出菲氏数列,则应该是: 0 1 1 2 3 5 8 13 21 34 …… ...
- 编写测试类,了解ArrayList的方法
这篇文章主要介绍了C#中动态数组用法,实例分析了C#中ArrayList实现动态数组的技巧,非常具有实用价值,需要的朋友可以参考下 本文实例讲述了C#中动态数组用法.分享给大家供大家参考.具体分析如下 ...
- pure css做的pc登陆界面
源码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w ...
- Python脚本控制的WebDriver 常用操作 <十> 层级定位
下面将使用WebDriver来模拟操作一个层级定位元素的操作 测试用例场景 在实际的项目测试中,经常会有这样的需求:页面上有很多个属性基本相同的元素,现在需要具体定位到其中的一个.由于属性基本相当,所 ...