前言:本文是在看《java语言程序设计》(英文版) (Y.Daniel Liang著 ISBN 978-7-111-36122-0)时自己记下的笔记,由于水平有限,翻译有不当之处。
Chapter1 Introduction to Computers, Programs, and Java
Chapter2 Elementary Programming
java是大小写敏感的。
当+号是作连接字符串操作时,如果有一个操作数不是字符串时,该操作数会被自动转换成字符串再继续执行连接操作。
字符串连接不能跨行,如下表达是错误的:
System.out.println(“java
note”);
应该表达如下:
System.out.println(“java” +
“note”);
java没有直接支持从控制台输入数据,但是可以使用Scanner类来创建一个对象,从System.in中读取数据,如下所示:
Scanner input = new Scanner(System.in);
一个Scanner对象可以调用它的方法来读入数据,常用的读入数据的方法有:
nextByte()
nextShort()
nextInt()
nextLong()
nextFloat()
nextDouble()
next() //读入一个字符串,以空格键作为结束
netxtLine() //读入一个字符串,以回车键作为结束
从控制台读入数据的一个例子:
Scanner input = new Scanner(System.in);
double radius = input.nextDouble();
标识符可以以$开头,但是标识符中不会使用$字符,因为按照惯例,$字符仅仅用在机械生成的源代码。
按照惯例,常量命名时字母全为大写。
原子数据类型:
byte 8位
short 16位
int 32位
long 6 4位
float 32位
double 64位
一般地,我们使用double类型来定义浮点数,因为double比float更精确。
java编译是对溢出不会有警告或错误的提示,所以对变量的值域一定要小心。
当两个整数相除时结果的小数部分会被忽略,如5/2 =2,如果要保留小数部分,则除数或被除数最少有一个是浮点数,如5.0/2 = 2.5。
要表示八进制常数时,八进制数前边加一个0(zero),如011 = 9
要表示十六进制常数时,十六进制数前边加上前缀0x(zero x),如0xffff = 65535
默认浮点常数是double类型,如果要指定为float型可以在常数后边加f或F,如1.0f,如果要指定为double类型可以在常数后边加d或D,如1.0d。
科学记数法:
1.23456e+2 = 1.23456e2 = 1.23456 X 102
1.23456e-2 = 1.23456 X 10-2
(E或e都可以)
可以用System类中的currentTimeMillis方法获取当前时间,该时间是代表由1970年1月1日00:00(EST美国东部标准时间)开始到当前的总毫秒数,要获取当前时分秒可按以下方法计算:
当前的总毫秒数/1000 = 当前的总秒数
当前的总秒数%60 = 当前的秒
当前的总秒数/60 = 当前的总分钟数
当前的总分钟数%60 = 当前的分
当前的总分钟数/60 = 当前的总小时数
当前的总小时数%60 = 当前的时
运算时扩大一个变量的类型会自动地执行,但缩小一个变量的类型必须显式的指明。
+= 之类的连写操作符中间不能有空格,如+ = (+和=中间有一个空格)是错误的。
强制类型转换只是临时的,不会真正的改变该变量的类型。
Math类中的pow(a,b)方法可以用来计算ab。
为了避免错误,nextLine()不能使用在nextByte(), nextShort(), nextInt(), nextLong(), nextFloat(), nextDouble()和next()之后。
命名习惯:
1、变量和方法习惯用小写字母命名,如果有多个单词,把多个单词连接起来,除了第一个单词以外,每个单词的首字母用大写,如showInputDialog。
2、类习惯用大写字母做开头,多个单词时和变量和方法的命名一样,但保持首字母是大写。如JOptionPane。
3、常量习惯用全大写字母命名,如有多个单词,用下划线”_”连接,如MAX_VALUE。
4、命名时单词用全写比用缩写好,如numberOfStudents比numStuds, numOfStuds, 或者numOfStudents都要好。
Integer类中的parseInt方法可以把数字字符串转换为整型数字。
Double类中的parseDouble方法可以把数字字符串转换为浮点型数字。
Chapter3 Selections
设flag是boolean类型,判断条件使用if(flag)比if(flag == true)要好,因为书写flag == true时有可能漏写一个等于号而导致错误。
使用Math类中的random方法可以获取一个0.0<= d <= 1的随机数。
1 <= number <= 3 的表达方式是错的,因为虽然运算1 <= number 是正确的,但该操作得到的是boolean类型的结果,boolean类型与3作<=比较操作将会出错。所以应该写作 (number >= 1) && (number <= 3)。
boolean类型不能强制转换为其他任何的类型。
格式化输出printf
%b a boolean value
%c a character
%d a integer
%f a floating-point number
%e a number in standard scientific notation
%s a string
%5d 能指定输出的位数为5位,不够5位的在左边用空格补齐,超过5位的长度会自动增加;
%10.2f 能指定整数部分为10位,小数部分为2位,同样不够长度的会用空格补齐,超过的自动增加长度;
%后加数字格式化输出默认是右对齐的,如果添加负号”-“,如 %-5d 则默认是左对齐,如果不够5位会在右边添加空格。
要输出%号要写成%%。
Chapter4 Loops
Chapter5 Methods
我们说的定义(define)和声明(declare)是有一点小区别的,定义(define)通常是指定义一个项目,而声明则包括为声明的变量分配内存去存储数据,所以我们会说“定义一个方法(define a method)”和“声明一个变量(declare a variable)”。
对于一个值返回方法,return语句是必须的,要小心下面的错误:
public static int sign(int n) {
if(n > 0) {
return 1;
}
else if(n == 0) {
return 0;
}
else if(n < 0) { //编译器会认为如果都不符合条件(即使我们知道这里至少有return -1; //一个条件成立),则没有return语句,所以编译错误
}
}
应改为如下:
public static int sign(int n) {
if(n >0)
return 1;
else if (n == 0) P
return 0;
else
return -1;
}
重载(overloading)
重载:两个相同名字的方法通过不同的参数列表去区别。
重载必须是参数列表不同,仅仅是返回值类型不同不能构成重载。
参数列表也是局部变量。
在for循环开头括号内定义的变量有效范围仅在循环体内。
嵌套关系内不能定义同名的变量。
如下代码是正确的:
public static void method1() {
int x = 1;
int y = 1;
for(int i=1; i<10; i++) {
x+=i;
}
for(int i=1; i<10; i++) {
y +=i;
}
}
如下代码是错误的:
public static void method2() {
int i = 1;
int sum = 0;
for(int i=1; i<10; i++) { // 这里i重复定义了
sum += i;
}
}
Chapter6 Single-Dimensional Arrays
声明一个数组变量
elementType[] arrayRefVar;
如 double[] myList;
也可以沿用C的格式如下:
elementType arrayRefVar[] 但是在java中更习惯用前一种格式
不像声明一个原始数据类型的变量,声明一个数组变量不会分配内存空间,声明的数组变量仅仅是一个引用,如果该数组变量没有引用一个数组,它的初始值是null。如果要分配内存空间,则要使用new关键字,格式如下:
arrayRefVar = new element Type[arraySize];
也可以声明与分配放在同一条语句中,如
elementType[] arrayRefVar = new elementType[arraySize];
或者 elementType arrayRefVar = new elementType[arraySize]; //该格式不常用
虽然准确的说声明的数组变量应该叫数组引用,而new elementType[arraySize]分配的内存空间叫数组,但一般地为了简化我们都直接称声明的数组变量为数组。
可以用arrayRefVar.length 获取数组长度。
当一个数组被创建时,他们的默认值分别是:数字类型的为0,字符类型的为’\u0000’,布尔型的为false。
数组初始化的格式如下:
elementType[] arrayRefVar = { value0, value1, ……, valuek};
如:double[] myList = {1.9, 2.9, 3.5, 3.5}; //没有new关键字
这个写法等同于:
double[] myList = new double[4];
myList[0] = 1.9;
myList[1] = 2.9;
myList[2] = 3.4;
myList[3] = 3.5;
如果使用数组初始化必须把声明、创建和初始化数组写在同一个语句中,如下边的编写使错误的:
double[] myList;
myList = {1.9, 2.9, 3.4, 3.5};
对于字符数组,可以使用一条打印语句将其输出,如:
char[] city = {‘D’, ‘a’, ‘l’, ‘l’, ‘a’, ‘s’};
System.out.println(city);
For-each 循环
java提供一种简便的for循环,格式如下
for(elementType element: arrayRefVar) {
//Process the element
}
例如要显示myList数组中的所有元素可以写作如下:
for(double u: myList) {
System.out.println(u);
}
可以理解为“对每一个在myList数组中的元素u执行System.out.println(u)操作”,要注意u的类型必须与myList数组中的元素的类型相同。
可以使用java.lang.System类中的 arraycopy方法复制数组的元素,该方法的参数如下:
System.arraycopy(sourceArray, src_pos, targetArray, tar_pos, length);
如把数组A复制至数组B:
System.arraycopy(A, 0, B, 0, A.length);
数字0表示开始复制的数组下标。
要注意arraycopy方法并不会给targetArray分配空间,所以必须确保复制前targetArray已分配空间。
(arraycopy不符合java命名规则,规范的应该是arrayCopy)。
匿名数组
new elementType[]{value0, value1, …, valuek};
这样创建出来的临时数组成为匿名数组,没有引用指向该数组,所以只能一次性使用。
数组传参
原始数据的传参是值传递,在方法中只会改变形参,不改变实参;
但是数组传递的是引用,也就是说方法中对形参数组的修改,也会导致实参数组改变,因为其修改的是同一个内存地址。
JVM把数组存放于堆(heap)内存中,堆内存使用动态内存分配技术按随意的顺序分配和释放内存。
有如下代码
public class Test {
publicstaticvoidmain(String[] args) {
int x = 1;
int [] y = new int [10];
m(x, y);
System.out.println(“x is” + x);
System.out.println(“y[0] is “ + y[0]);
}
public static void m (int number, int [] numbers) {
number = 1001;
number[0] = 5555;
}
}
运行结果为
x is 1
y[0] is 5555
代码的内存分配图如下
我们可以把相同数据类型的变量作为数组参数方便地传入方法中,方法的参数声明如下
typeName…parameterName。
例:
public class VarArgsDemo {
public static void main(String[] args) {
printMax(34, 3, 3, 2, 56.5); //printMax方法会把多个参数看作一个数组
printfMax(new double[] {1, 2, 3});
}
public static void printMax (double…numbers) {
if(numbers.length == 0) {
System.out.println(“No argument passed”) ;
return ;
}
double result = numbers[0];
for(int i=1; i< numbers.length; i++) {
if(numbers[i] > result)
result = numbers[i];
}
System.out.println(“The max value is” + result);
}
}
java.util.Arrays类中包含多种静态的方法供数组的排序、查找、比较和填充。这些方法被各个原始数据类型重载。
可以使用sort方法对整个或部分的数组进行排序。如
double[] numbers = {6.0, 4.4, 1.9, 2.9, 3.4, 3.5};
java.util.Arrays.sort(numbers); //对整个数组排序
char[] chars = {‘a’, ‘A’, ‘4’, ‘F’, ‘D’, ‘P’};
java.util.Arrays.sort(chars, 1, 3); //对char[1]到char[3-1]的数组部分进行排序。
可以使用equals方法检查两个数组是否相等,但是要注意元素的顺序也相同才相等,对于下边三个数组,list1与list2是相等的,但list1与list3不相等。
int[] list1 = {2, 4, 7, 10};
int[] list2 = {2, 4, 7, 10};
int[] list3 = {4, 2, 7, 10};
可以使用fill方法填充整个或部分数组,如
int[] list1 = {2, 4, 7, 10};
int[] list2 = {2, 4, 7, 10};
java.util.Arrays.fill(list1, 5); //对list1整个个数组填充5
java.util.Arrays. fill(list2, 1, 3, 8); //对list2[1]到list2[3-1]的部分填充8
Chapter7 Multidimensional Arrays
二维数组的声明格式
elementType[][] arrayRefVar;
或elementType arrayRefVar[][]; //允许,但不好
二维数组的声明并分配空间
elementType[][] arrayRefVar = new elementType[length][length];
如 int matrix = new int[5][5];
与一维数组一样,可以用数组初始化去声明、创建和初始化二维数组。
如:int[][] array = {
{1, 2, 3}, //不要遗漏后边的逗号
{4, 5, 6},
{7, 8, 9}
};
二维数组的每一行都是一个数组,所以每一行可以拥有不同的长度,如可以创建如下二维数组:
int [][] triangleArray = {
{1, 2, 3, 4, 5},
{2, 3, 4, 5},
{3, 4, 5},
{4, 5},
{5}
};
如果事先不知道值,也可以创建如下的二维数组:
int [] triangleArray = new int[5][];
triangleArray[0] = new int [5];
triangleArray[1] = new int [4];
triangleArray[2] = new int [3];
triangleArray[3] = new int [2];
triangleArray[4] = new int [1];
在new 二维数组时第一个指针必须指定,如new int[5][]中的5不能忽略,如果写成int[][]是错误的。