最简单的Java程序:
public class FirstSample { public static void main(String[] args) { System.out.println("We will not use 'Hello, World!'"); } }
类名定义规则:字母开头,后可以跟字母好数字的任意组合,长度基本没有限制。
标准命名规范:以大写字母开头的名词。若名词由多个单词组成,每个单词第一个字母大写。
源代码的文件名必须与公有类名字相同(大小写敏感),并用.java作为扩展名。
注释:
第一种:
// 这是一行注释
第二种:
/* 这是一行注释 /*
第三种:
/** 这是一行注释 */
和第二种的区别:可用来自动生成文档。
数据类型:
整型:
类型 |
---|
int
4字节
-2147483648~2147483647
short
2字节
-32768~32767
long
8字节
-9223372036854775808~9223372036854775807
byte
1字节
-128~127
整型的范围与运行Java代码的机器无关。
长整型有后缀L(4000000000L),十六进制有前缀0x(0xCAFE),八进制有前缀0(010)。
Java没有浮点类型。
浮点型:
类型 存储需求 取值范围
float
4字节
有效位数6~7位
double
8字节
有效位数15位
float型有后缀F(3.402F)。没有后缀F的浮点数值(3.402)默认为double类型。也可在浮点数值后加后缀D(3.402D)。
三个特殊浮点数值:
- 正无穷大(Double.POSITIVE_INFINITY)
- 负无穷大(Double.NEGATIVE_INFINITY)
- NaN(Double.NaN)
所有“非数值”的值都认为是不相同的,因此:
if (x == Double.NaN) // 错误! if(Double.isNaN(x)) // 正确!
浮点数值不适用于禁止出现舍入误差的金融计算中。如需在数值计算中不含有任何舍入误差,应使用BigDecimal类。
char类型:
char类型用于表示单个字符。Unicode编码单元可以表示为十六进制值,范围从\u0000到\UFFFF。
转义序列符\u还可出现在字符常量或字符串的引号之外(其他所有转义序列不可以):
public static void main(String \u005B\u005D args)
boolean类型:
false/true。用来判定逻辑条件。整型值和布尔值之间不能相互转换。
变量:
变量名定义规则:以字母开头,右字母或数字构成。(字母的范围更大)
变量需显式初始化,否则报错。
Java不区分变量的声明与定义。
常量:
利用关键字final声明常量:
final double CM_PER_INCH = 2.54;
使用static final设置的产量成为类常量,可以在一个类的多个方法中使用:
public class Constants2 { public static void main(String[] args) { double paperWidth = 8.5; double paperHeight = 11; System.out.println("Paper size in centimeters: " + paperWidth * CM_PER_INCH + " by " + paperHeight * CM_PER_INCH); } public static final double CM_PER_INCH = 2.54; }
如果一个常量被声明为public,那么其他类的方法也可以使用这个常量。
运算符:
使用strictfp关键字标记的方法必须使用严格的浮点计算来产生理想的结果:
public static strictfp void main(String[] args)
于是,在main方法中的所有指令都将使用严格的浮点计算。
如果将一个类标记为strictfp,这个类中的所有方法都要使用严格的浮点计算。
位运算:
>>>运算符将用0填充高位;>>运算符用符号位填充高位。没有<<<运算符。
数学函数与常量:
Math类提供的方法:
Math.sqrt(x); Math.pow(x, a);
三角函数:
Math.sin Math.cos Math.tan Math.atan Math.atan2
指数函数/自然对数:
Math.exp Math.log
舍入运算:
Math.round(x);
PI和e常量近似值:
Math.PI Math.E
如果得到一个完全可预测的结果比运行速度更重要的话,应使用StrictMath类。
枚举类型:
enum Size { SMALL, MEDIUM, LARGE, EXTRA_LARGE }; Size s = Size.MEDIUM;
Size类型的变量只能存储这个类型声明中给定的某个枚举值,或者null值,null表示这个变量没有设置任何值。
字符串
Java字符串就是Unicode字符序列:
String greeting = "Hello";
子串:
String greeting = "Hello"; String s = greeting.substring(0, 3); // s is "Hel"
拼接:
String expletive = "Expletive"; String PG13 = "deleted"; String message = expletive + PG13; // message is "Expletivedeleted"
当一个字符串与一个非字符串的值进行拼接时,后者被转换成字符串。
不可变字符串:
String类没有提供用于修改字符串的方法。
检测字符串是否相等:
s.equals(t)
s与t相等,返回true,否则返回false。
字符串常量可用:
"Hello".equals(greeting)
不需区分大小写时,可用:
"Hello".equalsIgnoreCase("hello")
不能使用“==”判断字符串相等。该运算符只能确定两个字符串是否放置在用一个位置上。
String greeting = "Hello"; if (greeting == "Hello") ... // probably true if (greeting.substring(0, 3) == "Hel") ... // probably false
代码点与代码单元:
大多数常用Unicode字符使用一个代码单元就可表示,而辅助字符需要一对代码单元表示。
length方法返回采用UTF-16编码表示的字符串所需的代码单元数量:
String greeting = "Hello"; int n = greeting.length(); // is 5.
若想获得实际长度,即代码点数量,可以调用:
int cpCount = greeting.codePointCount(0, greeting.length());
调用s.charAt(n)将返回位置n的代码单元:
char first = greeting.charAt(0); // first is 'H' char last = greeting.charAt(4); // last is 'o'
若想得到第i个代码点,应使用:
int index = greeting.offsetByCodePoints(0, i); int cp = greeting.codePointAt(index);
遍历字符串,且依次查看每一个代码点:
int cp = sentence.codePointAt(i); if (Character.isSupplementaryCodePoint(cp)) i += 2; else i++;
可以使用下列语句实现回退:
i--; int cp = sentence.codePointAt(i); if (Character.isSupplementaryCodePoint(cp)) i--;
构建字符串:
使用较短的字符串构建字符串。采用字符串连接的方式效率较低。应使用字符串构建器:
StringBuilder builder = new StringBuilder(); builder.append(ch); // appends a single character builder.append(str); // appends a string
需要构建字符串时调用toString方法:
String completedString = builder.toStrng();
输入输出
读取输入:
首先构造一个Scanner对象,并与“标准输入流”System.in进行关联:
Scanner in = new Scanner(System.in);
现在,就可以使用Scanner类的方法实现输入操作:
System.out.print("What's your name? "); String name = in.nextLine(); // 读取整行
希望读取一个单词(以空白符作为分隔符),可用next:
String firstName = in.next();
希望读取整数,可用nextInt:
System.out.print("How old are you? "); int age = in.nextInt();
希望读取浮点数,可用nextDouble。
Scanner类定义在java.util包中。因此需在程序开始加入:
import java.util.*;
Scanner类不适用于从控制台读取密码。可用Console类实现:
Console cons = System.console(); String username = cons.readLine("User name: "); char[] passwd = cons.readPassword("Password: ");
安全起见,密码存放在一维字符数组中,而不是字符串中。
格式化输出
可用System.out.print(x)将数值x输出到控制台:
double x = 1000.0 / 3.0; System.out.print(x);
输出:
3333.3333333333335
类似C语言,可用printf来格式化输出。
转换符 类型 举例
d
十进制整数
159
x
十六进制整数
9f
o
八进制整数
237
f
定点浮点数
15.9
e
指数浮点数
1.59e+01
g
通用浮点数
—
a
十六进制浮点数
0x1.fccdp3
s
字符串
Hello
c
字符
H
b
布尔
True
h
散列码
42628b2
tx
日期时间
—
%
百分号
%
n
与平台有关的行分隔符
—
用于printf的标志:
标志 | 目的 | 举例 |
---|---|---|
+ | 打印符号 | +3333.33 |
空格 | 正数前添加空格 | | 3333.33| |
0 | 数字前补0 | 003333.33 |
- | 左对齐 | |3333.33 | |
( | 负数括在括号内 | (3333.33) |
, | 添加分组分隔符 | 3,333.33 |
#(对于f格式) | 包含小数点 | 3,333 |
#(对于x或0格式) | 添加前缀0x或0 | 0xcafe |
$ | 给定被格式化的参数索引 | 159 9F |
< | 格式化前面说明的数值 | 159 9F |
$举例:%1$d,%1$x将以十进制和十六进制格式打印第一个参数。
<举例:%d%<x以十进制和十六进制打印同一个数值。
可使用s转换符格式化任意对象。
可使用静态的String.format方法创建一个格式化的字符串,而不打印输出:
String message = String.format("Hello, %s. Next year, you'll be %d. ", name, age);
日期和时间转换符
以t开始。例:
System.out.printf("%1$s %2$tB %2$te %2$tY", "Due date:", new Date());
打印:
Due date: 一月 11 2013
注:参数索引值从1开始,不是0。
文件输入输出
希望对文件读取,需要用一个File对象构造一个Scanner对象:
Scanner in = new Scanner(new File("myfile.txt"));
文件名中若包含反斜杠符号,则需要double反斜杠,如“c:\\mydirectory\\myfile.txt”。
希望写入文件,需要构造一个PrintWriter对象:
PrintWriter out = new PrintWriter("myfile.txt");
应告知编译器:已经知道有可能出现“找不到文件”的异常:
public static void main(String[] args) throws FileNotFoundException { Scanner in = new Scanner(new File("myfile.txt")); ... }
控制流程
不能在嵌套的两个块中声明同名的变量(不同类型也不可以)。
大数值
java.math包提供两个类BigInteger和BigDecimal,以解决证书和浮点数精度不够的问题。BigInteger实现任意精度整数运算,BigDecimal实现任意精度浮点数运算。
静态ValueOf方法可将普通数值转为大数值:
BigInteger a = BigInteger.valueOf(100);
不能使用常用算术运算福,而需要使用add和multiply方法。
数组
下面声明了整型数组a:
int[] a;
这条语句只声明了变量a,没有初始化为真正数组。创建数组使用new:
int[] a = new int[100];
可使用array.length获得数组中元素个数。
For each循环
for (variable : collection) statement
例如:
for (int element : a) System.out.println(element);
创建数组并同时赋初值的简写方式(不需用new):
int[] smallPrimes = { 2, 3, 5, 7, 11, 13 };
初始化匿名数组:
new int[] { 17, 19, 23, 29, 31, 37 };
这种语法形式可在不创建新变量的情况下重新初始化一个数组:
smallPrimes = new int[] { 17, 19, 23, 29, 31, 37};
相当于:
int[] anonymous = { 17, 19, 23, 29, 31, 37}; smallPrimes = anonymous;
Java允许数组长度为0。(0和null不同)
数组拷贝
int[] luckyNumbers = smallPrimes; luckyNumbers[5] = 12; // now smallPrimes[5] is also 12
这时,两个变量将引用同一个数组。(类似C++的引用?)
若希望进行值拷贝,需使用Array类的copyOf方法:
int[] copiedLuckyNumbers = Arrays.copyOf(luckyNymbers, luckyNumbers.length); // 参数2表示数组长度
这个方法通常用来增加数组大小:
luckyNumbers = Arrays.copyOf(luckyNumbers, 2 * luckyNumbers.length); // 数组大小变为原来的2倍
若数组元素为数值型,多余元素将被赋值为0。若为布尔型,则为false。
若长度小于原始数组长度,则只拷贝最前面的元素。
可用System类的arraycopy方法拷贝一个数组的部分元素拷贝到另一个数组:
System.arraycopy(from, fromIndex, to, toIndex, count);
Java中的[]运算符被预定义为检查数组边界,而且没有指针运算,即不能通过将数组名加1得到数组的下一个元素。
命令行参数
Java的main方法中,程序名没有存储在args数组中。args[0]即为第一个参数。
数组排序
可用Arrays类的sort方法(优化的快排):
int[] a = new int[10000]; ... Arrays.sort(a);
随机数
Math.random方法将返回一个[0, 1)之间的随即浮点数。用n乘以这个浮点数,即可获得0到n-1之间的随机数。
多维数组
double[][] balances;
在调用new对多维数组初始化前不能使用它。
初始化1:
balances = new double[NYEARS][NRATES]
初始化2:
int[][] magicSquare = { { 16, 3, 2, 13 }, { 5, 10, 11, 8 }, { 9, 6, 7, 12 }, { 4, 15, 14, 1} };
注1:必须使用括号将多组数据分隔开。
注2:for each循环不能处理二维数组,若想访问所有元素,必须嵌套2个for each:
for (double[] row : a) for (double value : row) do something with value
若想快速输出二维数组,可调用:
System.out.println(Arrays, deepToString(a));
输出格式为:
[[16, 3, 2, 13], [5, 10, 11, 8], [9, 6, 7, 12], [4, 15, 14, 1]]
多维数组交换两行:
double[] temp = balances[i]; balances[i] = balances[i + 1]; balances[i + 1] = temp;
不规则数组(数组的每一行有不同长度)
1. 分配一个具有所含行数的数组:
int[][] odds = new int[NMAX + 1][];
2. 分配每一行:
for (int n = 0; n <= NMAX; n++) odds[n] = new int[n + 1];