Java编程思想(五) —— 多态(上)

上一章,Java编程思想(四) —— 复用类里面讲到了向上转型,感觉和多态放在一起写更好。

多态,polymorphism。一个重要的特性,篇幅太长了,分上下两篇写。

(1)向上转型

class TV{
    public static void show(TV tv){
        System.out.println("TV");
    }
}

public class LeTV extends TV{
    public static void main(String[] args) {
        LeTV letv = new LeTV();
        TV.show(letv);
    }
}

看到没有,程序正常运行。本来参数类型是TV类型,但是子类传进去也可以。这种将LeTV转为父类TV的行为,就是向上转型。

向上转型是安全的,子类必须继承父类的方法(这是继承的定义),自己可以拥有自己的属性和方法,从一个特定的类向一个通用的类转换,是安全的。反过来有普通到特殊却有不对应的风险。

(2)多态

先看例子:

class TV{
    public  void show(){
        System.out.println("TV");
    }
}

class LeTV extends TV{
    public void show(){
        System.out.println("LeTV");
    }
}
class MiTV extends TV{
    public void show(){
        System.out.println("MiTV");
    }
}
class SanTV extends TV{
    public void show(){
        System.out.println("SanTV");
    }
}
public class EveryTV {
    public static void tvshow(LeTV tv){
        tv.show();
    }
    public static void tvshow(MiTV tv){
        tv.show();
    }
    public static void tvshow(SanTV tv){
        tv.show();
    }
    public static void main(String[] args) {
        tvshow(new LeTV());
        tvshow(new MiTV());
        tvshow(new SanTV());
    }
}

程序没什么问题,每个方法都有对应的类型。但是除了这三个子类,还有几十,几百个TV子类,那么tvshow方法岂不是也要写上对应的几十甚至几百个?

然后,多态出现了。

public class EveryTV {
    public static void tvshow(TV tv){
        tv.show();
    }

    public static void main(String[] args) {
        tvshow(new LeTV());
        tvshow(new MiTV());
        tvshow(new SanTV());
    }
}

程序简洁了很多,并且运行结果和上面的一样。美好了许多。再看一看,这和向上转型很像。

多态,可以理解成多种形式,多种状态。多态也叫动态绑定、后期绑定、运行时绑定。

谈到绑定就要联系前期绑定(前期绑定国内的搜索真的是惨不忍睹,把编程思想的话全部抄进去,不会去真正理解前期绑定是什么!)。

what is Early and Late Binding?(来自stackoverflow)。

The short answer is that early (or static) binding refers to compile time binding and late (or dynamic) binding refers to runtime binding (for example when you use reflection)——byChristian
Hagelid
.

简单说前期绑定是编译期的绑定,后期绑定是运行时的绑定。

书上指出C的方法全部都是前期绑定,如果上面多态的例子是前期绑定的话,编译时就要绑定,但是tv这个引用只有一个,即使你传进去的是LeTV,它也不知道是要执行TV的show方法还是其他类的show方法。

正因为有了多态,后期绑定的存在,会根据对象来执行对应的方法。

因为多态的存在,我们可以添加多个新的子类而不用去担心要写多少tvshow方法。

向上转型的写法:

    public static void main(String[] args) {
        TV letv = new LeTV();
        TV mitv = new MiTV();
        TV santv = new SanTV();
        tvshow(letv);
        tvshow(mitv);
        tvshow(santv);
    }

各种各样的TV还是TV,可以向上转型,因为多态,又会调用各自的对象的show方法。

书上的原话讲得很好,我照抄一下,多态是一种让程序员“将改变的事物和未变的事物分离开来”的重要技术。

就上述而言,各自的TV的show方法有自己的重写,但是EveryTV这个类里面的tvshow方法却不用变动。就是多态的用处所在。

是不是觉得没什么用?

List al = new ArrayList();
List ll = new LinkedList();

用处就在这里,我先用al也行,ll也行,以后要改可以改,不然很多东西都要改过。

(3)缺陷

1)“覆盖”私有方法

书上举的例子有点牵强,方法不算重写。

public class TV{
    private void show(){
        System.out.println("TV");
    }
    public static void main(String[] args) {
        TV tv = new LeTV();
        tv.show();
    }
}
class LeTV extends TV{
    public void show(){
        System.out.println("LeTV");
    }
}

学了多态之后,一看结果是LeTV吧。错了,LeTV根本没有重写show方法,父类的show方法是private的,不可见,不可继承。假的“覆写”。

2)域与静态方法

对域,field概念模糊的,可以看看:java中的域是什么?

public class TV{
    public int price = 10;
    public int getprice(){
        return price;
    }
    public static String getString(){
        return "tv";
    }
}
class LeTV extends TV{
    public int price = 20;
    public int getprice(){
        return price;
    }
    public int getsuperprice(){
        return super.price;
    }

    public static String getString(){
        return "letv";
    }

    public static void main(String[] args) {
        TV tv = new LeTV();
        System.out.println(tv.price+" getprice:"+tv.getprice()+tv.getString());
        LeTV letv = new LeTV();
        System.out.println(letv.price+" getprice:"+letv.getprice()+" getsuperprice:"+letv.getsuperprice()
                +letv.getString());
    }
}

按照多态,tv.price的结果应该为20,但是结果却是10,因为域访问操作是由编译器解析,不是多态,多态是后期绑定,也就是运行期间。

