由于时间原因,不能像讲课一样给大家一一列出所有的要点,故在此篇博客中,仅记录一些个人之前忽略的点和常见易错点,将不展开全面介绍,各位读者可以当做闲暇阅读,查漏补缺。
public static final DataType varName;
final
表示该变量只能赋值一次,一旦赋值便不可修改。习惯上,常量名使用全大写+下划线。java.lang.ArithmeticException: / by zero
异常;浮点除零会产生无穷大或NaN结果。strictfp
关键字标记该方法。 常用的数学函数都包含在Math
类中,可以直接调用。
Math.sqrt(x)
求平方根;Math.pow(x,a)
求xa;Math.floorMod(x, y)
求非负余数等。Math.PI
和Math.E
。注意:
当有类型转换不会造成数据溢出(Java允许丢失精度)时,或使用结合赋值运算符时,Java会根据计算需要自动进行类型转换。
当类型转换可能造成数据溢出从而损坏数据时(结合赋值运算符除外),Java不会自动进行类型转换。这时,就需要用小括号进行强制类型转换,强制类型转换会直接截断,不会进行舍入运算,而且如果超过目标类型的表示范围,就可能产生一个完全不同的值。 可以调用Math.round(x)产生一个四舍五入的long类型的值。
注意:
b? 1 : 0
。注意:
x += 3.5;
是合法的,这等价于x = (int) (x + 3.5);
。注意:
if(obj != null && obj.xxx);
。?:
。处理整型类型时,可以直接进行位操作。位运算符包括:
利用掩码技术可以得到整数中的各个位。例如:int forthBitFromRight = (n & 0b1000) / 0b1000
或int forthBitFromRight = (n & (1<<3)) >> 3
。利用&并结合使用2的适当的幂,可以将其他位“掩盖掉”,从而只保留某一位。
注意:
&
和|
应用在boolean上时,也会得到一个boolean值,但是不会采用短路的方式,左右的表达式都需要计算。()
运算符,
运算符。不过可以在for语句的第1部分和第3部分使用逗号分隔表达式列表。 Java中,字符串的本质就是一串Unicode序列。Java没有内置的字符串基本类型,而是在Java类库中提供了一个预定义类java.lang.String
String对象可以调用其substring(beginIndex, endIndex)
方法获得子串(起始下标为0)。
注意:
+
拼接字符串。当一个字符串与非字符串拼接时,后者将被转换成字符串。String.join("/", “s”, “m”, “l”, “xl”)
方法。相比C/C++可以修改单个字符而言,String类没有提供用于修改字符串的方法。 由于不能修改Java字符串中的字符,所以Java文档中将String类对象称为“不可变字符串”。如果需要修改某个字符串变量,通常直接让它引用另一个字符串。
虽然重新建立一个字符串的效率并不高,但是不可变字符串带来一个优点:编译器可以让字符串共享。Java中有一个字符串池,每个字符串变量分别指向存储池中相应的位置。如果复制一个字符串变量,原始字符串与复制的字符串可以共享相同的字符串,而不必担心字符串被莫名其妙修改的问题。
Java设计者认为共享带来的高效远远胜于提取、拼接字符串带来的低效。因为更多时候我们做的不是修改而是比较。(有一种例外情况,将来自输入流的单个字符或较短的字符串拼接成长串,不过为此有专门的类StringBuilder
来负责)
此外,不必担心过多的字符串导致堆内存遗漏,Java有GC机制。
可以使用equals
方法检测两个字符串(变量或字面量)是否相等。(如果忽略大小写可以使用equalsIgnoreCase
方法)。
注意: 一定不要使用 == 检查两个字符串是否相等!这只能判断两个字符串是否放在同一内存位置上。虽然放在同一位置上的字符串必然相等,但是完全有可能将内容相同的多个字符串拷贝防止在不同的位置上!“==”返回true或false与两个字符串相等与否并非等价。
如果虚拟机始终将所有相同的字符串共享,那么是可以使用==来判断的。但实际上只有字符串常量是共享的,而 + 或substring等操作产生的结果是不共享的。 C++中的string类重载了==运算符,以便检测字符串内容的相等性。C语言中则通常使用strcmp()方法。这类似于Java中的compareTo()方法,但是Java中的compareTo()通常用于比较字典序,判断String相等还是使用equals()最为清晰。
注意,如果要检查一个String既不是null也不是空串,要先判断是否为null,再调用它身上的方法判断是否为空串。
Java字符串由char值序列组成。char类型是一个采用UTF-16编码表示的Unicode码点的代码单元。大多数Unicode使用一个代码单元,某些特殊符号则需要两个。
str.length()
返回代码单元数量;str.codePointCount(0, str.length())
返回码点数量。char ch = str.charAt(index);
返回对应的char(太底层,不建议使用,可能返回一个无意义的代码单元);int cp = str.codePointAt(index);
返回Unicode码点值。int index = str.offsetByCodePoints(0, i);
,即从下标0开始,向后偏移i个码点对应码点的下标。int[] codePoints = str.codePoints().toArray()
方法,得到一个int[]数组;反之使用new String(codePoints, 0, codePoints.length)
得到原来的字符串。StringBuilder(JDK 5引入)和StringBuffer的区别:
new Scanner(System.in);
,直接调用它的next()、nextLine()、nextInt()、nextDouble()等方法,这个Scanner便会帮我们处理这些琐碎无聊且易错的事情。 幸运的是,Java沿用了C/C++的标准输入输出printf(),在Java中是System.out.printf()方法。转换符、格式控制符基本沿用了C/C++的风格。
此外Java还给出了很多扩展功能的printf()标志,以及用于Date类对象的日期和时间的转换符。
可以使用静态的String.format(String… args)
方法创建一个格式化的字符串。
java.nio.charset.Charset
,使得在跨平台时,兼容性和可控性会更好。read_data:
while(...) {
for(...;...;...) {
......
break read_data;
......
}
}
if(...) {
} else {
}
如果基本的整数和浮点数运算无法满足精度需要,则可以使用BigInteger和BigDecimal类,它们分别实现了任意长度的整数运算和任意精度的浮点运算。
注意: 与C++不同,Java没有重载运算符的功能。虽然Java设计者为String重载了 + 运算符,但没有重载其他运算符,也不支持程序员重载运算符。
数组是一种顺序存储的数据结构。优点在于支持随机访问,缺点在于增删元素的时间复杂度较高。
有关数组初始化问题:
有关数组长度问题:
public final int length
属性可以获得数组的长度,一旦访问越界则会抛出异常。 Java有一种简洁不易错且功能很强的循环结构:for (variable : collection) statement
,这样我们就无需担心集合长度以及下标问题辣~~~
注意:
Arrays.toString()
方法。它会调用数组中每个对象的toString方法(基本数据类型是直接转换成字符串),然后加一个方括号,每个元素用逗号分隔,将集合中的元素全部打印出来。new int[N]
或new int[] {1, 2, 3}
,其优点在于不创建新变量的情况下创建一个数组对象。注意:Java中,允许数组的长度为零。长度为零的数组与null不同,是占用空间的。
Arrays.copyOf(arr, arr.length)
方法,这将返回拷贝后新数组的引用。长度小于原数组则截断,大于原数组则补0/false。int arr[100];
是保存在栈内存中(随着代码块结束自动回收);int* a = new int[100];
才是保存在堆中(且需要手动delete)。 在Java中,main方法固定带有一个字符数组String[] args
作为参数。
当在命令行键入如下字符串并会车时,会调用Message类的main入口方法,并将"-g"、“cruel”、"world"作为参数传入String[] args
中,并可以在程序中使用。
java Message -g cruel world
可以直接调用Arrays.sort()方法,进行优化的快速排序,快排对于大多数数据集合来说效率还是比较高的。 程序清单3-7给出一个非常巧妙的不重复抽签办法。每次只随机产生下标,然后找出该元素后,用最后一个元素覆盖之,然后n–,使得下一次抽签的范围变成0 ~ (n-1),然后不断迭代这一过程即可。
Java中,N维数组的定义和初始化大体与之前的一维数组类似,只不过多了几个维度。 注意:
for(double[] row : arr)
for(double value : row)
do something with value......
System.out.println(Arrays.deepToString(arr));
Java的多维数组与C/C++在使用上大同小异,但是在存储结构上存在着很大差别,这正是Java的优势所在。 C/C++中,多维数组中的所有数据通常也是连续摆放在内存的一片区域中的,而Java中的数组更像是“数组的数组”,例如二维数组a引用的内存中,其实保存的是row个一位数组的引用。
这样带来的好处是: 第一,我们可以很轻易的将两行进行交换:
double[] tmp = balances[i];
balances[i] = balances[j];
balances[j] = tmp;
第二,我们可以创建一个每行长度不等的不规则数组(例如对角矩阵):
int[][] odds = new int[rowCount][]; // odds数组中均为null
// 依次为每一行创建一个新数组
for(int i = 0; i < rowCount; ++i) {
odds[i] = new int[i+1];
}
注意:
double[][] balances = new double[10][6];
等价于double **balances = new double*[10];
,然后为指针数组中的每个元素申请堆中的空间:for(int i = 0; i < 10; ++i) {
balances[i] = new double[6];
}
庆幸的是在Java中会自动进行这样的空间开辟,除非建立的是不规则数组。
小博同学,2020年7月8日凌晨00:32,于小破邮。