Thinking in Java(整理笔记第二天)

1.5 复用具体实现

    1、一旦你有了这样的设计,它就可供复用。代码复用是面向对象程序设计语言所提供的最了不起的优点之一。

    2、新的类可以由任意数量、任意类型的其他对象以任何可以实现新的类中想要的功能的方式所组成。

    3、新类的成员对象通常都被声明为private,使得使用新类的客户端程序员不能访问他们。这也使得你可以在不干扰现有客户端代码的情况下,修改这些成员。也可也在运行时修改这些成员对象,以实现动态修改程序的行为。

1.6 继承

    1、因为不需要在问题描述和解决方案描述之间建立许多中间模型。通过使用对象,类型层次结构成为了主要模型,因此,可以直接从真实世界中对系统的描述过渡到用代码对系统进行描述。

    2、这个新的类型不仅包括现有类型的所有成员(尽管private成员被隐藏了起来,并且不可访问),而且更重要的是它复制了基类的接口。也就是说,所有可以发送给基类对象的消息同时也可以发送给导出类对象。

    3、通过继承而产生的类型等价性是理解面向对象程序设计方法内涵的重要门槛。    

    4、如果只是简单地继承一个类而并不做其他任何事,那么在基类接口中的方法将会直接继承到基类中。

    5、直接在导出类中添加新方法。

    6、应该仔细考虑是否存在基类也需要这些额外的方法的可能性。

    7、想要覆盖某个方法,可以直接在导出类中创建该方法的新定义即可。

1.7 伴随多态的可互换对象

    1、这样的代码是不会受添加新类型影响的,而且添加新类型是扩展一个面向对象程序以便处理新情况的最常用方法。

    2、通过导出的新子类型而轻松扩展设计的能力是对改动进行封装的基本方式之一

    3、如果不需要知道哪一段代码会被执行,那么当添加新的子类型时,不需要更改调用它的方法,他就能够执行不同的代码。

    4、编译器不可能产生传统意义上的函数调用。一个非面向对象编程的编译器产生的函数调用会引起所谓的前期绑定。

    5、然而在OOP中,程序直到运行时才能确定代码的地址,所以当消息发送到一个泛化对象时,必须采用其他的机制。

    6、面向对象程序设计语言使用后期绑定的概念,当向对象发送消息时,被调用的代码直到运行时才能确定。

    7、为了执行后期绑定,Java使用一小段特殊的代码来替代绝对地址调用。

    8、而在Java中,动态绑定是默认行为,不需要添加额外的关键字来实现多态。

    9、把将导出类看做是它的基类的过程称为向上转型(upcasting)

    10、一个面向对象程序肯定会在某处包含向上转型,因为这正是将自己从必须知道确切类型中解放出来的关键。

    11、当Java编译器在编译doSomething()的代码时,并不能确切知道doSomething()要处理的确切类型 。

    12、当向一个对象发送消息时,即使涉及向上转型,该对象也知道要执行什么样的正确行为。

1.8 单根继承结构

    1、这个终极技能基类的名字就是Object。事实证明,单根继承结构带来了很多的好处。

    2、在单根继承中的所有对象都具有一个公共的接口,所以它们归根到底都是相同的基本类型。

    3、并且在所获得的任何新类库中,总会用到一些不兼容的接口,需要花力气(有可能要通过多重继承)来使新接口融入你的设计中。

    4、单根继承结构保证所有对象都具有某些功能。

1.9 容器

    1、如果不知道在解决某个特定问题时需要多少个对象,或者他们将存活多久,那么就不可能知道如何存储这些对象。

    2、创建另一种对象类型。这种新的对象类型持有对其他对象的引用。

    3、因此不需要知道将来会把多少个子对象置于容器中,只需要创建一个新的容器对象,然后让它处理所有细节。

    4、Java在其标准类库中也包含有大量的容器,在某些类库中,一两个通用容器足够满足所有的需求,具有满足不同需要的各种各样的容器,List(用于存储序列),Map(也被称为关联数组,用来建立数组之间的关联),Set(每种对象类型只支持一个),以及诸如队列、树、堆栈等更多的构件。

    5、第一,不同的容器提供了不同类型的接口和外部行为。堆栈相比于队列就具备不同的接口和行为,也不同于集合和列表的接口和行为。它们之中的某种容器提供的解决方案可能比其他容器要灵活的多。

    6、第二,不同的容器对于某些操作具有不同的效率,ArrayList和LinkedList。它们都是具有相同接口和外部行为的简单序列,但是它们对某些操作所花费的代价却有天壤之别。在ArrayList中,随机访问元素是一个花费固定时间的操作,对LinkedList来说,随机选取元素需要在列表中移动,这种代价是昂贵的,访问越靠近表尾的元素,花费的时间越长,而另一方面,如果想在序列中间插入一个元素,LinkedList的开销比ArrayList要小。

    7、我们可以在一开始使用LinkedList构建程序,而在优化系统性能时改用ArrayList。接口List所带来的抽象,把在容器之间进行转换时对代码产生的影响降到最小限度。

    

