Java编程思想——读后总结
更新时间线————————2018年5月5日20:23:01 Begin
第一章对象导论
Java的五大特性
- 万物皆对象:特征为属性,行为为方法。(抽象过程)
- 程序是对象的集合他们通过发送消息来告知彼此所要做的事情。
- 每个对象都有自己的由其他对象所构成的存储。因此可以在程序中构成复杂的体系结构。
- 每个对象都拥有其类型。即:每个对象都是一个类的实例
- 某一特定类型的所有对象都可以接受同样的消息。对象的继承性。面向对象的可替代性。
每个对象都拥有状态、行为和标识。状态==属性,行为==方法,标识==区分对象的唯一性,就是每个对象在内存中的地址。
每个对象都有一个接口,每个对象都提供服务。对象相当于“服务的提供者”,程序本身将向用户提供服务。
将程序开发人员按照角色可分为“类创建者”和客户端程序员,客户端程序员的目标是收集用来实现快速应用开发的类。类创建者的目标是构建类。
构建的类只想客户端程序员暴露必须的部分,而隐藏其他部分。即是访问控制;
访问控制的原因,1.让客户端程序员无法触及他们不应该触及的部分。2允许库设计者可以改变类内部的工作方式而不用担心会影响到客户端程序员。
访问权限修饰符:private protected public 默认的(什么都不写)
复用具体实现:
最简单的复用某个类的方式就是直接从创建该类的一个对象。也可以将那个类的一个对象至于某个新的类中。我们称之为创建一个成员对象。即拥有的关系。
继承:
在创建一个类之后,即时另一个新类与其有相似的功能,你还是得重新创建一个新类。如果我们能够以现有的类为基础。复制它,然后通过添加和修改这个副本来创建新类那就要好多课。这就是继承。
子类继承父类以后,只有添加新方法或者覆盖父类方法可以使基类与导出类产生差异。
是一个与像一个的关系
继承之后可以子类替代父类。一个子类继承父类。没有新添加方法。则是纯粹替代,称之为替代原则。
但是有时为了扩展接口,子类继承父类后又添加了属于自己本身的接口元素(方法),这时候虽然可以替代,但这种替代是不完美的,因为父类无法方位子类新添加的方法。这时候就这是子类像一个父类的关系。
伴随多态的可互换对象
因为编译器不可能产生传统意义上的函数调用,所以一个非面向对象编程的编译器产生的函数调用会引起所谓的前期绑定。也称之为编译期绑定。而运行时将这个调用解析到将要被执行的代码的绝对地址。而在面向对象的时候直到运行时才能确定对象的地址。这叫后期绑定。也称之为运行期绑定。java使用一小段特殊的代码来替代绝对地址的调用。这段代码会在第八章的生活详述。
单根继承结构
在面向对象OOP中,所有的对象都具有一个公用的接口,都有一个终极基类Object。使得垃圾回收变得容易的多,等其它好处。
容器
通常我们创建对象的时候都不确定创建几个,或者生存多久。所以java就有了数组、集合或者叫容器。在java中不同容器可以满足不同的需要。例如List中的ArrayList和LinkedList,ArrayList中随机访问效率高,LinkedList插入和删除效率高。
参数化类型
在java SE5之前,集合数组默认存储都是Object类型。这样就可以存储任何对象。也带来了很多不好的地方。因为存储的时候所有对象都有个终极基类Object。所以都可以向上转型为Object,但是取出来的时候却容易把对象的类型丢失。强转的生活如果对象类型不一致则会上抛异常。而且不容易阅读代码。在Java SE5之后推出了泛型的概念,一对尖括号,中间包含类型的信息。通过这个可以限制存储的类型。(为编译器检查)例如:List<String> 这样就可以知道这个容器里面存储的都是String类型,或者其子类型。这样就可以更容易的理解代码,并且更好的控制对象,避免向下转型的危险性。
异常处理:处理错误
异常处理在面向对象之前就已经有了,所以异常处理不属于面向对象特征。java中需要强制捕获一些异常。
Web是什么
客户/服务器系统的核心思想是:系统具有一个中央信息存储池,用来存储某种数据,它通常存在于数据库中,你可以根据需要把它分发给某些人员或机器集群。客户/服务器概念的关键在于信息存储池的位置集中于中央,这使得它可以被修改,并且这些修改将被传播给信息消费者。
第二章一切都是对象
用引用操纵对象
java中的对象都是用引用操纵的,并且可以操作的行为也是根据引用类型决定的。例如:String s,那么对象s的行为只能是String里面所拥有的行为。
必须由你自己创建对象
如果只有对象的引用,还不算完整的对象,就相当于有了指针却没有指向的东西,拿了遥控器却没有对着电视,还是不完整的。所以java中有了对象的引用后,必须给予对象的“值” 例如:String str = new String(“你好”),String str = “你好”
对象存在什么地方
java中的对象数据 有五个不同的地方可以存储数据:
1.寄存器:这是最快的存储区,因为它位于不同于其他存储区的地方——处理器内部。但是寄存器的数量及其有限,所以寄存器根据需求进行分配。你不能控制。
2.堆栈:位于通用RAM(随机访问存储器)中,但通过堆栈指针可以从处理器哪里获得直接支持。堆栈指针若向下移动,则分配新的内存。若向下移动则释放内存。这是一种快速有效的分配存储方法。仅次于寄存器。一般存储对象的引用。、
3. 堆:一种通用的内存池(也位于RAM区),用于存储所有的java对象,堆不同于堆栈的好处是:编译器不需要知道存储的数据在堆里存活多长时间,因此在堆里分配内存有很大的灵活性。
4. 常量存储,常量值通常直接存放在程序代码内部,这样做是安全的。因为他们永远不会被改变。有时,在嵌入式系统中,常量本身会和其他部分隔离开。所以在这种情况下,可以选择将其存放在ROM(只读存储器)中。
5. 非RAM存储。如果数据完全存活于程序之外,那么它可以不受程序的任何控制,在程序没有运行时也可以存在。其中两个基本的例子:流对象和持久化对象。
特例:基本类型
八大基本类型及Viod类型,略 高精度数字:BigInteger支持任意精度的整数,BigDecimal支持任意精度的定点小数。
java中的数组
数组创建略。需要注意的是当创建一个数组对象时,实际上也是创建了数组的引用,并且每个引用都自动被初始化为一个特定的值。
作用域
作用域由花括号的位置决定{},在作用域定义的变量只可用在作用域结束前。
对象的作用域
对象的引用存活也是同上面一样在作用域结束前,引用失效,对象还会在内存中。属于垃圾对象。
创建新的数据类型类
略
字段和方法
每个类通常有字段或方法组成,也可两者都有。即:变量和方法
方法的介绍
略
Static关键字
两种情况用到Static:1. 只想为某特定域分配单一存储空间,而不去考虑究竟创建多少对象,甚至根本就不创建对象。2. 希望某个方法不与包含它的类的任何对象关联起来。也就是说不创建对象也可以使用这个方法。
注释及文档略。后期后专门开一篇。
更新时间线———————— End
未完待续ing
第三章操作符
更简单的打印语句
利用的静态引入:
静态导包就是java包的静态导入,用import static代替import静态导入包是JDK1.5中的新特性。
一般我们导入一个类都用 import com…..ClassName;而静态导入是这样:import static com…..ClassName.*;这里的多了个static,还有就是类名ClassName后面多了个.* ,意思是导入这个类里的静态方法。当然,也可以只导入某个静态方法,只要把 .* 换成静态方法名就行了。然后在这个类中,就可以直接用方法名调用静态方法,而不必用ClassName.方法名 的方式来调用。
优先级

