1、组合和继承之间的选择

组合和继承都允许在新的类中放置子对象,组合是显式的这样做,而继承则是隐式的做。

组合技术通常用于想在新类中使用现有类的功能而非它的接口这种情形。即在新类中嵌入某个对象,让其实现所需要的功能,但新类的用户看到的只是为新类所定义的接口,而非所嵌入对象的接口。为取得此效果,需要在新类中嵌入一个现有类的private对象。但有时,允许类的用户直接访问新类中的组合成分是极具意义的,即将成员对象声明为public。如果成员对象自身都隐藏了具体实现,那么这种做法是安全的。当用户能够了解到你正在组装一组部件时,会使得端口更加易于理解。比如Car对象可由public的Engine对象、Wheel对象、Window对象和Door对象组合。但务必要记得这仅仅是一个特例,一般情况下应该使域成为private。

在继承的时候,使用某个现有类,并开发一个它的特殊版本。通常,这意味着你在使用一个通用类,并为了某种特殊需要而将其特殊化。稍微思考一下就会发现,用一个“交通工具”对象来构成一部“车子”是毫无意义的,因为“车子”并不包含“交通工具”,它仅是一种交通工具(is-a关系)。

"is-a"(是一个)的关系是用继承来表达的,而"has-a"(有一个)的关系则是用组合来表达的。

到底是该用组合还是继承,一个最清晰的判断方法就是问一问自己是否需要从新类向基类进行向上转型,需要的话就用继承,不需要的话就用组合方式。

2、final关键字

对final关键字的误解

当final修饰的是基本数据类型时,它指的是数值恒定不变(就是编译期常量,如果是static final修饰,则强调只有一份),而对对象引用而不是基本类型运用final时,其含义会有一点令人迷惑,因为用于对象引用时,final使引用恒定不变,一旦引用被初始化指向一个对象,就无法再把它指向另一个对象。然而,对象其自身却是可以被修改的,Java并未提供使任何对象恒定不变的途径(但可以自己编写类以取得使对象恒定不变的效果),这一限制同样适用数组,它也是对象。

使用final方法真的可以提高程序效率吗?

将一个方法设成final后,编译器就可以把对那个方法的所有调用都置入“嵌入”调用里。只要编译器发现一个final方法调用,就会(根据它自己的判断)忽略为执行方法调用机制而采取的常规代码插入方法(将自变量压入堆栈;跳至方法代码并执行它;跳回来;清除堆栈自变量;最后对返回值进行处理)。相反,它会用方法主体内实际代码的一个副本来替换方法调用。这样做可避免方法调用时的系统开销。当然,若方法体积太大,那么程序也会变得雍肿,可能受到到不到嵌入代码所带来的任何性能提升。因为任何提升都被花在方法内部的时间抵消了。

在最近的Java版本中,虚拟机(特别是hotspot技术)能自动侦测这些情况,并颇为“明智”地决定是否嵌入一个final 方法。然而,最好还是不要完全相信编译器能正确地作出所有判断。通常,只有在方法的代码量非常少,或者想明确禁止方法被覆盖的时候,才应考虑将一个方法设为final。

类内所有private 方法都自动成为final。由于我们不能访问一个private 方法,所以它绝对不会被其他方法覆盖(若强行这样做,编译器会给出错误提示)。可为一个private方法添加final指示符,但却不能为那个方法提供任何额外的含义。

3、策略设计模式与适配器模式的区别

策略设计模式

创建一个能够根据所传递的参数对象的不同而具有不同行为的方法,被称为策略设计模式,这类方法包含所要执行的算法中固定不变的部分,而“策略”包含变化的部分。策略就是传递进去的参数对象,它包含要执行的代码。

适配器模式

在你无法修改你想要使用的类时,可以使用适配器模式,适配器中的代码将接受你所拥有的接口,并产生你所需要的接口。

4、内部类

内部类与组合是完全不同的概念,这一点很重要。

为什么需要内部类? — 主要是解决了多继承的问题,继承具体或抽象类

