第2章 程序,数据,变量和计算
2.1 数据和变量
变量是一段有名字的内存, 存储程序中的信息, 描述事物的数据项;
每段定义了名字的内存只能存储一种特定类型的数据. Type; 编译器会检测错误的类型使用;
程序中出现的显式数据值叫做字面量, 有特定类型;
2.1.1 变量的命名
标识符-选择的名称; 可以是任意长度, 必须以字母, 下划线或美元符号$开始; 标识符的其他部分最好使用字母数字或下划线, 不能使用运算符(+ - * /);
大小写敏感, 不能在一个名字中包含空格或制表符; 不能数字开头; 不能使用关键字, 不能是常量;
Note Java通常约定变量名小写字母开始, 词的首字母大写;
2.1.2 变量名与Unicode
Java源码使用Unicode, 不管原始代码的编码, 在编译之前会在内部转换为Unicode字符;
编译器假设源代码在工作过程中使用默认字符编码. 使用-encode选项告诉编译器源代码使用的字符编码; e.g. javac.exe -encoding unicode JavaTest.java
2.1.3 变量与类型
类型+名字: int nubmerOfCats;
基本数据类型: 数值数据, 整型或浮点; 单个Unicode字符; 逻辑值true/false;
Java中的基本变量类型名都是关键字;
2.2 整数数据类型
4种变量, 都是带符号的;
byte: −128 到+127; 占1字节(8 比特);
short: −32768 到32767; 占2 字节(16 比特);
int: −2147483648 到2147483647; 占4 字节(32 比特);
long: −9223372036854775808 到9223372036854775807; 占8 字节(64 比特);
Java中存储值的范围不会变, 与计算机类型无关;
最大值和最小值:
>最左边的是符号位, 0代表正, 1代表负; 负二进制数用补码形式来表示;
整数字面量
设定为十进制数字序列的整数字面量都默认为int类型: 1, -999, 123; long类型的整数字面量需要加L: 1L, -999L, 123L;(可以用小写l, 但是容易和数字1混淆)
数字字面量可以使用(一个或多个)下划线字符划分表示: 1,234,567,890->1234567890L->1_234_567_890L.
4种方式写整数字面量:
十进制, 十六进制, 二进制, 八进制;
1) 十六进制
0x或0X开头, 字母A-F(a-f)表示数字10-15; e.g. 0x100 = 1*16^2 + 0X16^0 + 0*16^0 = 256;
默认为int, 需要设定long类型时在后面添加L; 0xFL -> 15;
下划线字符可以将十六进制数字每4个分为一组, 每组对应内存中的2个字节; 下划线只能在数字间出现, 0x_3A和0x3A_都不对;
2) 二进制
0b或0B开头, 数字为1或0; 0b1100_1010_1011和0xCAB一样->3234; 每组4个二进制对于一个十六进制数;
3) 八进制
0开头, e.g. 0777_777L, 只能使用数字0-7; 每个八进制数为3比特;
2.2.1 声明整型变量
声明变量需要初始化;
单条语句定义多个变量, 使用逗号分隔: long bigOne = 999_999L, largeOne = 100_100L;
一般使用int和long足够, 使用byte和short增加复杂度, 在必须对应数据类型的情况下才使用,e.g. 从硬盘读取数据;
2.3 浮点数数据类型
有准确的固定位数, 广泛的取值空间; float和double的定义遵循IEEE 754标准;
float: −3.4E38(−3.4×10^38)到+3.4E38(+3.4×10^38), 4个字节, 小数点后7位. 最小值~1.4*10^-45;
double: −1.7E308(−1.7×10^308)到+1.7E308(+1.7×10^308); 8字节, 小数点后17位, 最小值~4.9*10^-324;
表示浮点值的数字位数称为精度precision;
2.3.1 浮点数字面量
默认为double类型; e.g. 1.0, 345.678; 设定float类型需要在后面加上f或F, e.g. 1.0f. 345.678F; double类型需要的话在后面附加d或D;
7.123456 == 7.123_456; 149,600,000 == 1.496E8, 添加E或e代表10的指数次方;
2.3.2 声明浮点型变量
double sunDistance = 1.496E8; flat electronMass = 9E-28F;
Note 不在数字末尾添加F/f的话默认为double类型;
2.4 固定变量的值
final int FEET_PER_YARD = 3; //constant vlaue;
final关键字设定变量的值不能修改, 使用大写字母是Java中约定的常量写法; 必须有初始值;
2.5 算术运算
赋值语句: 变量名; 运算符=; 算术表达式' numFruit = numApple + numOrange;
单条语句赋值: a = b = c = 777; (编译器会在编译时优化赋值语句)
short value = 10; 类型转换int ->short;
2.5.1 整数计算
加减乘除, 二元运算符;
Note 使用括号()来控制运算顺序/优先级;
一元运算符: count(-10)->-count == 10;
e.g. 读取键盘输入, Enter退出
1
2
3
4
5
6
7
8
9
|
public static void main(String[] args){
System.out.print( "press Enter to exit:" );
try {
System.in.read();
}
catch (IOException e){
return ;
}
}
|
>args提供运行时访问从命令行传数据的方法;
>通常将main()设为public static, 返回值void: 共有, 静态(不必创建对象), 没有返回值;
2.5.2 整数除法和余数
整数不能整除时, 会舍弃余数, e.g. 3/2->1; 11/3->3; 正负符号不影响绝对值, e.g. 7/(-3)->-2; (-5)/(-3)->1;
Note 特例 -2_147_483_648是int的最大负值, 除以-1等于2_147_483_648超过了int的最大值2_147_483_647, 结果无法表示, 会变回为最初的被除数-2_147_483_648;
被0除会导致程序终止->ArithmeticException;
余数%, 8%(−3)->+2; (-8)%3->-2; (-8)%(-3)->-2; 与乘除法有同样优先级;
2.5.3 增量与减量运算符
++和--; 前缀式prefix(先自操作, 后计算), 后缀式postfix(先计算, 后自操作);
e.g. int a = 1; int b = ++a; int c = a++; >b和c都为2;
2.5.4 短整数类型的计算
Note Java中的二元整数运算只允许int或long, byte和short类型会转换为int, 使用32位计算, 结果是int类型(32位整数);
int->short需要显式转换: int a =100; short b = (short)a;
Note Java二进制数位都是从右向左增加, 保留低位是可以转换值的, 但是如果超出位数, 转换就会截断;
这里只能把b转换到最接近a的内容, 应该避免意料之外的数据的显式转换;
long类型值的整数运算总是使用64位, 编译器会把其他操作数转换为long类型;
2.5.5 整数算术中的错误
除以0和对0取余都会抛出异常;
如果整数表达式产生的值在取值范围之外, 结果会缩减至相应类型的位数, 这个情况不会报错, 需要程序员来确保结果不出错;
Note 注意中间结果也可能出错, e.g. (1000000*2000000)/500000 乘法得到的结果是有问题的, 最后值没有溢出但是结果不是预期的;(可以先做出发避免溢出)
2.5.6 浮点计算
+ - * /
2.5.7 其他浮点算术运算符
++, --, 每次位移1.0;
取模 %; floatOperand1 % floatOperand2->将floatO1用floatO2分割整数次之后得到的浮点余数;
e.g. 12.6%5.1 == 2.4; 结果的符号一般和被除数的符号一致;
2.5.8 浮点算术中的错误
1) 计算产生的值在浮点型取值范围外; "Infinity"-表示正的有效无限大的结果; (10 / 0)
2) 数学上的: 计算除以零的值; "NaN"-非数字Not a Number, 表示一个不确定值; (0 / 0)
Note Infinity与有限数做加,减或乘运算时, 值不会改变; 但是如果除以任何有限数, 结果为0;
2.5.9 混合算术表达式
类型检查: 如果一个操作数是double/float/long, 运算前将另一个转换为double/float/long;
Note 先后次序是double, float, long; (有double变double)
2.5.10 显式转换
e.g. three(3), two(2)
result = 1.5 + three/two; //2.5
result = 1.5 + (double)three/two; //3, 在运算前three被转换成了double型的3.0;
Note 注意类型转换时的精度丢失, e.g. double --> float, 如果double的值比float的最大值大, 会产生一个Infinity;
2.5.11 赋值中的自动类型转换
当赋值运算符右边的算术表达式结果的类型与左边不同, 信息不丢失的情况下会自动转换;
byte->short->int->long-float->double;
相反方向需要进行显式转换;
2.6 op=运算符
op=操作符可以是任何算术运算符 +, -, *, /, %;
lhs op = rhs; --> lhs = lhs op (rhs);
rhs会首先执行, 然后进行运算; e.g. result /= a % b/(a + b); --> result = result/(a % b/(a + b));
如果rhs和lhs类型不同, 编译器会自动插入转换, 将rhs的值转换成lhs的类型; lhs = (type_of_lhs)(lhs op (rhs));
+=, -=, *=, /=, %=, <<=, >>=, >>>=, &=, |=, ^=;
2.7 数学函数和常量
数学函数作为标准库的一部分存储在java.lang中; 数学函数的方法都在Math类中, 作为static方法;
sin(arg)正弦; cos(arg)余弦; tan(arg)正切; asin(arg)反正弦; acos(arg)反余弦; atan(arg)反正切; atan2(arg1, arg2) arg1/arg2的反正切; toRadians()将角度转换为弧度, 反之toDegrees(); Math.E和Math.PI; abs(arg)绝对值; max(arg1, arg2)较大值, min(arg1, arg2); ceil(arg) 返回等同于参数或比参数大的最小整数值; floor(arg) 返回等同于参数或比参数小的最大整数值; round(arg)离参数值最近的整数, rint(arg); random() 返回比0.0 大但比1.0 小的伪随机数; ...
导入Math类的方法
import static java.lang.Math.*; //导入静态的类成员, 可以在使用时省略类名;
Math.floor(radius) --> floor(radius);
import static java.lang.Math.floor; //导入特定的方法或者变量;
2.8 存储字符
char-单个字符代码, Unicode, 占16bit/2字节, 初始化: char myCharacter = 'X'; 单引号代表字符, 双引号代表字符串;
2.8.1 字符转义序列
通过转义序列(escape sequence)设定十六进制表示的字符编码来定义Unicode字符;
转义序列通常通过代码设定字符, 反斜线开始- \n;
在表示字符编码的4个16进制数字前加上\u, 可以为一个Unicode字符创建一个转义序列: X - 0x0058; e.g. char myCharacter = '\u0058';//对应 'X';
www.unicode.org 反斜线的转义序列: \\, 引号 \', \"; \b 退格; \f 换页符; \n 新行; \r 回车换行; \t 制表符;
2.8.2 字符算术
myCharacter += 1; //当myCharacter为字符时,'X'+1 --> 'Y' (same as ++myCharacter)
char类型在算术表达式中被转换为int类型进行计算;
1
2
3
|
char aChar = 0 ;
char bChar = '\u0028' ;
aChar = ( char )( 2 *bChar + 8 );
|
>aChar变量保存了字母X的编码--0x0058, 使用(char)转换, 否则编译器会认为char不可转换成int;
>int(aChar), System.out.printIn出来的显示是 58; static方法Integer.toHexString()可以输出16进制;
Integer类与int相关, 封装了int类型的值. e.g. Byte, Short, Long.
可以使用静态导入语句来只导入静态成员: import static java.lang.Integer.toHexString;
2.9 位运算
整型变量在内部以二进制数表示, int类型由32个2进制数组成(bit);
使用bit运算符对组成证书值的比特进行运算:
& 与(AND); 位与运算符, 两个操作数的对应比特结合, 如果两者都是1, 结果为1, 否则为0;
| 或(OR); 位或运算符, ...如果其中一个是1, 结果为1, 只有当两者都为0时, 结果为0;
^ 异或(Exclusive OR); 位移或XOR, ...,如果两个比特位值相同, 结果为0, 否则为1;
~ 补(Complement); 只有一个操作数, 改变该操作数所有比特位的值, 使得每个1变成0, 每个0变成1;
在位运算时很关心单个位, 所以将常量写成二进制字面量比较方便;
2.9.1 AND和OR运算符
掩码(Mask)是用来引用一个特定位配置的术语, 当一个位运算符将掩码和一个变量结合起来时, 掩码用来对特定的位进行操作;
e.g. 从一个int变量indicators中选出第三位: thirdBit = indicators & 0b0100; 十六进制选第三位是 0x4;
Indicators- 0b1111_1111_0000_1111 (0xFF07); Mask- 0b0000_0000_0000_0100;
indicator & mask- 0b0000_0000_0000_0100;
>掩码值将结果中除了第三位以外的所有位都设置为零, 将indicators的第三位设置到相对应的位置;
indicators 0b1111_1111_0000_1001 (0xFF09); mask 0b0000_0000_0000_0100;
indicator & mask 0b0000_0000_0000_0000;
>如果indicator第三位为0, 则得到的结果也是0;
indicators = indicators | mask; // Set the 3rd bit on, 将第三位设为1;
使用op=的形式: indicators |= mask;
设置indicators的第三位为0: indicators &= ~mask;
>Binary caculate
1
2
3
4
|
import static java.lang.Integer.toBinaryString;
//...
int indicators = 0b1111_1111_0000_0111;
System.out.println( "indicators = " + toBinaryString(indicators));
|
2.9.2 使用异或运算符
Note 运算符^可以用来交换两个数的值: a ^= b; b ^= a; a ^= b; 只对整数有效; (在图形编程中应用)
在使用16进制的值初始化byte和short变量时, 要注意避免位数错误:
byte allBitsOne = 0xFF; // Wrong!!
0xFF字面量是1111 1111 (0b1111_1111), 二进制值是0000 0000 0000 0000 0000 0000 1111 1111, 和十进制255一样, 在byte类型的表示范围外. 1111 1111编译器会识别为十进制int的-1;
将allBitsOne全部初始化为1的正确写法: byte allBitsOne = 0xFFFFFFFF; // Correct - well done!!
2.9.3 位移操作
将整数的位左移或右移, 可以将对二进制数进行左右位移的过程看作除以或乘以2的对应次幂.
<< 向左位移, 右边用零填充; >> 向右位移, 左边用符号位填充; >>> 向右位移, 左边用零填充;
e.g. long mask = 0xFFFF; 最右边的16位是1, 可以用来提取最右边的字符: char letter = (char)(packed & mask);
2.9.4 位操作方法
位操作的方法定义在 java.lang的Integer和Long类中.
bitCount(arg) 返回作为arg 提供的二进制整数中值为1 的位的个数, 该个数作为int 类型值返回;
highestOneBit(arg) 返回一个整数, 该整数只有与arg 中最左边的1 对应的位为1. 返回值与arg 类型一样;
lowestOneBit(arg) 返回一个整数, 该整数只有与arg 中最右边的1 对应的位为1. 返回值与arg 类型一样;
numberOfLeadingZeros(arg) 返回arg 中在最左边的1 之前的0 位的个数, 返回值为int 类型. 如果arg 是零, 该方法返回arg 中所有位的个数, 即对int 类型为32, 而对long 类型为64;
numberOfTrailingZeros(arg) 返回arg 中在最右边的1 之后的0 位的个数, 返回值为int 类型. 如果arg 是零, 该方法返回arg 中所有位的个数, 同上;
reverse(arg) 返回通过反转arg 的位顺序而得到的值, 返回值与arg 类型一样;
rotateLeft(arg, distance) 返回将arg左边distance个数的位的值左轮换得到的值, 其中distance是int. 左轮换表示将从左边轮换出去的位填到右边的空位中. 返回值与arg 类型一样;
rotateRight(arg, distance) 返回将arg右边distance个数的位的值右轮换得到的值,distance是int. 右轮换表示将从右边轮换出去的位填到左边的空位中. 返回值与arg 类型一样;
e.g.
1
2
|
int data = 0x0F00 ; // data is: 0b0000_0000_0000_0000_0000_1111_0000_0000;
int bits = Integer.bitCount(data); // Result is 4
|
>int和Integer必须对应;
1
2
|
long number = 0xF000_0000_0000_000FL;
long result = Long.rotateLeft(number, 2 );
|
>result首字节为0xC0, 尾字节为0x3F, 其他位都是0; (16进制 1100 -> 12 -> C)
toBinaryString()将二进制以字符串形式表示;
2.10 取值范围为固定整数值集合的变量
枚举类型 enumerated type/enumeration
1
|
enum Day {Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }
|
>默认从0开始, 类型名约定为大写字母开头;
1
|
Day weekday = Day.Tuesday;
|
Note enum类型不可以作为一个方法的局部变量; Day类型是class的局部类型; 可以将enum放在类外面作为全局定义;
Note Java中枚举类型的值默认表示成字符串, 值只是用来区分枚举常量;
e.g. System.out.println(yesterday); // 显示为 "Thursday"
2.11 布尔变量
boolean类型: 字面量true或false; (George Boole, 布尔代数)
结合boolean值使用的运算符: 与&&, 或||, 非!;
Note Java中boolean类型的变量不同于其他基本数据类型, 不能和其他任意基本类型相互转换;
2.12 运算符的优先级
决定语句中执行的顺序; 高->低:
()、[]、后缀++、后缀-- ; 一元+、一元-、前缀++、前缀--、~、!; (类型)、new ;
*、/、%; +、-; <<、>>、>>> ; <、<=、>、>=、instanceof ; ==、!= ;
& ; ^ ; | ; && ; || ; ?: ; =、+=、-=、*=、/=、%=、<<=、>>=、>>>=、&=、|=、^= ;
Note 后缀++运算符会在其他运算符执行后修改操作数的值;
2.13 程序注释
//和/*...*/
文档注释 documentation comment
javadoc可以处理source code中的文档注释, 生成单独文档; e.g. SDK中的文档; HTML格式, 可以使用浏览器查看;
由/**开始*/结束:
1
2
3
|
/**
* This is a documentation comment.
*/
|
>文档注释会忽略每行开头的星号(每行需要有个星号);
@author 用于定义代码的作者. 通过添加如下标签来指定作者:
1
2
3
|
/**
* @author Ivor Horton
*/
|
@deprecated 在库中类和方法的文档中使用, 指示已经替换它们并且不应该在新的应用程序中使用. 主要用于标识类库中废弃的方法;
@exception 用于记录代码可能抛出的异常以及可能导致这种情况发生的条件. e.g. 将如下文档注释添加到一个方法的定义之前, 指示该方法可能抛出的异常类型:
1
2
3
|
/**
* @exception IOException When an I/O error occurs.
*/
|
{@link} 生成到所生成文档中另一部分文档的链接. 可以使用这个标签在代码的描述文本中插入到另一个类或方法的链接. 花括号用来分离链接和其他的文本;
@param 用来描述一个方法的参数;
@return 用来记录从一个方法返回的值;
@see 用来设定到另一个类或方法的其他部分代码的交叉引用.
1
2
3
|
/**
* @see Object#clone()
*/
|
也可以只设定一个代表外部引用的字符串, 不识别为URL. 可以引用一个URL
1
2
3
|
/**
* @see "Beginning Java 7"
*/
|
@throws @exception 的同义词;
@version 用来描述代码的当前版本;
除了header标签, 可以在文档注释中使用任何HTML标签; javadoc会添加HTML标签对特殊@标签的注释进行格式化;
2.14 小结
基本类型: 内置于Java 语言的类型. 基本类型的变量存储整型或浮点型的数值, boolean 值以及Unicode 字符;
整数类型: byte、short、int 以及long 类型, 这些类型的变量分别占据1、2、4 以及8 个字节;
存储字符: char 类型的变量占据2个字节并且可以存储单个的Unicode 字符编码;
存储逻辑值: boolean 类型的变量只能存储true 或false 值;
浮点类型: 浮点类型是float 和double, 分别占用4 字节和8 字节;
整型运算: 整型表达式使用用于long 类型变量的64 位操作以及用于其他所有整型类型的32 位操作来计算, 因此, 必须为用来存储byte、short 或char 类型的结果赋值操作添加转换;
浮点运算: 产生一个在结果类型取值范围之外的结果. 在浮点类型取值范围之外的值中, 有一个特殊的表示为Infinity 或−Infinity 的值. 浮点运算的结果也可以是不确定的, 用NaN 表示;
转换: 通过使用显式转换将一种类型的值转换为另一种类型. 对于op=赋值操作, 转换会在需要时自动提供. 不能对boolean 类型的值进行类型转换操作, 不能将其他值转换成boolean 类型;
操作顺序: 一个表达式中运算符的执行顺序由它们的优先级决定. 对于优先级相同的运算符, 执行顺序取决于自身的结合性;
枚举类型: 可以使用枚举类型定义一些变量, 只能从一个作为枚举一部分设定好的固定集合中取值. 枚举类型不能在方法内部定义;
---2 End---