赋值
A = B,就是把B的值赋给A,就是把等号右边的值赋值给等号左边。
如果是两个都是引用对象的话,赋值的是引用。即:两个变量同时引用(指向)一个相同对象实例。
自增自减
需要注意的是++在前与在后的区别。自增自减同理。

逻辑操作符
与、或、非


非即是“取反”即可。
这里要注意的是断路问题。当一个逻辑操作符的时候不会出现断路问题,即逻辑表达式两边都会执行。
当逻辑操作符为两个的时候会出现断路问题。即:如果能正确算出表达式的结果,就不会计算后面的。例如:false && 2==2 这个逻辑表达式,就不会执行2==2的结果判断。因为与判断的原则遇false则false,所以就出现了断路。
按位操作符
与、或、与或、非及取反,按位操作符都是以二进制进行运算的。
与
当两个值都为1的时候则为1.否则为0,例如:
操作符优先级图片取自:https://www.cnblogs.com/zjfjava/p/5996666.htm
| 十进制 | 二进制 |
| 10 | 1010 |
| 2 | 0010 |
| 结果为: | 0010 |
0010在二进制中为:2,所以 10&2 = 2
或
当有一个为1时则为1,没有1的时候则为0,例如:
十进制 二进制
10 1010
2 0010
结果为: 1010
在二进制中1010 =10,即:10|2 = 10;
与或
当两个值相同时,则为0,不同时则为1;例如:
十进制 二进制
10 1010
2 0010
结果为: 1000
在二进制中1000=8,即:10^2 = 8;
取反
就是所有的位数都取反。取反为一元运算
例如:10 ,用二进制表示就是:00000000 00000000 00000000 00001010
取反以后就是:11111111 11111111 11111111 11110101
即等于-11
移位操作符
>> 与 <<
例如:A >> B 即:把A以二进制的方式右移B为。
例如:10的二进制位:1010
10 >> 2 == 0010 = 2
10 << 2 == 101000 = 2的5次方+2的3次方 = 40
运算时候,通常表达式中出现的最大的数据类型决定了表达式的结果数据类型。
第四章控制执行流程
总结:
while 与do——while的区别。while则是先判断,后执行,do-while则是先执行一次,后判断;
break 与continue的区别, break会跳出循环,continue则只跳出本次循环继续下一循环、
第五章初始化与清理
方法的重载
在一个类中,方法名相同,参数列表不同(个数不同或类型不同)的两个类就叫重载。
this关键字
this代表当前类的对象/实例
Static的含义
静态,需要注意的是静态方法是没有this的,在static方法内部不能调用非静态方法,反过来确实可以的。
清理:终结处理和垃圾回收(不常用)
假定你的对象(并非new)获得了一块“特殊“内存区域,由于垃圾回收器只知道释放那些经由new分配的内存,所以它不知道该如何释放该对象的这块“特殊”内存,为了应对这种情况,java允许在类中定义一个名为finalize()的方法。垃圾回收器准备释放对象占用的存储空间,将首先调用其finalize()方法,并在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
对象可能不被垃圾回收,垃圾回收并不等“析构”,垃圾回收只与内存有关
finalize使用场景
之所以要有finalize方法,是由于在分配内存时,采用了类似C语言中的做法,而非java中的通常做法。这种情况主要发生在使用“本地方法”的情况下,本地方法是一种在java中调用非java代码的方式,本地方法目前只支持C与C++,但它们可以调用其他语言写的代码,所以实际上可以调用任何代码。在非java代码中,也许会调用C的malloc函数系列来分配存储空间,而且除非调用了free函数,否则存储空间将得不到释放,从而造成内存邪路。当然,free是C和C++中的函数,所以需要在finalize中用本地方法调用它。
JVM
暂略
成员初始化
所有变量在使用前都能得到恰当的初始化,对于方法的局部变量,java以编译错误的形式贯彻这个保证。
静态数据的初始化
无论创建多少个对象,静态数据都只占用一份存储区域。Static关键字不能应用于局部变量。
数组的初始化
//创建数组的第一种方法
int[] arr=new int[6];
//创建数组的第二种方法
int[] x={1,2,3,4};
//创建数组的第三种方法。
int[] y= new int[]{1,2,3,4,5};
可变参数列表