一般来说,内部类继承自某个类或实现某个接口,内部类的代码操作创建它的外围类的对象。所以可以认为内部类提供了某种进入其外围类的窗口。

内部类最吸引人的原因是:每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。

如果没有内部类提供的、可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效的实现了“多重继承”。也就是说,内部类允许继承多个非接口类型。

考虑这样一种情形:如果必须在一个类中以某种方式实现两个接口。由于接口的灵活性,你有两种选择:使用单一类或者使用内部类。但如果拥有的是抽象的类或具体的类,而不是接口,那就只能使用内部类才能实现多重继承。

使用内部类,还可以获得其他一些特性:

----- 内部类可以有多个实例,每个实例都有自己的状态信息,并且与其外围类对象的信息相互独立。

----- 在单个外围类中,可以让多个内部类以不同的方式实现同一个接口或继承同一个类。

----- 创建内部类对象的时刻并不依赖于外围类对象的创建。

----- 内部类并没有令人迷惑的is-a关系,它就是一个独立的实体。

5、序列化控制

当我们对序列化进行控制时,可能某个特定子对象不想让Java序列化机制自动保存与恢复。如果子对象表示的是我们不希望将其序列化的敏感信息(如密码),通常会面临这种情况。即使对象中的这些信息是private属性,一经序列化处理,人们就可以通过读取文件或者拦截网络传输的方式来访问到它。有两种办法可以防止对象的敏感部分被序列化:

实现Externalizable代替实现Serializable接口来对序列化过程进行控制,Externalizable继承了Serializable接口,同时增添了两个方法:writeExternal()和readExternal()。

两者在反序列化时的区别:

---- 对Serializable对象反序列化时,由于Serializable对象完全以它存储的二进制位为基础来构造,因此并不会调用任何构造函数,因此Serializable类无需默认构造函数,但是当Serializable类的父类没有实现Serializable接口时,反序列化过程会调用父类的默认构造函数,因此该父类必需有默认构造函数,否则会抛异常。

---- 对Externalizable对象反序列化时,会先调用类的不带参数的构造方法,这是有别于默认反序列方式的。如果把类的不带参数的构造方法删除,或者把该构造方法的访问权限设置为private、默认或protected级别,会抛出java.io.InvalidException: no valid constructor异常,因此Externalizable对象必须有默认构造函数,而且必需是public的。

---- Externalizable的替代方法:如果不是特别坚持实现Externalizable接口,那么还有另一种方法。我们可以实现Serializable接口,并添加writeObject()和readObject()的方法。一旦对象被序列化或者重新装配,就会分别调用那两个方法。也就是说,只要提供了这两个方法,就会优先使用它们,而不考虑默认的序列化机制。

这些方法必须含有下列准确的签名:

private void writeObject(ObjectOutputStream stream)

throws IOException;

private void readObject(ObjectInputStream stream)

throws IOException, ClassNotFoundException

---- 可以用transient关键字逐个字段地关闭序列化,它的意思是“不用麻烦你保存或恢复数据—我自己会处理的”。由于Externalizable对象在默认情况下不保存它们的任何字段,所以transient关键字只能和Serializable对象一起使用。

6、小结:

关于到底用组合还是继承,我的理解是优先使用组合,少用继承,由其是多重直接类的继承,会让你的程序带来灾难性的后果;内部类弥补了多继承问题,需要注意所依赖的外部类的生命周期;Android中提供了性能更好的Parcelable接口实现序列化。

