第3章 Java基本的程序设计结构
__3_1 简单的Java程序
1.关键字public称为访问修饰符(access modifier)。用于控制程序的其他部分对这段代码的访问级别。(c5中详细介绍)
2.类名定义:以字母开头,后面可跟字母和数字的任意组合。长度基本没有限制。不可使用Java保留字。
标准规范:大写字母开头(每个单词)。这种在一个单词中间使用大写字母的方式称为骆驼命名法。
源文件的文件名必须与公有类的名字相同,并使用.java作为扩展名
3.当使用 java ClassName
运行编译程序时,Java虚拟机将从指定类中的main方法开始执行
__3_2 注释
1./* … /格式的注释可用于自动生成文档
2./* … */注释不能嵌套
__3_3 数据类型
Java是一种强类型语言,必须为每一个变量声明一种类型,Java中共有8种基本类型(primitive type)。
- 整形
类型 | 空间 | 表示范围 |
---|---|---|
int | 4字节 | 正好超过20亿 |
short | 2字节 | |
long | 8字节 | |
byte | 1字节 |
长整形数值后有后缀L
Java没有任何无符号类型(unsigned type)
- 浮点型
float 4字节 有效位6~7位
double 8字节 有效位15位
1)只有很少的情况适合使用float类型,例如,需要快速处理单精度数据,或者需要存储大量数据。
2)float型数值后有后缀F,没有后缀F的浮点数值默认为double型,也可在double型数值后加后缀D。
3)十六进制表示浮点数值 —— 0.125 可表示为 0x1.0p-3,p表示指数而非e,位数采用十六进制,指数采用十进制,指数基数为2。
4)表示溢出和出错的三个特殊浮点数值,分别对应三个常量
含义 | 对应常量 |
---|---|
正无穷大 | Double.POSITIVE_INFINITY |
负无穷大 | Double.NEGATIVE_INFINITY |
NaN(不是一个数字) | Double.NaN |
所有“非数值”的值认为是不相同的,使用Double.isNaN方法,而非==来检测一个特定值是否等于Double.NaN
5)浮点数值不适用于禁止出现舍入误差的金融计算中,例如System.out.println(2.0-1.1);
将输出0.899999…而非0.9,因二进制无法精确表示1/10。
- char型
1)转义序列符\u表示Unicode代码单元的编码,它也可以出现在字符常量或字符串的引号外,如 public static void main(String\u005B\u005D args)符合规则。而除此之外的转义序列均不可。
2)代码点(code point)是指与一个编码表中的某个字符对应的代码值。Unicode的代码点可分为17个代码级别(code plane)。第一个级别为基本的多语言级别(basic multilingual plane),代码点从U+0000到U+FFFF,其中包括了经典的Unicode代码;其余的16个附加级别,从U+10000到U+10FFFF包括了一些辅助字符。
UTF-16编码采用不同长度的编码表示所有Unicode代码点。在基本的多语言级别中,每个字符用16位表示,通常被称为代码单元(code unit);而辅助字符采用一对连续的代码单元进行编码。可以迅速知道一个代码单元是一个字符的编码,还是辅助字符的第一或第二部分。
3)强烈建议不要在程序中使用char型,最好将需要处理的字符串用抽象数据类型表示。 - boolean型
__3_4 变量
1.在Java中,不区别变量的声明与定义。
2.在Java中,使用final声明常量,即该变量只能被赋值一次,习惯上,常量名使用大写。经常希望某个常量可以在一个类中的多个方法使用,通常称其为类常量,使用static final设置之。
3.const为保留关键字,但目前未使用。
__3_5 运算符
1.整数除0会产生一个异常,而浮点数被0除将会得到无穷大或NaN结果。
2.在默认情况下,虚拟机设计者将中间计算结果采用扩展的精度。但是使用strictfp关键字标记的地方必须使用严格的浮点计算来产生理想的结果。例如,
public static strictfp void main(String[] args)
如果将一个类标记为strictfp,这个类中的所有方法都要使用严格的浮点计算。
3.“短路”方式求值的逻辑计算
4.三元操作 ?:
condition ? expression1 : expression2
x < y ? x : y 将返回x,y中较小的那个值
5.位运算
1)逻辑位运算
运算符 | 含义 |
---|---|
& | 与 |
| | 或 |
^ | 异或 |
~ | 非 |
& | 应用于布尔值将得到布尔值,与&& ||相似,只是不按“短路”方式计算
2)移位运算
运算符 | 含义 | 说明 |
---|---|---|
>> | 算数右移 | 用符号位填充高位 |
>>> | 逻辑右移 | 用0填充高位 |
<< | 左移 | (无<<<) |
移位运算对右侧参数进行模32的运算,long型模64
6.数学函数与常量
Math.sqrt(x);
计算平方根
Math.pow(x,a);
计算x的a次幂 (double)
Math.sin, cos, tan, atan, atan2
三角函数
Math.exp, log
指数函数及其反函数,自然对数
Math.PI
PI的近似值
Math.E
e的近似值
从JDK 5.0开始不必添加前缀Math,只需
import static java.lang.Math.*;
使用StrictMath类可确保在所有平台上得到相同的结果。
7.类型转换
不同类型的操作数,若其中一个为double,则另一个转为double
否则,若其中一个为float,则另一个转为float
否则,若其中一个为long,则另一个转为long
否则,转为int
8.强制类型转换
浮点型转整形保留整数部分
使用Math.round()舍入以得到浮点参数最接近的整数,Math.round()返回long类型
注: 不要在boolean类型与任何数值类型间强转,使用 b? 1:0
9.括号与运算符级别
按照运算符优先级次序进行计算,同级别的运算符按照从左到右进行计算(除右结合运算符外)
运算符优先级
运算符 | 结合性 |
---|---|
[] . () (方法调用) | 从左向右 |
! ~ ++ – new (强制类型转换) | 从右向左 |
| 从左向右 |
| 从左向右 |
<< >> >>> | 从左向右 |
< <= > >= instanceof | 从左向右 |
== != | 从左向右 |
& | 从左向右 |
^ | 从左向右 |
| | 从左向右 |
&& | 从左向右 |
|| | 从左向右 |
?: | 从右向左 |
= += -= *= /= %= &= |= ^= = <<= >>= >>>== | 从左向右 |
10.枚举类型
enum Size { SMALL, MEDIUM, LARGE, EXTRA_LARGE };
Size s = Size.MEDIUM;
Size类型的变量只能存储这个类型声明中给定的某个枚举值,或者null值。
__3_6 字符串
Java字符串就是Unicode字符序列,Java没有内置的字符串类型,而是在标准Java类库中提供的一个预定义类String,每个用双引号括起来的字符串都是String类的一个实例。
1.substring(a,b)
第一个参数为开始复制的位置,第二个参数为不想复制的第一个位置,子串长度为b-a
2.使用+拼接两个字符串。
3.String类对象为不可变字符串。
4.s.equals(t)
s,t可以是字符串变量,也可以是字符串常量。
不区分大小写 equalsIgnoreCase()
实际上只有字符串常量是共享的,而+或substring等操作产生的结果不是共享的。
5.代码点与代码单元
1)length返回代码单元数量,字符串实际的长度,即代码点数量使用codePointCount
String greeting = "Hello";
int n = greeting.length();
int cpCount = greeting.codePointCount(0, greeting.length());
2)s.charAt(n)
将返回位置n的代码单元,除非对底层的代码单元感兴趣,否则不应调用。
3)想要得到第i个代码点,使用
int index = greeting.offsetByCodePoints(0,i);
int cp = greeting.codePointAt(index);
4)遍历字符串,依次查看代码点
int cp = sentence.codePointAt(i);
if(Character.isSupplementaryCodePoint(cp))
i += 2;
else
i++;
5)replace(CharSequence oldString, CharSequence newString)
,用newString代替原始字符串中所有的oldString。可用String或StringBuilder对象作为CharSequence参数。
6)toLowerCase() toUpperCase()
7)构建字符串
由较短的字符串构建字符串时,使用字符串连接的方式效率低,因每次连接创建新String对象,耗时且浪费空间。使用字符串构建器。
StringBuilder builder = new StringBuilder();
每次需要添加时调用append方法
builder.append(str);
需要构建字符串时,使用
String completedString = builder.toString();
注:StringBuilder的前身使StringBuffer,效率略低但允许采用多线程执行添加或删除字符的操作。
__3_7 输入输出
1)
Scanner in = new Scanner(System.in); //构造Scanner对象并与标准输入流System.in关联。import java.util.*
in.nextLine();
in.next();
in.nextInt();
in.nextDouble();
2) 读取密码 为安全起见,读取结果应存放至数组中,并在处理密码后立刻用一个填充值覆盖数组元素
Console cons = System.console();
String username = cons.readLine("User name: ");
char[] passwd = cons.readPassword("Password: ");
3)
格式化输出
System.out.printf("%8.2f",x);
宽度8,精度小数点后两位
a)转换符
转换符 | 类型 |
---|---|
d | 十进制整数 |
x | 十六进制整数 |
o | 八进制整数 |
f | 定点浮点数 |
e | 指数浮点数 |
g | 通用浮点数 |
a | 十六进制浮点数 |
s | 字符串 |
c | 字符 |
b | 布尔 |
h | 散列码 |
tx | 日期时间 |
% | 百分号 |
n | 与平台有关的行分隔符 |
b) 标志
标志 | 含义 |
---|---|
+ | 打印正数和负数的符号 |
空格 | 在正数前添加空格 |
0 | 数字前面补0 |
- | 左对齐 |
( | 将负数括在括号内 |
, | 添加分组分隔符 |
(f格式) | 包含小数点 |
(x或0格式) | 添加前缀0x或0 |
$ | 参数索引 |
< | 格式化说明前面的数值 |
c)
String msg = String.format("Hello,%s. Next year, you'll be %d", name, age);
d)
System.out.printf("%1$s %2$tB %2$te, %2$tY", "Due date:", new Date());
索引必须紧跟%后且以$终止
e)
System.out.printf("%s %tB %<te, %<tY", "Due date:", new Date());
<表示前面格式说明中的参数将再次被引用
4) 文件输入与输出
a) 使用File对象构造Scanner对象以读取文件
Scanner in = new Scanner(new File("myfile.txt"); //反斜杠需要转义
Scanner(String data) //构造一个从给定字符串读取数据的Scanner
b) 构造PrintWriter对象以写入文件
PrintWriter out = new PrintWriter("myfile.txt"); //可使用print,println等`
c) 关于相对路径,命令行下为命令解释器当前的路径,IDE下由IDE控制,可用String dir = System.getProperty("user.dir");
找到
如果用不存在的文件构造Scanner或不能创建的文件名构造PrintWriter,会发生异常
d) 使用重定向将任意文件捆绑到System.in System.out;
java MyProg < myfile.txt > output.txt
__3_8 控制流程
1)break语句可以带标签,可以利用它实现从内层循环跳出的目的。
read_data:
while(...)
{
for()
{
if()
break read_data;
}
}
事实上可以将标签应用到任何语句中,甚至使if语句或块语句中:
label:
{
if(condition)
break label;
}
break语句只能跳出语句块,不能跳入语句块。
2)还有一种带标签的continue语句,将跳到与标签匹配的循环首部。
3)在循环中检测两个浮点数是否相等要格外小心。如
for(double x = 0; x!=10; x+=0.1);
可能永远不会结束,由于舍入误差,最终得不到精确值,因0.1无法用二进制表示。
4)如果在case分支语句的末尾没有break语句,有可能触发多个case分支。case标签必须是整数或枚举常量,不能测试字符串。switch使用枚举常量时不必在每个标签中指明枚举名,case SMALL //no need to use Size.SMALL
__3_9 大数值
java.math包中的BigInteger和BigDecimal可以处理包含任意长度数字序列的数值,分别实现了任意精度的整数运算和任意精度的浮点数运算。
BigInteger a = BigInteger.valueOf(100);
BigInteger b = a.add(b);
BigInteger d = c.multiply(b.add(BigInteger.valueOf(2)));
//API
add()
subtract()
multiply()
divide()
mod()
int compareTo()
static BigInteger valueOf(long x)
__3_10 数组
1)声明与初始化
int[] a; //声明
int[] a = new int[100] //初始化
可使用int[] a;
或 int a[];
int[] smallPrimes = {2,3,5,7};
匿名数组: new int[] {17,19,23};
2)遍历
For each //只可用于一个数组或者一个实现了Iterable接口的类对象
for(int element : a);
3)输出
Array.toString(a)
==> “[2,3,5,7]”
5)Java中允许数组长度为0,可用于返回数组的方法
new elementType[0]
6)数组拷贝
int[] copiedLuckyNumbers = Arrays.copyTo(luckyNumbers, luckyNumbers.length);
后一参数可用于增加数组大小或截断数组前一部分。
System.arraycopy(from, fromIndex, to, toIndex, count);
7)数组排序
Array.sort(a); //优化的快排
8)随机数生成
Math.random()
返回一个0到1之间,包含0不包含1的随机浮点数,乘N可得0到N-1的随机数。
9)填充数值
fill(type[] a, type v);
10)快速打印二维数组的数组元素列表
System.out.println(Arrays.deepToString(a));
11)不规则数组