枚举类型
使用enum关键字修饰。枚举类型的值都是常量,
第六章访问权限控制
如何把变动的事物与保持不变的事物区分开来。
接口访问权限——public
接口访问权限,使用public修饰符修饰。任何地方都可以访问public修饰的变量。
继承访问权限——protected
即:继承就可以访问
包访问权限——默认
如果不加任何修饰符,就是默认权限,默认权限只能本类和同一包类才可以访问。
你无法访问——private
关键字private修饰的变量或者方法,除了包含该成员的类之外,其它都不可访问,相当于自己封闭自己。
摘自网上的一个图片很好的说明了权限修饰符的 关系

第七章复用类
复用代码是java众多引人注目的功能之一,仅仅能复制代码并对之加以改变是不够的,它还必须能够做更多的事情。
三种方式:
组合:创建新类并持有现有类的对象,组成的类就叫组合。
可参考我的另一篇文章: Java设计模式——装饰者模式
继承:创建新类并使用extends修饰符继承现有的类,然后在其中添加新代码这就是继承。
可参考我的另一篇文章中的Cglib代理,就是使用的子类代理:Java设计模式——代理模式
代理:这个是继承和组合之间的中庸之道,因为我们将一个成员对象至于所要构造的类中(就像组合),但与此同时我们在新类中暴露了该成员的所有方法(就像继承)。
可参考我的另一篇文章代理:Java设计模式——代理模式
所有private的方法都隐式的指定为final的。
第八章多态
个人觉得多态是很重要的,而且自己比较喜欢的。
学习多态的时候要有向上转型的概念。可自行百度向上转型这里不细说。
可看我的另一篇文章:Java面向对象三大特征
此篇总结也也会写一下多态
多态的作用则是消除类型之间的耦合关系,多态方法调用允许一种类型表现出与其他相似类型之间的区别。
构造器里的多态行为
这个是需要注意的:就拿书中的例子吧。
场景:
如果一个构造器的内部调用正在构造的对象的某个动态绑定方法,那会发生什么情况呢?
在一般的方法内部,动态绑定的调用时在运行时才决定的。因为对象无法知道它是属于方法所在的那个类,还是属于那个类的导出类(子类)。
如果要调用构造器内部的一个动态绑定方法,就要用到那个方法的被覆盖后的定义。然而这个调用的效果可能相当难于预料,因为被覆盖的方法在对象呗完全构造之前就会被调用。这可能会造成一些难于发现的隐藏错误。如下面的例子:摘自书上代码:感觉这个知识点比较重要,
class Glyph { void draw() { System.out.println("Glyph.draw()"); }; Glyph(){ System.out.println("Glyph() before draw()"); draw(); System.out.println("Glyph() after draw()"); } } class RoundGlyph extends Glyph{ private int radius = 1; RoundGlyph(int r){ radius = r; System.out.println("RoundGlyph.RoundGlyph().radius = " + radius); } void draw() { System.out.println("RoundGlyph.RoundGlyph().radius ="+ radius); } }
然后创建子类对象
new RoundGlyph(5);
然后看打印信息:

这个牵涉到创建类的顺序:不过一般构造器的工作实际上是创建对象。
第九章接口
接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法。
抽象类与抽象方法都需要用abstract修饰。有抽象方法的类叫做抽象类,抽象类不一定有抽象方法。
接口:使用interface修饰,接口里面的方法必须是抽象的不可为完整的方法,接口里面的变量默认是public static final的。
java中只能单继承,可多实现接口。继承具有传递性。
因为你放入接口中的任何域都自动是static和final的,所以接口就成为了一种很便捷的用来创建常量组的工具。
嵌套接口,接口可以嵌套在类或其它接口中。书上有例子,工作中暂时没见到用过,暂略
实现多接口时候
需要注意的是,实现多接口时候,接口的抽象方法名称一样而返回类型或者参数不一样时,会出现什么情况呢:下面举个例子

如图所示,第二个方法报错,这是因为方法的重载只能从参数列表来区分,不能根据返回类型区分方法的重载,所以java编译器区分不了void f()与int f()在调用的时候会是调用哪个方法。
接口的适配
接口最吸引人的原因之一就是允许同一接口具有多个不同的具体实现。例如:一个方法的参数被指定为接口类型。
接口最常见的用处就是策略模式(注:书上说的,我还不知策略模式是啥呢,我现在立马去总结策略模式)
可以看我的另一篇文章 Java设计模式——策略模式
第十章内部类
可以将一个类的定义放在另一个类的内部,这就是内部类。

浙公网安备 33010602011771号