第一章 Java程序设计概述
太简单了,直接略过。
1.2 Java“白皮书”的关键术语
- 简单性:指相对于C++简单(指针、多重继承等),但设计者也并没有试图清楚C++中所有不适当的特性
- 面向对象:java与C++主要不同在于多重集成,以及接口概念
- 网络技能
- 健壮性
- 安全性
- 体系结构中立
- 可移植性
- 解释性:过去Java解释器可以在任何移植了解释器的机器上执行java字节码,现在使用即使编译器将字节码再翻译成机器码
- 高性能
- 多线程
- 动态性
第二章 Java程序设计环境
我选择使用了JetBrainde IDEA社区版,直接忽略
第三章 Java的基本程序设计结构
3.3 数据类型
主要关心的是boolean类型,包含false和true,与C++是同一个类型的
3.4 变量
合法特殊字符为任何代表字母的Unicode字符,但是不能出现+
(操作符)和copyright(除字母外的其他Unicode字符)。其中$
尽量不要在自己的代码中使用,一般出现在Java编译器或者其他工具生成的名字中。
需要显示初始化变量,与C++一致。
在java中,使用final
指示常量,如final double CM_PER_INC=2.54
。final表示该变量只能赋值一次,一旦赋值就不能修改,习惯上常量名使用大写。
类常量可以使用static final
进行设定,在某个类内部定义
public class test{
public static final double CM_PER_INC=2.54;
}
3.5 运算符
求余符号为%
3.5.6 强制类型转换
double x = 9,997;
int nx = (int) x;
3.6 字符串
任何语言的字符串都是值得重视的。
java使用类型String
定义字符串
String greeting = "Hello";
String s = greeting.substring(0,3);//Hel 前闭后开区间,对于substring(a,b),子串长度为b-a
String t = "123"+"456";//123456
3.6.3 不可变字符串
String类不能直接修改字符串,只能够使用子串+拼接的方式进行间接修改。
原理是编译器让所有的字符串共享,可以想象字符串被放在公用的存储池中,赋值字符串后,新字符串与原字符串指向相同的对象。
3.6.4 检测字符串是否相等
可以使用s.equals(t)
检测是否相等,但不能使用==
,后者只能确定两个字符串是否放在同一个位置上,这点C++应该也是一样的。
3.6.5
可以调用string.length()
返回长度
可以调用string.charAt(index)
返回指定位置的char类型变量。
3.6.7 字符串API
……不用想着背了,肯定是用到的时候再查的。
3.7 输入输出
IO也是很重要的
标准输出流:System.out.println
标准输入流:
import java.util.*;//Scanner类定义在java.util包中
Scanner in = new Scanner(System.in);//Scanner绑定标准输入流
String nextline = in.nextLine();//读取下一行
String nextword = in.next();//读取下一个单词
int age = in.nextInt();//读取整数
格式化输出:System.out.printf("%8.2f",x);
,同样,与C++类似
3.7.3 文件输入输出
也是一般最常用的
Scanner in = new Scanner(Paths.get("myfile.txt"));//读取文件
PrintWriter out = new PrintWriter("myfile.txt");//写文件
相对路径为启动环境的根目录。使用集成开发环境时,路径地址可以使用String dir = System.getProperty("user.dir");
获得
3.8 控制流程
3.8.1 块作用域
block,指花括号括起来的若干条简单java语句
java支持带标签的break来跳出多重循环,标签必须放在希望跳出的最外层循环之前,加上引号
read_data:
while(...){
for(...){
break read_data;//直接跳到指定循环之外
}
}
3.9 大数值
java.math中的BigInteger和BigDecimal,可以处理任意长度数字序列的树枝。前者为任意精度整数运算,后者为任意精度浮点数运算。可以使用valueOf方法将普通数值转换为大数值。
3.10 数组
int[] a = new int[100]
,声明数组
匿名数组smallPrimes = new int[]{1,2,3,4,5}
,可以在不创建新变量的情况下重新初始化一个数组
数组拷贝int[] luckyNumbers = smallPrimes;
为引用,想要拷贝数值应该使用Arrays.copyOf
方法(可以使用该方法来增加数组长度)
数组排序Arrays.sort(arr)
3.10.7 不规则数组
double[][] balances = new double[YEARS][RATES]
Java本质上没有多维数组,只有一维数组。因此,二维数组的每一行可以拥有不同的长度
int[][] odds = new int[NMAX+1][]
for(int n=0;n<=NMAX;n++){
odds[n] = new int[n+1];
}
第4章 对象与类
类之间的关系:
- 依赖"use a"。如果一个类的方法操纵另一个类,就说一个类依赖于另一个类。应该尽可能降低互相依赖的类的数量
- 聚合"has a"。一个类的对象包含另一个类,即为聚合
- 继承"is a"。
空对象null
4.2.3 更改器方法与访问器方法
GregorianCalendar now = new GregorianCalendar();
int month = now.get(Calendasr.MONTH);//访问器
deadline.set(Calendar.YEAR,2001);//更改器
对实例域作出修改的访问成为更改器方法,仅访问实例域的方法称为访问器方法。
4.3 用户自定类
类方法构成
public String getName()
其中public表示访问控制,String表示返回值,函数名内部为形参表
4.3.2 多个源文件的使用
java编译器可以认为内置了make功能,就算使用java XXX.java
命令没有显示编译其他的java文件,它也会查找其他的java文件。
4.3.3 剖析
一般建议实例域采用private来维持封装
4.3.4 构造器
C++中的构造函数,没有看到有什么不同的
PS:Java中的所有对象都是在堆中构造的,容易遗漏new
操作符
PPS:不要在构造器中定义与实例域重名的局部变量,会重复。
4.3.5 隐式参数
即对于类方法
public void raiseSalary(double byPercent){
double raise = salary*byPercent/10;
salary += raise;
//一般推荐this.salary += raise;,这样可以显式区分局部变量和实例域
}
java中可以选择显示调用this指针,也可以不调用。这里类方法中的第一个参数为隐式参数,即类自己。该类方法的副作用就是salary会一起改变。
方法可以访问所有类的私有域(与C++类似,抱歉我C++学的不好)
class Employee{
private String name;
public boolean equals(Employee other){
return name.equals(other.name);
}
}
4.4 静态域
对象中的变量一般是跟着对象走的,但是static的变量可以看作独立于具体对象之外。这样,对于所有的对象,它们共享同样的静态域。
4.4.3 静态方法
静态方法是一种不能向对象实施操作的方法,可以认为静态方法没有this参数。
可以使用静态方法来实现工厂函数。
4.5 方法参数
一般来说,存在按值调用和按引用调用。Java总是默认采用按值调用,但是需要注意,=
赋值号一般总是直接复制对象的地址,除非使用clone
这也就是说,方法得到的是所有参数值的一个拷贝。但是如果参数是自定类的话,则拷贝的内容为类的地址,因此可以认为是引用传值。
4.6 对象构造
4.6.1 重载
即构造函数重载,相同的构造函数可以使用相同的名字、不同的参数。
4.6.6 调用另一个构造器
关键字this引用方法的隐式参数
public Employee(double s){
//call Employee(String,double)
this("Employee #"+nextId,s);
nextid++;
}
这样对于公共的构造器代码,只用编写一次即可。
4.6.8 对象析构
为类添加finalize方法,将在垃圾回收器清除对象之前调用。
PS:在实际应用中不要依赖finalize方法,因为实际很难知道具体什么时间会调用这个函数
4.7 包
Java允许使用包将类组织起来,有点类似C++中的namespace
4.7.1 类的导入
导入的方式,一种是输入全名java.util.Date today = new java.util.Date();
也可以使用import java.util.*;
导入全部类,这样就不用写入全名了。
另外,*
只能导入一个包,不能使用java.*
的方式导入所有包。
4.7.2 静态导入
import static java.lang.System.*
可以导入静态方法和静态域。
4.7.3 将类放入包中
想要将类放入包中,就必须将包的名字放在源文件的开头,可以必须写全名,例如
package com.horstmann.corejava;
,而不能只是package corejava
同时,包中的文件需要被放置在与完整的包名匹配的子目录中,例如上面的包应该被放在com/horstmann/corejava
下。
4.7.4 包作用域
对于private定义的类,只有同一个包能够访问。而public类则是导入包即可见。
4.8 类路径
主要是使用JAR文件。一般将JAR文件放在一个目录中,然后设置类路径classpath(一般是java -classpath/-cp XXX
),就可以读取。在UNIX环境中,类路径的不同项目之间采用冒号分割。也可以设置环境变量CLASSPATH
4.9 文档注释
JDK的工具,javadoc,可以由源文件生成一个HTML文档。
有点类似python的doc,不过是放在定义的前面而不是后面,并且对于/**
开头的注释来说,每一行的开头都要有*
方法注释还可以使用以下的标记:
@param
变量描述@return
返回描述@throws
类描述
通用注释:
@author
姓名@version
版本文本@since
对引入特性的版本描述
执行命令javadoc -d docDirectory nameOfPackage
,即可生成docDirectory
下的指定包的HTML文件。
4.10 类设计技巧
- 一定要保证数据私有,绝对不要破坏封装。我觉得在这里主要是因为JAVA的语言特性,对象默认传递地址使得一旦发生修改,查找起来会非常痛苦。
- 一定要对数据初始化
- 不要在类中使用过多的基本类型(便于理解)
- 不是所有的域都需要独立的域访问器和域更改器。
- 将职责过多的类进行分解
- 类名和方法名要能体现它们的职责。(PS:个人观点,不要出现magic number)
第5章 继承
5.1 类、超类和子类
可以使用关键词extends
表示继承,且JAVA中只有公有继承,没有C++中的私有继承和保护继承
一些显然但容易忘的事实:子类方法并不能直接访问超类的私有域,必须借助于公有接口。如果需要调用超类的同名方法,应该使用特定关键字super
同时,super可以在构造器中使用,比如
public Manager(String test){
super(test);
}
super与this指针具