1.9.1 参数化设置

    1、容器存储的对象都只是具有Java中的通用类型:Object。单根继承结构意味着所有东西都是Object的容器可以存储任何东西。这使得容器很容易被复用。

    2、要使用的这样的容器,只需要在其中置入对像的引用,稍后还可以将他们取回。但是由于容器只存储Object,所以当将对象引用置入容器时,它必须被向上转型Object对象的引用.

    3、这里的转型不是向继承结构的上层转型为一个更泛化的类型,而是向下转型为更具体的类型 ,这种转型我们称为向下转型。

    4、向上转型是安全的,向下转型几乎是不安全的。

    5、当从容器取出对象引用时,还是必须要以某种方式记住这些对象究竟是什么类型,这样才能执行正确的向下转型。

    6、参数化类型就是一个编译器可以自动定制作用于特定类型上的类。   

1.10 对象的创建和生命期

    1、每个对象为了生存都需要资源,尤其是内存。当我们不需要一个对象时,它必须被清理掉,使其占用的资源可以被释放和重用。

    2、当处理完某个对之后,系统某个其他部分可能还在处理它

    3、为了追求最大的执行速度,对象的存储空间和生命周期可以在编写程序时确定,这可以通过将对象置于堆栈(它们有时被称为自动变量(automatic variable)或限域变量(scoped variable))或静态存储区域来实现。

    4、还有一种方式就是堆的内存池中动态地创建对象。

    5、如果需要一个新的对象,可以在需要的时刻直接在堆中创建。因为存储空间是在运行时被动态管理的,所以需要大量的时间在堆中分配存储空间,这可能要远远大于在堆栈中创建存储空间地时间。在堆栈中创建空间和释放存储空间通常各需要一条汇编指令即可,分别对应栈顶指针向下移动和将栈顶指针向上移动

    6、动态方式有这样一个一般性的逻辑假设:对象趋向于变得复杂,所以查找和释放存储空间的开销不会对对象的创建创造重大冲击。动态方式所带来的更大的灵活性正式解决一般化编程问题的要点所在。

    7、每当想要创建新对象时,就要使用new关键字来构建此对象的动态实例。

    8、对于允许在堆栈上创建对象的语言,编译器可以确定对象的存活时间,并可以自动销毁它。

    9、Java提供了被称为“垃圾回收器”的机制,它可以自动发现对象何时不再被使用,并继而销毁它。

1.11 异常处理:处理错误    

    1、异常是一种对象,它从出错的地点被”抛出“,并被专门设计用来处理特定类型错误相应的异常处理器”捕获“。

    2、异常处理就像是与程序正常执行路径并行的,在错误发生是执行的另一条路径。

    3、因为它是另一条完全分离的执行路径,所以它不会干扰正常的执行代码。因为不需要被迫定期检查错误。

    4、异常不能被忽略,所以它保证了一定会在某处得到处理,异常提供了一种从错误状况进行可靠恢复的途径。

    5、Java一开始内置异常处理,而且强制你必须使用它。它是唯一可接受的错误报告方式。

    6、异常处理不是面向对象的特征——尽管在面向对象语言中语言中异常常被表示成为一个对象。

1.12 并发编程

    1、但是对于大量的其他问题,我们只是想把问题切分成多个可以独立运营行的部分(任务),从而提高程序的响应能力。这是彼此独立的运行的部分成为线程,成为“并发”。

    2、用户可以在按下按钮后快速得到一个反应,而不用被迫等待到程序完成当前任务为止。

    3、线程只是一种为单一处理器分配执行时间的手段。

    4、由于程序在逻辑上被分为线程,所以如果机器拥有多个处理器,那么程序不需要特殊调整也能执行的更快。

    5、存在隐患:共享资源。例如:两个进程不能同时向一台打印机发送消息。

猜你喜欢

转载自blog.csdn.net/weixin_45697323/article/details/121502569