而tv.getString方法也一样,并没有打印出letv,而是tv,因为方法是静态方法,只和类有关,与具体的对象不关联。

这是运用多态时要注意的两个地方。

刚开始看这个多态特性的时候难看懂,也不知道这东西有什么用,其实程序敲多了,其义自现。你会发现你写的东西导出都在用它。

时间: 2024-10-13 06:07:26

Java编程思想(五) —— 多态(上)的相关文章

Java编程思想(五) —— 多态(下)

多态(上)基本讲解了很多多态的特性和问题.下面继续. 1)构造器和多态 这个问题其实前面写过了,构造器实际上是static方法,只不过是隐式声明,所以构造器并没有多态性. 但是需要知道加载的顺序. class GrandFather{ GrandFather(){ print(); } private int print(){ System.out.println("g"); return 1; } } class Father extends GrandFather{ Father(

JAVA编程思想(4) - 多态(三)

若干个对象共享 例如Frog对象拥有其自己的对象,并且知道他们的存活多久,因为Frog对象知道何时调用dispose()去释放其对象.然而,如果这些成员对象中存在于其他一个或多个对象共享的情况,问题将不再简单,不再能简单的调用dispose()了.在这种情况下,我们也许需要引用计数来跟踪依旧访问着共享对象的数量. //: polymorphism/ReferenceCounting.java // Cleaning up shared member objects. import static

JAVA编程思想(4) - 多态(一)

多态 在面向对象的程序设计语言中,多态是继数据抽象和继承之后的第三种基本类型. 多态通过分离做什么和怎么做,从另一个角度将接口和实现分离开来.多态不但能够改善代码的组织结构和可读性,还能够创建可扩展程序. 再论向上转型 代码 //: polymorphism/music/Note.java // Notes to play on musical instruments. package polymorphism.music; public enum Note { MIDDLE_C, C_SHAR

Java编程思想(四) —— 复用类

看了老罗罗升阳的专访,情不自禁地佩服,很年轻,我之前以为和罗永浩一个级别的年龄,也是见过的不是初高中编程的一位大牛之一,专访之后,发现老罗也是一步一个脚印的人.别说什么难做,做不了,你根本就没去尝试,也没有去坚持. If you can't fly then run,if you can't run then walk, if you can't walk then crawl,but whatever you do,you have to keep moving forward--Martin

《On Java 8》中文版,又名《Java 编程思想》中文第五版

来源:LingCoder/OnJava8 主译: LingCoder 参译: LortSir 校对:nickChenyx E-mail: [email protected] 本书原作者为 [美] Bruce Eckel,即(Thinking in Java 4th Edition,2006)的作者. 本书是事实上的 Thinking in Java 5th Edition(On Java 8,2017). Thinking in Java 4th Edition 基于 JAVA 5 版本:On

Java编程思想之8多态

这一章看下来,感觉比较混乱.乱感觉主要乱在8.4  8.5. 开始读的时候,感觉8.1 8.2 8.3都挺乱的.读了两遍后发现前三节还是比较有条理的. 8.1主要讲了什么是多态,多态的好处. 8.2主要讲了什么情况会发生多态?? 8.3主要讲了构造器内部里面的方法调用会发生多态. 8.4就一页,而且感觉一般用不到.用到了再看也行. 8.5也很简单,相当于一个总结,一个补充(向下转型) 我主要根据书上的内容,总结两个内容: 1.什么是多态,多态的好处: 2.什么情况下会发生多态?为什么这些情况下会

Java 编程思想 第五章 ----初始化与清理(1)

从今天开始每天一小时的java 编程思想的阅读和编码,其实就是把书上的代码抄下来. 5.5 清理:终结处理和垃圾回收 初始化和清理工作同等重要,但是清理工作却被常常忘记,但是在使用对象之后,对对象弃之不顾的做法并不是很安全.Java有自己的垃圾回收器负责回收无用的对象占据的内存资源.但也有特殊情况:假定你的内存区域不是用new获得的,这是无法用垃圾回收器释放所以java中允许在类中定义一个名为 finalize()的方法.       工作原理: 一旦垃圾回收器准备好释放对象占用的存储空间,将首

JAVA编程思想读书笔记(五)--多线程

接上篇JAVA编程思想读书笔记(四)--对象的克隆 No1: daemon Thread(守护线程) 参考http://blog.csdn.net/pony_maggie/article/details/42441895 daemon是相于user线程而言的,可以理解为一种运行在后台的服务线程,比如时钟处理线程.idle线程.垃圾回收线程等都是daemon线程. daemon线程有个特点就是"比较次要",程序中如果所有的user线程都结束了,那这个程序本身就结束了,不管daemon是否

Java 编程思想 Chapter_14 类型信息

本章内容绕不开一个名词:RTTI(Run-time Type Identification) 运行时期的类型识别 知乎上有人推断作者是从C++中引入这个概念的,反正也无所谓,理解并能串联本章知识才是最重要的 本章的内容其实都是为类型信息服务的,主要内容有 一.Class对象 问题: 1.Class对象的创建过程是怎么样的 2.Class对象有哪几种创建方式,之间有什么差异 3.使用泛型 在了解类型信息之前,需要了解class对象 创建class对象,需要先查找这个这个类的.class文件, 查找