阅读原文:【读】Java 核心技术卷 1
看到这本书时,我的内心是崩溃的,卷 1 就 700 多页,但是这本书是很多前辈所推荐的,想必其中必有精华所在,硬着头皮上吧。
如何阅读本书
拿到书的第一眼肯定去看目录,大概了解一下,各个章节所讲内容。
为表对作者的尊重,快读扫读了,译者序、前言和致谢。
通过目录了解到,第 1,2 章所讲概述和环境搭建,对于我来说没有价值,选择忽略。
第 10,11,12,13 章所讲 Java 图形界面相关,当今这方面几乎很少使用,选择忽略。
由于并不是 Java 新手,所以我将选择对我有益的知识点进行记录。
第三章 Java 的基本程序设计结构
长整型
long a = 3.14L 这里注意要用大写的 L 作为后缀,因为小写 l 有时很像数字 1
浮点型
单精度类型表示:float a = 3.14F 或 3.14f
双精度类型的表示:double b = 3.14D 或 3.14d
注意:当浮点型数字没有后缀时(如:3.14),默认为 double 类型。另外浮点数值不适用于无法接受舍入误差的金融计算中,如 2.0 – 1.1 结果是 0.89999999999999,为更精确的计算,可以使用 BigDecimal 类。
有三个特殊的浮点型数值:
正无穷大
负无穷大
NaN(不是一个数字)
正整数除以 0 的结果正无穷大 (如:3/0.0 结果为 Infinity),Infinity 表示无穷大的概念,0.0 并不是真正意义上的 0,它只是非常接近 0 而已。,0/ 0 或者负数的平方根结果为 NaN.(如:0.0/0.0,Math.sqrt(-3) 结果为 NaN ),对于所有没有良好的数字定义的浮点计算,例如 0.0/0.0,或者对负数求平方根其值都是它.
结合赋值和运算符
x = x + 4 简写:x += 4
注意:如果运算符得到一个值,其类型与左侧操作数类型不同,,就会发生强制类型转换,如 int x = 2 ; x += 3.14 ; 这相当于 x =(int)(x + 3.14)
自增自减运算符
java 中借鉴了 C 和 C ++ 的做法,提供了自增自减运算符:n + + 将当前值加 1
这种运算符有两种形式:运算符作为前缀和运算符作为后缀。例:
int m = 7 ;
int n = 7 ;
int a = 2 * ++m; //a=16,m=8
int b = 2 * n++; //b=14,n=8
前缀形式先完成加 1,后缀形式会使用原来的值,再加 1。
不建议在表达式中使用 ++, 因为这样的代码很容易让人困惑,而且会带来烦人的 bug。
&& 和 & 与 || 和 |
&& 表示逻辑“与”,|| 表示逻辑“或”。
这两个运算符是按照“短路”方式来求值的:如果第一个操作数已经能够确定表达式的值,第二个操作数就不会计算了。如:
exp1 && exp2 , 当 exp1 为 flase 时,那么 exp2 就不会执行了。
exp1 || exp2 , 当 exp1 为 true 时,那么 exp2 就不会执行了。
& 和 | 运算符不采用“短路”方式求值,所以不论第一个操作数是否确定整个表达式的值,两个操作数都会被计算。
字符串
检测是否相等
一定要用 equals()函数,它是判断两个字符串内容是否相等,而 == 是判断两个字符串是否在同一个位置上。如果 == 相等,那么 equals 一定相等,反之不然。
空串和 Null
“” 是一个 Java 对象,有自己的串长度(0)和内容(空),当为 Null 时,表示目前没有任何对象与该变量关联。
检查一个字符串既不是 null 也不是空串:
if(str != null && str.length() != 0)
要先检查不为 null,因为为 null 时无法调用 length()函数。
多重选择:switch
switch(x){
case x1 :
***
break;
case x2 :
***
break;
}
其中 x 可以为 char,byte,short,int 类型,到 Java SE 7 开始,可以是 String 类型的。
一般不建议使用 switch 语句,因为 break 语句的忘记容易导致问题。
命令行参数
学习 Java 你一定知道下面代码:
public class Massage{
public static void main(String[] args){
System.out.println(args[0]);
System.out.println(args[1]);
}
}
当你在命令行变异运行这个类时:java Massage -hello world
打印结果:
hello
world
第四章 对象与类
类之间的关系
依赖(uses-a)A 类方法操纵 B 类对象,叫做一个类依赖另一个类。
聚合(has-a)A 类的对象包含 B 类的对象。
继承(is-a)A 类继承 B 类。
我们应该尽量减少相互依赖的类存在,如果 A 类不知道 B 类,就不会关系 B 类的变化,这样 B 类无论怎么变化都不会导致 A 的 bug,软件工程上叫做:让类之间的耦合度最小。
Java 8 中新增 LocalDate 类
Date 是一个用来表示时间点的 Date 类,LocalDate 用来表示大家熟悉的日历表示法。
Date 类所提供的日期处理并没有太大的用途。1.Date 和 SimpleDateFormatter 都不是线程安全的。2.Date 对日期的计算方式繁琐,月份从 0 开始。
创建一个对象可以通过以下几个方式:
LocalDate local1 = LocalDate.now();
LocalDate local2 = LocalDate.of(2017,10,30);
LocalDate 并不包含时间,你可以通过下面获取年月日:
int year = local2.getYear();
int month = local2.getMonthValue();
int day = local2.getDayOfMonth();
当然 LocalDate 也提供了日期的增减:
local2.pulsDays(100);
local2.minusDays(100);
更多方法查看 API,这里不做详细表述。
final 实例域
将实例域定义为 final,构建对象时必须初始化这个实例域,后面的操作中不能够再对它进行修改。如:
public class Employee{
private final String name;
……
}
这个 name 属性没有 setName 方法。final 修饰符大都应用于基本数据类型或不可变的类或对象。如果类中每个方法都不会改变其对象,那么这个类就是不可变类,如 String 类。
对于可变的类使用 final 修饰,会对别人造成混乱。如:
private final StringBuilder sb;
在 Employee 构造方法中进行初始化
public Employee(){
sb = new StringBuilder();
}
final 关键词只是表示存储在 sb 变量中的对象应用不会再指向其他 StringBuilder 对象,不过这个对象可以更改:
public void giveGoldStar(){
sb.append(LocalDate.now() + “: Gold star!”);
}
静态域 static
public class Employee{
private static int sid = 1001;
private int id ;
……
}
static 修饰的常量,是面向类的,即无论存在多少 Employee 对象,sid 只存在一个,所有对象将共享一个 sid,但 id 却和对象同存在,多少个对象就有多少个 id。(static 修饰后,它属于类,而不属于任何对象)
静态工厂方法
类似 LocalDate.now 和 LocalDate.of 都是使用静态工厂方法来构造对象。
NumberFormat currenyFormatter = NumberFormat.getCurrencyInstance();
NumberFormat percentFormatter = NumberFormat.getPercentInstance();
double x = 0.1;
System.out.println(currenyFormatter.format(x)); // 输出 $0.10
System.out.println(percentFormatter.format(x)); // 输出 10%
为什么不利用构造方法来完成这些操作呢?原因:
无法命名构造器,这里希望得到的货币实例和百分比实例采用不同的名字。
当使用构造器时,无法改变所构造的对象类型,而 Factory 方法将返回一个 DecimalFormat 类对象,这是 NumberFormat 的子类。
方法参数
方法参数共有两种类型:
基本数据类型
对象类型
一个方法不可能修改一个基本数据类型的参数,如:
double x = 10;
harry.raiseSalary(x);
中不论加薪方法具体怎么实现,但 x 值始终不变。
对象作为参数其实是对象引用的拷贝,他们指向同一个对象。
public void swap(Employee x,Employee y){
Employee temp = x;
x = y;
y = temp;
}
Employee a = new Employee(“zhang”);
Employee b = new Employee(“wang”);
swap(a,b); // 现在 x 指向 wang,y 指向 zhang
System.out.println(a.toString()+”–“+b.toString());
最后你会发现 a 依然是 zhang,b 依然是 wang, 因为形参 x,y 在执行完后被丢弃了,原来的 a,b 依然指向之前的的对象。
总结:
java 对对象采用的不是引用调用,实际上,对象引用是按值传递的。
一个方法不能修改一个基本数据类型(数值型和布尔型)
一个方法可以改变一个对象的状态(属性……)
一个方法不能让一个对象参数引用新的对象
无參构造函数
当一个类没有提供构造函数时,系统会为这个类提供一个默认的无參构造函数,但当你提供了有参的构造函数时,系统是不会提供无參构造函数的,所以当你要调用无參构造函数时,主动提供无參构造函数或不提供任何构造函数。
类设计技巧
一定保证数据的私有性
一定对数据初始化
不要在类中使用过多的基本类型
将职责过多的类进行分解
类名和方法名要能体现他们的职责
优先使用不可变类
类不可变,就可以安全地在多个线程间共享其对象。
第五章 继承
父类和子类
将通用方法放在父类中,而将具有特殊用途的方法放在子类中。
关键字 this 的两种用法:一是引用本类成员变量,二是调用本类其他构造函数。
关键字 super 两种用法:一是应用父类成员变量,二是调用父类构造函数。不过两者调用构造函数时,调用语句必须放在构造函数第一行。