”对象“:问题空间中的元素及其解决方案空间中的具体呈现。
理念即是通过添加各种新的对象,可以将程序改编为一种描述问题的语言。
对象是具有状态、行为及标识的。
对象可以拥有自己的内部数据(用以赋予状态),方法(用以产生行为),对象在内存中都有唯一的地址。
关键字class的由来:状态不同但结构相同的对象汇聚在一起而组成的同一类对象。
类是描述了一系列具有相同特征(即数据元素)和行为(即功能方法)的对象,也就是说类其实是数据类型。
在面向对象领域中,我们将创建的变量称为”对象“或者”实例“,将操作变量称为”发送消息“或者”发送请求“。
让一个对象真正的发挥其作用就是向对象发送请求。而对象能够接收什么请求,是由其接口决定,对象所归属的类则定义了这些接口。
eg:
类型名 | Light |
---|---|
接口 | on() |
off() | |
brighten() | |
dim() |
Light lt=new Light(); lt.on();
接口定义了能向这个对象发送的请求。
代码+隐藏的数据=”实现“
在开发一个面向对象程序或者理解其设计时,可以将对象想象成”服务提供者“。程序是为用户提供服务的。
高内聚性:设计的组件(比如对象、方法、对象库等)无论从哪个方面都整合的很好。
程序员的两大阵营:”类的创建者“(负责创建新数据类型的人),”客户程序员“(在自己的应用程序里使用现有数据类型的人)。
”类的创建者“:只暴露必要的接口给客户程序员,同时隐藏其他所有不必要的信息。这样可以避免修改隐藏信息时对其他人造成的影响,即是隐藏代码的具体实现可以有效的减少程序的bug。
首要原因:防止客户程序员接触本不应该接触的数据类型内部运转的代码(即非那些用于解决特定问题的接口部分)。
第二个原因:让接口部分和实现部分分离,便于库的设计者在改变类的内部工作机制时,不用担心影响到使用该类的客户程序员。
Java提供了三个显示的关键字(访问修饰符)来设置访问控制:
还有一种默认的访问权限,即是包访问(package access)
复用一个类的最简单方法就是直接使用该类所生成的对象。
组合:新创建的类可以由任意数量和类型的对象组成,也可以任意组合这些对象以满足想要的功能,即是利用已有的类组合成一个新的类。(如果组合是动态的,通常称为聚合)
为了避免重复性代码的书写(即创建功能相近的类),我们复制了现有的类并且能够在此基础上再做一些增补,这就是继承的好处。
子类可继承父类的所有成员变量和方法及接口,同时子类可以增加或者复写父类没有或者已有的成员变量和方法及接口。
区分子类和父类很简单,第一种直接为子类添加新的方法,那么执行时,父类的行为讲会和你的预期不符。第二种就是重写方法,可以让子类与父类增加差异化。
替换原则(里氏替换原则):即当只重写父类中定义的方法时,子类和父类的类型将会是完全相同的(接口一模一样),这样我们就能够用子类的对象代替父类的对象。这是一种理想的继承方式,即是is-a关系。
当我们为子类的接口添加新的内容时,子类依然能够代替父类的对象,但不饿能通过父类的接口获取子类的新方法,这种关系即是is-like-a关系。
当涉及类型层次的时候,将一个对象视为父类的一个实例,而不是对象实际的类。
不同子类执行父类的同一方法时的结果应该是不同的,那么我们可能需要的是派生子类,这样可以扩展程序设计的能力。
eg:
当Bird对象的move()方法被调用时,(Goose对象执行的是行走、飞翔或者游泳,Penguin对象执行的则是移动或者游泳)。
我们将子类视为父类从而能够区别不同对象的不同方法,这也是向上转型。
前期绑定是非面向对象编译器的调用函数时所触发的,这样意味着当调用具体方法时,该方法名就决定了被执行代码的绝对地址。
但对于继承,程序需要运行时才能明确代码的地址,所以就有了面向对象使用的机制:后期绑定。(Java里会默认具备动态绑定特性,所以不用借助其他的关键字或者代码来实现多态,但c++会使用virtual关键字)
单根层次结构有利于实现垃圾收集器,这也是Java相对于c++的一个重要改进。既然所有的对象都拥有类型信息,那么就不用再去了解某个对象具体是什么类型了,这个特性对于系统级别的操作尤其重要,比如异常处理。
在大多数语言中,用数组就可以保存许多的内容。而Java中通常是创建一种新类型的对象,然后利用这个新对象来保存其他对象的引用,这个对象通常被叫做集合,并且会根据放入其中的内容而自行调整空间。
当然不同的集合也有着不同的用途:
几个不同的List类(用于保存序列),几个Map类(也叫做关联数组,用于关联对象),几个Set类(用于保存不同类型的对象),以及一些队列(queue)、树(tree)、栈(stack)等。
不同的集合在特定操作的执行效率上也有差异,比如:ArraytList和LinkedList,ArraytList随机获取元素是一种耗费固定时间的操作,意思就是不管你选择获取哪个元素,耗费的时间都是相同的,而LinkedList在列表中随机选择元素是一种代价很大的操作,查找列表更深处的元素也会耗费更多的时间。如果要在列表中插入元素,LinkedList耗费的时间会比ArrayList更少。
当我们知道向上转型是安全的时,反过来我们不知道Object对象实际上是什么类型,那么这种向下转型就是不安全的,当然如果向下转型失败,会得到异常。
为了节省向下转型与其关联的运行检查所需要的时间,我们通常关注创建的集合能不能明确所包含的对象类型。
C++需要显式删除对象,因为C++的宗旨是效率优先。
Java只允许动态分配内存。当创建一个对象时,需要new操作符来创建一个对象的动态实例。
Java语言的底层支持垃圾收集器机制,所以它会自动找到无用的对象并将其销毁。
异常是从错误发生之处“抛出”的对象,而根据错误类型,它可以被对于的异常处理程序所“捕获”,当然异常不允许被忽略。