Java(Android)编程思想笔记02:组合与继承、final、策略设计模式与适配器模式、内部类、序列化控制(注意事项)的更多相关文章

  1. Java编程思想 笔记

    date: 2019-09-06 15:10:00 updated: 2019-09-24 08:30:00 Java编程思想 笔记 1. 四类访问权限修饰词 \ 类内部 本包 子类 其他包 publ ...

  2. java编程思想笔记(1)

    java编程思想笔记(1) 一,对象的创建和生命周期 对象的数据位于何处?怎样控制对象的生命周期? 在堆(heap)的内存池中动态地创建对象. java完全采用了动态内存分配方式. 二,垃圾回收器 自 ...

  3. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

  4. JAVA学习笔记--策略设计模式与适配器模式

    一.策略设计模式 创建一个能够根据所传递对象的不同而具有不同行为的方法被称为策略设计模式:这类方法包含所要执行的算法中固定不变的部分,而“策略”包含变化的部分.策略就是传递进去的参数对象,它包含要执行 ...

  5. #Java编程思想笔记(一)——static

    Java编程思想笔记(一)--static 看<Java编程思想>已经有一段时间了,一直以来都把笔记做在印象笔记上,今天开始写博客来记录. 第一篇笔记来写static关键字. static ...

  6. 7.JAVA编程思想笔记隐藏实施过程

    欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/51040237 "进行面向对象的设计时,一项主要的考虑是:怎样将发生变 ...

  7. 2.1(java编程思想笔记)位移操作

    java位移操作主要有两种: 有符号位移:有符号位移会保留原有数字正负性,即正数依然是正数,负数依然是负数. 有符号位左移时,低位补0. 有符号右移时:当数字为正数,高位补0.当数字为负时高位补1. ...

  8. Java并发编程学习笔记

    Java编程思想,并发编程学习笔记. 一.基本的线程机制 1.定义任务:Runnable接口 线程可以驱动任务,因此需要一种描述任务的方式,这可以由Runnable接口来提供.要想定义任务,只需实现R ...

  9. Java并发编程读书笔记(一)

    ----------------------------------------------<Java并发编程实战>读书笔记-------------------------------- ...

随机推荐

  1. 大连网络赛 1006 Football Games

    //大连网络赛 1006 // 吐槽:数据比较水.下面代码可以AC // 但是正解好像是:排序后,前i项的和大于等于i*(i-1) #include <bits/stdc++.h> usi ...

  2. Tkinter教程之Frame篇

    本文转载自:http://blog.csdn.net/jcodeer/article/details/1811339 '''Tkinter教程之Frame篇'''#Frame就是屏幕上的一块矩形区域, ...

  3. 在fedora20下面手动为自己的安装程序创建桌面图标

    (博客园-番茄酱原创) 在/usr/share/applications/下面创建destktop文件,用于产生桌面图标 创建文件:touch android-eclipse.desktop 编辑文件 ...

  4. 第三百零四天 how can I 坚持

    我以为我遇到了,却是痴心妄想啊.哪有那么好的事.其实也无所谓,淡定,却又有点不淡定了. 洗澡睡觉吧,明天还要上班呢. 应该摆脱这种状态. 什么都不想,放空.

  5. 第二百八十六天 how can I 坚持

    bug不断啊,头疼. 今天早上到的倒是挺早. 中午吃的黄焖鸡,晚上加了会班. 勇江的鱼都死了,杨建的还剩3条,晚上到家都快十点了,还洗了衣服,没捞出来呢, 希望可以请下来假吧. 晾上衣服睡觉.

  6. HIVE删除表数据

    HIVE只有INSERT,没有UPDATE跟DELETE,所以通过其他的语句产生DETELE效果. 在HDFS上或者本地服务器上新建空的文件XXXXX, 然后执行: LOAD DATA LOCAL I ...

  7. ocp 1Z0-047 1-60题解析

    1. You need to load information about new customers from the NEW_CUST table into the tables CUST and ...

  8. UVALive 7464 Robots (贪心)

    Robots 题目链接: http://acm.hust.edu.cn/vjudge/contest/127401#problem/K Description http://7xjob4.com1.z ...

  9. C# 中的sealed修饰符学习

    转载原地址 http://developer.51cto.com/art/200908/147327.htm C#语言还是比较常见的东西,这里我们主要介绍C# sealed修饰符,包括介绍两个修饰符在 ...

  10. myeclipse内存配置

    配置文件路径:D:\work\myeclipse\MyEclipse for Spring 10\myeclipseforspring.ini 替换以下内容即可 -vmargs-Xmx768m-XX: ...