重新精读《Java 编程思想》系列之向上转型与向下转型
前言
今天重读了一下向上转型与向下转型,有些新的体会,了解了向上转型的好处,及如何向下转型。在此分享给大家。
向上转型
向上转型是用来表现新类和基类之间的关系。在传统中,由导出类转型成基类,在继承图中是向上移动的。因此称作向上转型。由于向上转型是从一个较专用类型向较通用类型转换,所以总是安全的。也就是说,导出类是基类的一个超集。它可能比基类含有更多的方法。但他必须具备基类中所含有的方法。
我们来看一个例子。
class Car {
public void run() {
System.out.println("这是父类run()方法");
}
}
public class Benz extends Car {
public void run() {
System.out.println("这是Benz的run()方法");
}
public void price() {
System.out.println("Benz:800000$");
}
public static void main(String[] args) {
Car car = new Benz();
car.run();
//car.price();程序报错
}
}
运行后输出。这是Benz的run()方法。
但是当我们用car这个对象去调用Benz类中price这个方法时,就会报错。
这就是因为我们此处进行的向上转型,car这个对象虽然指向子类,但是子类由于进行了向上转型,就失去了使用父类中所没有的方法的“权利”,在此处就是不能调用price()这个方法。
那么向上转型到底有什么用呢,到目前为止我们不仅看不到它的好处,反而发现使用了向上转型后反而不能调用子类所特有的方法了。那么向上转型的作用到底是什么呢,我们一起来看下面的代码:
class Car {
public void run() {
System.out.println("这是父类run()方法");
}
public void speed() {
System.out.println("speed:0");
}
}
class BMW extends Car {
public void run() {
System.out.println("这是BMW的run()方法");
}
public void speed() {
System.out.println("speed:80");
}
}
public class Benz extends Car {
public void run() {
System.out.println("这是Benz的run()方法");
}
public void speed() {
System.out.println("speed:100");
}
public void price() {
System.out.println("Benz:800000$");
}
public static void main(String[] args) {
show(new Benz());//向上转型实现
show(new BMW());
}
public static void show(Car car) {//父类实例作为参数
car.run();
car.speed();
}
}
上面代码中
public static void main(String[] args) {
show(new Benz());
show(new BMW());
}
public static void show(Car car) {
car.run();
car.speed();
}
就体现了向上转型的优点,这也体现了Java抽象编程的思想。如果此处没有向上转型,要实现show每个子类的功能,那么有几个子类就要写多少函数。代码如下:
public static void main(String[] args) {
show(new Benz());
show(new BMW());
}
public static void show(Benz benz) {
benz.run();
benz.speed();
}
public static void show(BMW bmw) {
bmw.run();
bmw.speed();
}
试想一下,一旦有很多子类,那么这个工作量将会比没有使用向上转型大很多。这也表明向上转型还有个优点就是提高了代码的简洁性。
我们再来一种带着static的特殊调用情况。
public class Animal {
String name = "我是动物";
static int age = 20;
public void eat() {
System.out.println("动物可以吃饭");
}
public static void sleep() {
System.out.println("动物可以睡觉");
}
public void run(){
System.out.println("动物可以奔跑");
}
public static void main(String[] args) {
Animal am = new Dog();
am.eat();
am.sleep();
am.run();
//am.watchdog();这里会报错
System.out.println(am.name);
System.out.println(am.age);
}
}
class Dog extends Animal {
String name = "小狗";
static int age = 60;
public void eat() {
System.out.println("小狗可以吃饭");
}
public static void sleep() {
System.out.println("小狗可以睡觉");
}
public void watchdog() {
System.out.println("小狗可以看门");
}
}
运行结果:

但是可以看到代码块中,直接调用Dog的watchdog()方法会报错。

