经典的书再读一遍,虽然1.8有很多新特性,java12都出来了,但是真的写的不错的书,还是这几本。
一、抽象过程
所有编程语言都提供抽象机制,可以认为,人们能够解决问题的复杂性直接取决于抽象的类型和质量。C、BASIC之类的语言都是对汇编语言的抽象,他们的抽象是基于计算机结构,而不是基于要解决的问题的结构。另一种机器建模的方式就是只针对问题建模,他们针对特定问题是不错的解决方案,但是超出其特定领域,就力不从心了。
面向对象(OOP,Object Oriented Programming 面向对象的程序设计)方式通过向程序员提供问题空间中的元素的工具更进了一步,它不受限于特定问题,只要添加新类型就可以适应某个特定问题。
成功的面向对象的五个特性:
(1)万物皆为对象;
(2)程序是对象的集合,他们通过发送消息来告知彼此所要做的;
(3)每个对象都可以拥有其他对象;
(4)每个对象都有类型;
(5)某一类型的所有对象都可以接收同样消息。这种可替代性(substitutability)是一个强有力的概念。
二、每个对象都有一个接口
类具有相同的特性(数据元素)和行为(功能),实际上就是一个数据类型。
而接口(interface)类似于定义了类的某些功能。
Unified Modeling Language (UML)又称统一建模语言或标准建模语言。在IDEA中都可以画出来,技术的发展真的是很快的!而spring framework都到了5.0!
三、被隐藏的具体实现
为啥类会用权限控制来隐藏某些细节?因为这样的隐藏可以任意修改被隐藏的部分,而不用担心对其他任何人造成影响。
这也是权限控制存在的原因:
(1)不让客户端程序员访问他们不应该访问的部分;
(2)修改类内部而不用担心影响到客户端程序员;
在建立新类的时候首先考虑组合,过多的继承会导致过分复杂的设计。
继承时,子类包括了父类的所有成员(包括private,尽管不能访问)
是一个 与 像是一个
继承的关系类似于 is a,继承接口的关系类似于 is like a
多态:即父类接口指向子类对象,调用子类的实现。
一个非面向对象语言在调用时会引起所谓的前期绑定,然而在OOP中,程序直到运行时才能确定代码的地址,因此面向对象语言使用了后期绑定的概念。在java中,动态绑定是默认的。
将导出类看做是基类的过程就是 向上转型(upcasting);所以向下转型,就是父类变成子类。
四、单根继承结构
单根继承结构使垃圾回收器的实现变得容易得。
怎样才能知道何时销毁这些对象?
C++认为效率控制是最重要的议题,所以给程序员提供了选择的权力。为了追求最大的执行速度,对象的存储空间和 生命周期可以在编写程序时确定。
第二种方法:在堆(heap)的内存池中动态地创建对象。
Java完全采用了动态内存分配方式,创建对象时要用new 关键字。
五、一切都是对象
程序运行时,对象是怎么放置安排的呢?有五个不通的地方可以存储数据:
(1)寄存器;最快的存储区,CPU内部
(2)堆栈;位于通用RAM,但通过堆栈指针可以从处理器那里获得直接支持。Java知道确切生命周期。
堆栈指针向下移动,则分配新的内存;若向上移动,则释放内存。对象引用存放在堆栈,但是Java对象并没有存储在这里。
(3)一种通用的内存池(也位于RAM),用于存放所有的Java对象。编译器不用知道存活多长时间。
(4)常亮存储,通常直接放在程序代码内部。
(5)非RAM存储。如流对象和持久化对象。
“基本”类型,创建并非是引用的“自动”变量,放置在堆栈中。这种数据类型的大小一般是确定的。
高精度类型:BigInteger、BigDecimal
import关键字,导入包
static:静态或者类的,实际上就一个特点,同一个类共享这个成员,他们指向同一个存储空间。
javadoc是用来提取注释的工具,它输出的是一个html文件。
文档注释的一些标签:
(1)@see 引用其他类
(2){@link package.class#member laber} 与@see极其类似,只是它用于行内
(3){@docRoot} 用来搞路径的
(4){@inheritDoc} 继承的注释
(5)@version 版本信息
(6)@author 作者
(7)@since 最早使用版本
(8)@param 参数说明
(9)@return 返回值
(10)@throws 抛出异常
(11)@deprecated 过时的 被@Deprecated取代
六、操作符
引用,注意引用传的是地址
++a a++ 前缀式和后缀式,差别在于++a先自增再赋值,a++先赋值再自增
== 与 equals()方法
比较有趣的是"aa" == "aa"
短路运算符: && ||
按位操作符:& | ^ ~
移位操作符:<< >> >>>
三元操作符: ? :
七、控制执行流程
foreach语法:
for(val : list)
switch注意一点,default如果没写break,结果也是default后面的语句会运行。
rand.nextInt(26) 里产生的随机数是0~25间的
八、初始化与清理
static方法就是没有this 的方法,在static方法内不能调用非静态方法,反过来是可以的
关于垃圾回收:
1,对象可能不被垃圾回收;
2,垃圾回收并不等于“析构”;
3,垃圾回收只与内存有关;
finalize方法用来对付java语言中的本地方法。
System.gc() 用于强制进行终结动作。
垃圾回收器并非基于引用记数技术,它的基本思想是:对任何“活”的对象,一定能追溯到其存活的堆栈或静态存储区之中的引用。这种方式下,Java虚拟机采取一种自适应的回收技术。
静态初始化只有在必要时刻才会进行,没有调用这个类的时候,当然也就不会调用这个类的静态方法了。初始化的顺序也是先静态对象初始化,然后才是非静态对象。
注意:即使没有显示地使用static,构造器实际上也是静态方法。
九、访问权限控制
重构即重写代码,以使得它更可读、更易理解,并因此而更具备可维护性。在面向对象编程中需要考虑一个基本问题:“如何把变动的事物与保持不变的事物区分开来”。
Java解释器的运行过程如下:首先,查找系统变量CLASSPATH
java的访问权限控制符:public 包访问 protected private
十、复用类
final表示这是无法改变的,无法改变通常出于两种理由:设计或效率。
final在三种情况下可能被用到:数据、方法和类。
1,数据
(1)作为编译时常量;(2)运行时初始化的值,而且不希望改变。
对(1),减轻运行时负担,一个static + final的对象,只占用一段不能改变的存储空间。注意一点,不是说final的值都在运行时就可以知道,比如 final static ran = new Random(37)。
注意final变量必须在定义的地方或者构造方法中进行赋值。
另外,final可以做参数,这样的参数,只可以读,但不能修改。
2,方法
为啥要用final修饰方法?一是锁定方法,继承之后也不能改,二是可以提升效率。为啥final修饰的方法可以提升效率?因为早期的final,可以跳过一些步骤,现在不建议使用了。
final和private,有个有意思的地方,所有private方法隐式都是final。同名也只是新建了一个方法。
3,类
对类而言,final的含义也很好猜,就是不让其他类继承。
再次明确一个概念,加载,类的代码只有在第一次使用时才会被加载。
十一、多态
多态的作用在于消除类型之间的耦合关系。
Java中除了static和final(private也属于final的一种)之外的方法,都是后期绑定的。这样有个好处,我们和基类打交道就可以了。
多态有一个特殊场景(以后都用sup表示supper父类,sub表示子类),sup和sub都有field,这时候sup.field和sup.getField的多态表现不同,sup.field指向父类的属性,而getField方法指向子类的属性。简单说,父类藏着自己的钱,除非你直接找他,他是不认这个账的。
静态方法也是很有趣的,调用父类的静态方法,不会进行多态表现,这就像总部已经划分好了岗位序列,你在省分也是操作不了的。
构造器是隐式静态的,它会依次生成父类对象,就像基因它是一代代传下来的,要是寻觅你的肤色,就要一代代回溯到祖宗的基因。这个东东,可以在聊天的时候吹一吹,说java类的构造的时候唬一唬小朋友。
要注意多态在销毁对象和调用顺序上可能产生的问题,销毁对象有一点,一般是要先销毁导出类,再销毁基类;调用顺序上,导出类,可能会调用到没有初始化的对象。这就好像顺拐,想走正常路,却走出了搞笑的一路。这个知识点,可能会在查找问题中有用。这就对构造器的初始化有一个要求,尽可能简单,有其他的方法,也采用final形式的。
在书中,对组合的推崇远胜于继承,因为继承会让事情变得更加复杂。然后继承中可以通过字段来表示状态。
多态一般针对的是向上转型,而向下转型通常容易得多,就是打个括号。
十二、接口
和接口相关的有抽象类,还有内部类。
interface有个变化,可以有static、default方法。interface的方法默认是public,另外java不允许继承(实现)后的权限变小。
策略设计模式,通过一个对象或者参数控制行为:
这个模式,将固定的部分写在方法里,变化的部分通过策略来表现。就像鼠标,按左键或者右键,他们的行为是不一样的。这种模式在跳转过程中可以参照,但是不一定写成类,写成枚举的参数好像更好用。
适配器设计模式,接受所有接口,然后再产生需要的接口。这就像家里电脑的白色转接口,好像一般很少会用到适配器模式,它在重新设计代码时可以用到。
对于接口,很有趣的一句话:接口是没有相关的存储!但是我可以看到接口实际上也是以类的方式存储:
java不支持多继承,支持interface的多实现,类似于父亲只能有一个,而亲戚可以有很多个。写接口的时候,可以同时实现几个接口。
对于interface中的域,自动是static、final的,因此,在interface中定义的东东就是:
int JANUARY=1
而更加常见的变量定义是enum,没错,这两个的域都是static、final的。
工厂方法,是用来生成实现某接口对象的典型方法。这种方式的好处在于,将接口和实现完全隔离!就像哪个隔着,吃东西的人是不用知道怎么做出来罐头的,只要符合工厂的规范就可以了。这样会有什么好处?当然是你换了一个实现,用户跟不上就没有感知。