【编程语言】Java基础语法(与C比较学习)
花了不到一周的时间,简单且快速的过了一遍男神的课,做了一些笔记,现记录如下:
1. 编译语言vs解释语言
·语言本无编译/解释之分
·只是常用的执行方式而已
·解释型语言有特殊的计算能力
·编译型语言有确定的运算性能
+ 的字符串操作:可以连接两个字符串,或者将一切非字符串的东西转化成字符串之后与另一个字符串连接起来。
2. 常用语句
1 Scanner in = new Scanner(System.in); 2 int a = 0; 3 a = in.nextInt(); 4 System.out.println(a); // System.out.print(a + “\n”); 5 System.out.println(); // System.out.print(“\n”);
3. 变量与常量
在C中,常量可以有两种方式来表达:
1) 宏定义: #define CONSTANT 100
2) 定义常量并赋值: const int Constant = 100;
在Java中,常量的定义方式用final而非const:
final int Constant = 100;
4. 浮点数注意事项
在Java中浮点数无法精确表示运算结果:
1.2 – 1.1 → 0.09999999999999987
在C中则为:
1.2– 1.1 → 0.100000 // 因为%lf只表示小数点后六位,实际上也存在精度误差
因此,
1 double a = 1.0; 2 3 double b = 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1; 4 5 System.out.println(“a = ” + a); // a = 1.0 6 7 System.out.println(“b = ” + b); // b = 0.9999999999999999 8 9 System.out.println(1.0 == 1.0); // true, 同一表达式的比较当然相等 10 11 System.out.println(a == b); // false, 浮点数存在精度误差
若想进行浮点数比较,则应采取两浮点数差值的绝对值与非常小的数进行比较:
System.out.println(Math.abs(a - b) < 1e-6); // true, 表示两数相等
5. 关于布尔值
在C中,true的值为1,false的值为0。布尔值即视作整型值可与整数做逻辑运算与算术运算;
在Java中,true与false是单纯的布尔值,类型是布尔型boolean,不可与整数做任何运算。
因此,
在C中:
1 int a = 4; 2 3 printf (“%d\n”, a + true); // 5 4 5 printf (“%d\n”, a > true); // 1
而在Java中,上述写法则是异常的(exception)。
6. 数组
写法:
<类型>[] <数组名称> = new <类型>[数组长度·元素个数];
·元素个数必须是整数
·元素个数必须给出
·元素个数可以是变量 // C较早版本的标准不支持此项,从C99之后允许
如:
int[] a = new int[10];
数组特点:
·.length:每个数组有一个固有成员length,表明元素个数
因此写关于数组的for循环时,最好的写法是:
for ( int i = 0; i < array.length; i++ )
·用new创建的数组会默认初始化,初始值为0
·也可以直接在定义数组的时候初始化赋值:
int[] arrary = {1, 2, 3, };
7. 数组变量
在C中,数组变量之间无法进行赋值:
如
1 int a[5]; 2 3 int b[5]; 4 5 b = a;
这样的写法是错误的,因为在C中数组变量(数组名)是特殊的指针,其含义就是内存中一片连续区域(即数组)的首地址,两个首地址之间无法进行赋值;
而在Java中,没有指针的概念:
如
1 int[] a = new int[5]; 2 3 int[] b = a; // 类似于C中定义了一个指针变量b并为其赋值数组a的首地址 4 5 b[0] = 1; // b[0] 即为 a[0],所以本质上即为修改数组a 6 7 System.out.println(a[0]); // 因此a[0] == 1
若将Java中的变量类比成数据的“所有者”的话,那么数组变量更像是数据的“管理者”,而实际上数组内的数据保存在另外的地方。上述代码中的a与b都类似C中的指针,同时指向了一片连续的没有名字的区域,就好比两个管理者,同时管了一组柜子。
·数组变量是数组的管理者而非数组本身
·数组必须创建出来然后交给数组变量来管理
·数组变量之间的赋值是管理权限的赋予
·数组变量之间的比较是判断是否管理同一个数组
因此复制数组必须用遍历赋值的方式,判断两个数组的内容是否相同也需要遍历判断每个数组元素是否相等。
8. 遍历数组
用for循环遍历数组是最经典的写法:
1 for ( int i = 0; i < array.length; i++ ) { 2 3 array[i] … ; 4 5 }
在Java中,除了使用与C写法一样的for三段式循环来遍历数组之外,还有另一种更简洁的写法,for-each循环。
写法:
for (<类型><变量> : <数组>)
意为“对于(for)数组中的每一个(each)元素,取其值作为变量的值。
例:
1 for ( int k : array ) { 2 3 k … ; 4 5 }
其中,
1) 在循环体内修改k的值并不会修改k对应的数组元素的值,因为两者之间的关系是值传递;
2) 变量k必须是在括号内声明的,不可以是之前已经存在的变量。
for-each循环因为无法修改数组和得到对应下标,因此只适用于对数组遍历取每个数组元素值的场合,如打印数组,查找数组内某一元素等。
另外,如果是多层循环嵌套,若想跳出多层循环直接到达最外层,则用类似C中的goto的方法来实现:
1 MAIN_LOOP: // 类似C中的goto的标号 2 for ( … ; … ; … ) { 3 for ( … ; … ; … ) { 4 for ( … ; … ; … ) { 5 if ( … ) { 6 continue MAIN_LOOP; // 类似C中的goto MAIN_LOOP; 7 } 8 } 9 } 10 }
9. 二维数组
1 int[][] array1[3][5]; // 3行5列的二维数组 2 int[][] array2 = { 3 {1, 2, 3, 4,}, 4 {5, 6, 7, }, 5 }; // 编译器自动数出行列数(2,4),缺省部分不会默认填0,a[1][3]会出现数组越界
array1.length 表示的是数组的行数, array1[i].length 表示的是第i+ 1行的列数,
因此遍历二维数组写成:
1 for ( int i = 0; i < array1.length; i++ ) { 2 for ( int j = 0; j < array1[i].length; j++ ) { 3 … ; 4 } 5 }
10.字符
关于字符,在C中采用的是ASCII码,而Java中则是Unicode字符集。因此除ASCII码之外的各种语言文字,包括汉字也属于Java的字符。
另外,逃逸字符(即转义字符)中的\b在eclipse的console中是不会有效果的,需要在OS的console中查看效果。
如:
1 System.out.println(“abc\b”); // abc 2 System.out.println(“abc\bd”); // 在eclipse中显示abcd,而OS中abd
11.包裹类型
对于基本数据类型,Java提供了对应的包裹(wrap)类型。这些包裹类型将一个基本数据类型的数据转换成对象的形式,从而使得它们可以像对象一样参与运算和传递。下表列出了基本数据类型所对应的包裹类型:
基本类型 |
包裹类型 |
boolean |
Boolean |
char |
Character |
byte |
Byte |
short |
Short |
int |
Integer |
long |
Long |
float |
Float |
double |
Double |
包裹类型和基本数据类型之间可以相互赋值。且包裹类型提供一些基本操作,比如:
Integer.MAX_VALUE 给出int类型所能表达的最大整数(int型的范围):2147483647
Character.toLowerCase() 将括号内的大写字符转换成小写
Character.isDigit() 判断字符是否为数字
这种包裹类型的.运算操作有一部分功能与C标准库中的<ctype.h>类似。
12.字符串
在Java中,String是字符串类型。从首字母大写中可以看出,其为包裹类型,是一个类,而不是基础类型。因此,String类型的变量与基础类型的变量是不同的。
与数组的特点类似,String的变量是对象的管理者而非所有者,也需要用new来创建一个对象并管理之。
写法:
String s = new String(“a string”);
意义:创建了一个String的对象并用“a string”来初始化它,然后创建用来管理这个对象的变量s,让s管理这个对象。
初始化字符串变量,也可以直接用字符串字面量赋值的方法:
String s = “a string”;
编译器会创建一个String类的对象交给s来管理。
关于字符串的连接,在前面已经提到过。用+可以连接两个字符串,当+的一边是字符串而另一边不是时,会将另一边表达为字符串然后做连接。
“abc” + “de” → abcde
1 + 2 + “abc” → 3abc
“abc” + 1 + 2 → abc12
输入字符串时,
in.next(); // 读入一个单词,以空格/tab/换行为结束标志
in.nextLine(); //读入一整行文本
对象变量的赋值与普通变量的赋值意义是不同的:
1 int a = 5; 2 int b = a; // a 5 b 5
-----------------b = a;-----------------
1 String a = new String(“Hi”); 2 String b = a; // a → Hi ← b
正因为字符串的这种特性,因此在比较两个String时:
== 比较的是两个String变量是否管理同一个对象;
而 String.equals() 才是比较两个String变量管理的内容是否相同
即,“同一个”(用 ==) 还是“相同”(用 .equals() )的问题。
13.字符串操作
字符串的操作即是对象的操作:
字符串是对象,对它的所有操作都是通过 . 这个运算符来进行的:
<字符串>.<操作>
它表示对.左边的这个字符串做右边的那个操作。这里的字符串可以是变量也可以是常量。
尤其需要注意的是,Java的字符串是一种特殊的“不可变”对象,所有字符串操作的结果都是产生一个新的字符串,而不是对原来的字符串进行修改。对这一点的理解颇为重要。
1)获得String的长度可用 .length() ,注意这里是 .length() 与数组的 .length 不同,因为在String中 .length() 是一个操作,而数组的 .length 是数组的一个固有成员。
1 String str1 = “hello”; 2 String str2 = “”; 3 String str3; 4 str1.length(); // 5 5 str2.length(); // 0 6 str3.length(); // Error!因为str3没有管理任何String对象
2)访问String里的字符,需要用.charAt(index)操作,其中:
·返回index上的单个字符
·index的范围是0~length()-1
·第一个字符的index是0,和数组一样
·但不能用for-each循环来遍历字符串
3)得到子串,有两种表达方式:
s.substring(n); // 得到s中从n号位置到末尾的全部内容 s.substring(b, e); // 得到从b号位置到e号位置之前的内容
4)寻找字符
s.indexOf(c); // 得到s中字符c第一次出现的位置,-1表示s中不存在c s.indexOf(c, n); // 在s的第n号位置上开始寻找c s.indexOf(t); // 得到s中字符串t第一次出现的位置
从右边开始找:
s.lastIndexOf(c);
s.lastIndexOf(c, n);
s.lastIndexOf(t);
关于 s.indexOf(c, n) 的常用套路:
当s中有多个字符c,而想找其中某一个的时候,可以这样做:
1 int loc = s.indexof(c); // 记录c第一次出现的位置 2 s.indexOf(c, loc+1); // 从loc + 1处开始寻找s中的第二个c,若不+1,则结果还是第一次出现的位置
5)其他字符串操作:
s.startsWith(t); // 判断字符串s是否以字符串t开头 s.endsWith(t); // 判断字符串s是否以字符串t结尾 s.trim(); // 删除字符串s两端的空格 s.replace(c1, c2); // 将字符串s中所有的c1都置换成c2 s.toLowerCase(); // 将字符串s内所有字符变成小写 s.toUpperCase(); // 将字符串s内所有字符变成大写
6)字符串的switch-case:
1 switch( s ) { 2 case “this”: …; 3 case “that”: …; 4 }
此写法只能在Java1.7及以上的版本使用。
14.函数
C中的函数在Java中被称作方法,但两者没有本质上的区别。与C不同的是,在同一个函数内,块(即{})里定义的变量不能和块外定义过的变量同名。
如:
1 int a = 0; 2 3 { 4 5 int a = 1; // Error! Duplicate local variable a 6 7 }
而在C中,块里面定义了与外面同名的变量则掩盖了外面的。
关于函数参数类型,C中不允许实参与形参类型不匹配,而在Java中,
·当形参类型比实参长度宽时,编译器会自动转换类型为宽类型
·当形参类型比实参长度窄时,需要对实参进行强制类型转换
·当形参与实参类型无法转换时则不允许
在Java中,因为没有指针的概念,所以在调用函数时,永远只能传值给函数。
以上就是本周所学的Java基础语法,只学了这些还远远不够,就像不学指针就等于未学C一样,大概Java的灵魂在于面对对象的思想和封装、继承、多态这三大特性吧。