这就是因为我们此处进行的向上转型,am这个对象虽然指向子类,但是子类由于进行了向上转型,就失去了使用父类中所没有的方法的“权利”,在此处就是不能调用watchdog()这个方法。
而且结果里也可以看到,睡觉是引用的父类“Animal”的睡觉方法,这是因为Animal的睡觉方法为静态方法,可以总结如下:
如果是访问成员变量,编译的话就是看父类,运行同样是看父类。
如果访问的方法,编译就看父类,运行则看子类。
如果是静态方法,编译和运行都是看父类。
向下转型
先看一个错误的例子
public class Animal {
public void eat(){
System.out.println("Animal eat()");
}
}
public class Dog extends Animal {
@Override
public void eat(){
System.out.println("Dog eat");
}
}
public class Test {
public static void main(String[] args) {
//向下转型
Animal animal = new Animal();
((Dog)animal).eat();
}
}
运行结果:
Exception in thread "main" java.lang.ClassCastException: com.hello.test.Animal cannot be cast to com.hello.test.Dog
at com.hello.test.Test.main(Test.java:7)
从上述例子来看,Java似乎并不支持向下转型,真是如此吗?其实不然,Java同样支持向下转型,只是向下转型是有条件的——只有引用子类对象的父类引用才能被向下转型为子类对象。也就是说,向下转型之前,必须先向上转型。
public class Animal {
public void eat(){
System.out.println("Animal eat()");
}
}
public class Dog extends Animal {
@Override
public void eat(){
System.out.println("Dog eat");
}
}
public class Test {
public static void main(String[] args) {
//向上转型
Animal animal = new Dog();
//向下转型
((Dog)animal).eat();
}
}
运行结果:
Dog eat
重新精读《Java 编程思想》系列之向上转型与向下转型的更多相关文章
- JavaSE(五)JAVA对象向上转型和向下转型
今天做了一个测试的题目,发现自己还是很多问题没有静下心来做.很多问题是可以自己解决的但是自己一是没有读清题意,二是自己心里太急躁了.所以这个要自己应以为鉴! 对象的转型问题其实并不复杂,我们记住一句话 ...
- 重新精读《Java 编程思想》系列之组合与继承
Java 复用代码的两种方式组合与继承. 组合 组合只需将对象引用置于新类中即可. 比如我们有一个B类,它具有一个say方法,我们在A类中使用B类的方法,就是组合. public class B { ...
- Java编程思想读书笔记(一)【对象导论】
2018年1月7日15:45:58 前言 作为学习Java语言的经典之作<Java编程思想>,常常被人提起.虽然这本书出版十年有余,但是内容还是很给力的.很多人说这本书不是很适合初学者,我 ...
- 《Java编程思想》阅读笔记二
Java编程思想 这是一个通过对<Java编程思想>(Think in java)进行阅读同时对java内容查漏补缺的系列.一些基础的知识不会被罗列出来,这里只会列出一些程序员经常会忽略或 ...
- java编程思想-基础
interface: 方法默认为public:成员变量默认 static and final 对象数组的定义:理解? 多接口继承:可以多个接口,但只有一个具体类,具体类在前面 自:多接口继承时,来自不 ...
- 《Java编程思想》读书笔记(四)
前言:三年之前就买了<Java编程思想>这本书,但是到现在为止都还没有好好看过这本书,这次希望能够坚持通读完整本书并整理好自己的读书笔记,上一篇文章是记录的第十七章到第十八章的内容,这一次 ...
- Java编程思想重点笔记(Java开发必看)
Java编程思想重点笔记(Java开发必看) Java编程思想,Java学习必读经典,不管是初学者还是大牛都值得一读,这里总结书中的重点知识,这些知识不仅经常出现在各大知名公司的笔试面试过程中,而 ...
- java编程思想-复用类总结
今天继续读<java 编程思想>,读到了复用类一章,看到总结写的很好,现贴上来,给大家分享. 继承和组合都能从现有类型生成新类型.组合一般是将现有类型作为新类型底层实现的一部分来加以复用, ...
- Java编程思想学习(八) 内部类
可以将一个类的定义放在另一个类的定义内部,这就是内部类. 内部类的定义是简单的,但是它的语法确实很是复杂,让人不是很好理解.下面就内部类做一个小结. 一.内部类的分类 总的来讲内部类分为普通内部类,匿 ...
随机推荐
- 简单的 smartpointer
水水地 发第一篇blog, 瘦身版的smartpointer. template <typename T> class CountedPtr { private: T* ptr; long ...
- 附010.Kubernetes永久存储之GlusterFS超融合部署
一 前期准备 1.1 基础知识 在Kubernetes中,使用GlusterFS文件系统,操作步骤通常是: 创建brick-->创建volume-->创建PV-->创建PVC--&g ...
- ZeroC ICE的远程调用框架 AMD
继上一篇<ZeroC ICE的远程调用框架>,本篇再来说其中的AMD.(本篇需要重写) 当在ice文件中声明某个接口方法Method为["amd"]后,接口方法在stu ...
- 2C 还是 2B,跟找工作有什么关系?
通常,我们会把公司的业务类型分成以下几种: 2C,to Customer,指面向个人客户的业务,即将公司的产品或服务销售给个人,通常做出购买决策的个人也是使用产品或服务的用户.举例说明,像 BAT 发 ...
- source for "Android 28 platform" not found
source for "Android 28 platform" not found 解决办法:点击右上角的Download,但是下载完点击Refresh之后没有反应,这时候需要重 ...
- Springboot操作Elasticsearch
常见的日志系统是基于logstach+elasticsearch+kibna框架搭建的,但是有时候kibana的查询无法满足我们的要求,因此有时需要代码去操作es,本文后续都以es代替elastics ...
- Hadoop之HDFS文件系统(二)
HDFS客户端 通过IO流操作HDFS HDFS文件上传 @Test public void putFileToHDFS() throws Exception{ // 1 创建配置信息对象 Confi ...
- java struts2 debug
出了一堆bug 改的顺序和哪个起了作用不太记得了 下面列出遇到问题的顺序:1java.lang.NoSuchMethodException:没这个方法 代码是改正后的,出错的时候保证class ,ac ...
- 浅析scrapy与scrapy-redis的区别
首先,要了解两者的区别,就要清楚scrapy-redis是如何产生的,有需求才会有发展,社会在日新月异的飞速发展,大量相似网页框架的飞速产生,人们已经不满足于当前爬取网页的速度,因此有了分布式爬虫,让 ...
- 【Android - 自定义View】之View的draw过程解析
draw(绘制)过程的作用是将View绘制到屏幕上面.View中有 draw() 方法和 onDraw() 方法,但onDraw()方法是空方法:ViewGroup中没有draw()方法,也没有onD ...