package hello;
public class FirstSample
{
public static void main(String[]args)
{
System.out.println("Hello World!");
}
}
源代码的文件名必须与公共类的文件名相同。
main方法必须声明为public
如果希望在终止程序时返回其他代码, 需要调用System.exit方法。
C#中文件注释为///, java中文件注释为以/**开始, */结束。
数据类型
整型
int, short, long, byte(1字节)
前缀加上0b可表示二进制数
浮点类型
float, double
有三个表示出错的浮点数值:
- Double.POSITIVE_INFINITY 正无穷大
- Double.NEGATIVE_INFINITY 负无穷大
- Double.NaN 不是一个数字
不能用如下语句判断:
if (x == Double.NaN)
所有非数值的值都认为是不相等的
可以使用
if (Double.isNaN(x))
char类型
java中char类型描述了UTF-16编码中的一个代码单元(code unit)
boolean 类型
只有true, false两个值
变量
在c++中, int i = 10 是一个定义
而 extern int i 是一个声明
java中不区分声明和定义
常量
java中用关键词final指示常量
运算符
对于浮点运算, 可在方法之前使用strictfp关键字标记, 使其使用严格的浮点运算
public static strictfp void main(String args[])
数学函数与变量
Math类中可以调用各种数学函数
public class FirstSample
{
public static void main(String[]args)
{
double x = 4;
double y = Math.sqrt(x);
System.out.println(y);
}
}
floorMod解决了负数取余的问题.
floorMod(position + adjustment, 12)(对于负除数, floorMod仍会得到负数结果)
Math.sin
Math.cos
Math.tan
Math.atan
Math.atan2
Math.exp
Math.log
Math.log10
Math.PI
Math.E
对于这些默认定义的类, 可以使用静态引入
import static java.lang.Math.*;
import static java.lang.Math.*;
public class FirstSample
{
public static void main(String[]args)
{
double x = 4;
double y = sqrt(x);
System.out.println(y);
}
}
Math类中, 所有的方法都使用计算机浮点单元中的例程, 如果得到一个准确的结果更重要, 那么应该使用StrictMath类, 使用fdlibm实现算法, 以确保在所有平台得到相同的结果。
数值类型之间的转换
int转换成double类型不会损失精度
强制类型转换
double x= 9.997;
int nx = (int)x;
对浮点数进行舍入运算用Math.round方法
double x = 9.997;
int nx = (int) Math.round(x);
round方法返回的结果是long类型, 仍需要强制类型转换
位运算符
运算符>>>会用0填充高位, 而>> 会用符号位填充高位
枚举类型
enum Size {SMALL, MEDIUM, LARGE, EXTRA_LARGE};
Size t = Size.MEDIUM;
字符串
String e = ""; //an empty string
String greeting = "Hello";
子串
String类中的substring方法可以从一个较大的字符串中提取出来一个子串
String greeting = "Hello";
String s = greeting.substring(0, 3);
创建s为由字符“Hel”组成的字符串。
拼接
java允许使用+号进行字符串的拼接。
不可变字符串
String类中没有提供修改字符串的方法, java文档中称String类对象为不可变字符串, 不过可以通过修改字符串变量, 使其引用其它字符串。
greeting = greeting.substring(0, 3) + "p!";
java中字符串相当于char* 指针.
检测字符串是否相等
使用equals方法
s.equals(t)
相等返回true, 否则返回false
java中的compareTo则完全与C中的strcmp类似
if (greeting.compareTo("Hello") == 0)...
空串和NULL串
空串是长度为0的字符串, 可调用如下代码进行检查
if (str.length() == 0)
或
if (str.equals(""))
null串表示目前没有任何对象与该变量关联
判断使用如下代码:
is(str == null)
码点与代码单元
大多数常用Unicode字符使用一个代码单元就可以表示, 而辅助单元需要一对代码单元
实际的码点数量可以调用
String greeting = "Hello";
int cpCount = greeting.codePointCount(0, greeting, length());
调用s.charAt(n)将返回位置n的代码单元
char first = greeting.charAt(0);
char last = greeting.charAt(4);
要想得到第i个码点
int index = greeting.offsetByCodePoints(0, i); // 偏移i个码点
int cp = greeting.codePointAt(index);
该字符需要两个代码单元, 调用charAt()时请注意
如果想遍历一个字符串, 并依次查看每一个码点, 可使用如下代码
int cp = sentence.codePointAt(i);
if(Character.isSupplementaryCodePoing(cp)) i += 2;
else i++;
使用如下语句实现回退操作:
i--;
if (character.isSurrogate(sentence.charAt(i))) i--;
int cp = sentence.codePointAt(i);
更容易的方法是使用codePoints方法, 其生成一个int值的“流”, 每个int对应一个码点, 可以将其转换为一个数组, 再完成遍历。
int [] codePoints = str.codePoints().toArray();
反之, 可以使用构造函数
String str = new String(codePoints, 0, codePoints.length);
构建字符串
使用StringBuilder类可以用多个较短字符串来构建字符串
StringBuilder builder = new StringBuilder();
builder.append(ch);
builder.append(str);
String completedString = builder.toString();
StringBuffer和StringBuilder的API是相同的, 但StringBuffer支持多线程, 效率稍低。
输入输出
读取输入
首先需要构建一个Scanner对象, 并与System.in关联
Scanner in = new Scanner(System.in);
System.out.print("What is your name?");
String name = in.nextLine();
nextLine方法可以实现C中gets函数的效果。
要想读取一个整数, 则调用nextInt方法
System.out.print("How old are you?");
int age = in.nextInt();
要想读取浮点数, 则使用nextDouble方法。
Scaner类定义在java。util包中, 当时用的类不是定义在java.lang包中时, 必须使用import
import java.util.*;
public class InputTest
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
// get first input
System.out.print("What is your name?");
String name = in.nextLine();
//get second input
System.out.print("How old are you?");
int age = in.nextInt();
System.out.println("Hello" + name + ". Next you will be " + (age + 1));
}
}
Console类实现了从控制台读取密码
import java.io.Console.*;
Console cons = System.console();
String username = cons.readLine("User name:");
char[] passwd = cons.readPasswword("Password:");
格式化输出
-
用于printf的标志
-
+:打印正数和负数的符号
空格: 证书之前追加空格
0: 数字前面补0
-: 左对齐
( : 将负数括在括号内
, : 添加分组分隔符
#(对于f格式): 包含小数点
#(对于x或o格式): 添加前缀0x或0
$ : 给定被格式化的参数索引, 输出。(%1$d , %1 $x)
< : 格式化前面说明的字符(%d%<x)
可以使用静态的String。format方法创建一个格式化的字符串, 而不打印输出
String message = String.format("Hello, %s . Next you will be %d", name, age);
-
日期和时间的转换符
-
c : 完整的日期和时间 Mon Feb 09 18:05:19 PST 2015
F: ISO 8601 日期 2021-04-26
D: 美国格式时间 02/09/2019
T: 24小时时间 18:05:19
r: 12小时时间 06:05:19 pm
R: 24小时时间没有秒 18:05
Y: 4位数字的年(前面补0) 2021
y: 年的前两位数字(前面补零) 21
C: 年的后两个数字(前面补零) 20
B: 月的完整缩写 April
b或h: 月的缩写 Apr
m : 两位数字的月 04
d:两位数字的日(前面补0) 26
e: 两位数字的日(前面不补零) 26
A: 星期几的完整拼写 Monday
a: 星期几的缩写 Mon
j: 三位数的年中的日子(前面补0) 116
H: 两位数字的小时(前面补0) 18
k: 两位数字的小时(前面不补零) 18
I: 两位数字的小时(前面补0, 12进制) 06
l: 两位数字的小时 (前面不补零, 12进制) 6
M:两位数字的分钟 (前面补零) 05
S:两位数字的秒(前面补0) 19
L: 三位数字的毫秒(前面补0) 047
N: 九位数字的毫微秒(前面补0) 047000000
p: 上午或下午的标志 pm
z: 从GMT 起, RFC822数字位移 +0800
Z: 时区 CST
s: 从格林威治时间1970-01-01 00:00:00 起的秒数 1619435298
Q: 从格林威治时间1970-01-01 00:00:00起的毫秒数 1619435298047
System.out.printf("%1$s %2$tB %2$te, %2$tY","Due Date:" , new Date());
还可以使用< 标志
System.out.printf("%s %tB %<te, %<tY","Due Date:" , new Date());
文件输入与输出
若想进行读取需要用一个File对象构造一个Scanner对象
Scanner in = new Scanner(Path.get("myfile.txt"), "UTF-8");
要想写入文件, 需要构造PrintWrite对象, 在构造器中, 只需要提供文件名
PrintWriter out = new PrintWriter("myfile.txt", "UTF-8");
完成之后记得关闭文件流, 不然不会保存写入内容
out.close();
如果用一个不存在的文件构造Scanner, 或者用一个不能被创建的文件名构造一个PrintWriter, 那么就会发生异常, 这需要在main方法中用子句throws标记
public static void main(String[] args) throws IOException
{
Scanner in = new Scanner(Paths.get("myfile.txt"), "UTF-8");
...
}
API
-
java.util.Scanner
-
Scanner(File source)
Constructs a new Scanner that produces values scanned from the specified file.
Scanner(String source)
Constructs a new Scanner that produces values scanned from the specified string.
java.io.PrintWriter
-
PrintWriter(String fileName)
Creates a new PrintWriter, without automatic line flushing, with the specified file name.
java.nio.file.Paths
-
static Path get(String first, String… more)
Converts a path string, or a sequence of strings that when joined form a path string, to a Path.
控制流程
与C语言不同, 不能在嵌套的块中声明同名变量
import java.util.*;
/**
* This program demonstrates a <code>while<code> loop.
* @author Cay Horstmann
*@writeby Saigyoujinexas
*/
public class Retirement
{
public static void main(String[] args)
{
//read inputs
Scanner in = new Scanner(System.in);
System.out.print("How much money do you need to retire?");
double goal = in.nextDouble();
System.out.print("How much money will you contribute every year?");
double payment = in.nextDouble();
System.out.print("Interest rate in %:");
double interestRate = in.nextDouble();
double balance = 0;
int years = 0;
//update account balance while goal is not reached
while (balance < goal)
{
//add this year's payment and interest
balance += payment;
double interest = balance * interestRate / 100;
balance += interest;
years++;
}
System.out.println("You can retire in " + years + " years.");
}
}
import java.util.*;
/**
* This program demonstrates a <code>while<code> loop.
* @author Cay Horstmann
*@writeby Saigyoujinexas
*/
public class Retirement2
{
public static void main(String[] args)
{
//read inputs
Scanner in = new Scanner(System.in);
System.out.print("How much money will you contribute every year?");
double payment = in.nextDouble();
System.out.print("Interest rate in %:");
double interestRate = in.nextDouble();
double balance = 0;
int year = 0;
String input;
//update account balance while goal is not reached
do
{
//add this year's payment and interest
balance += payment;
double interest = balance * interestRate / 100;
balance += interest;
year++;
//print current balance
System.out.printf("After year %d, your balance is %,.2f%n", year, balance);
// ask if ready to retire and get input
System.out.print("Ready to retire?(Y / N)");
input = in.next();
}while(input.equals("N"));
}
}
对于switch循环, 必须有break语句
如果故意使用直通式(fallthrough)行为
在其外围方法加个标注 @SuppressWarnings(“fallthrough”)
中断控制流程语句
java提供了一种** 带标签的break语句**
Scanner in = new Scanner(system.in);
int n;
read_data:
while(...)
{
for(...)
{
System.out.print("Enter a number >= 0");
n = in.nextInt();
if(n < 0) // should never happen-can't go on
break read_data;
//break out of read_data loop
...
}
}
// this statement is excuted immediately after the labeld break
if (n < 0) // check for bad situation
{
//deal with bad situation
}
else
{
//carry out normal processing
}
该标签可以应用到任何语句, 甚至是if语句或块语句中
label:
{
...
if (condition) break label; // exit block
}
continue语句同样可带标签, 将跳转到与标签匹配的循环首部
大数值
java中两个很有用的类:BigInteger和Bigdecimal。
使用静态的valueOf方法可以将普通数值转换为大数值。
BigInteger a = BigInteger.valueOf(100);
不能使用运算符对大数值进行运算
需要使用add和multiply方法
BigInteger c = a.add(b);
BigInteger d = c.multiply(b.add(BigInteger.valueOf(2)));
java不提供运算符重载功能
import java.math.*;
import java.util.*;
/**
* This program uses big numbers to compute the odds of winning the grand prize in a lottery.
* @author Cay Horstmann
*/
public class BigIntegerTest
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
System.out.print("How many numbers do you need to draw?");
int k = in.nextInt();
System.out.print("What is the highest number you can draw? ");
int n = in.nextInt();
/*
*compute binomial coeffcient n*(n - 1)*(n-2)*(n-3)*...*(n-k+1)/(1*2*3*4*...*k)
*/
BigInteger lotteryOdds = BigInteger.valueOf(1);
for (int i = 1; i <= k; i++)
{
lotteryOdds = (lotteryOdds.multiply(BigInteger.valueOf(n - i + 1)).divide(BigInteger.valueOf(i)));
System.out.println(lotteryOdds);
}
System.out.println("Your odds are 1 in " + lotteryOdds + ". Good luck!");
}
}
API
-
java.math.BigInteger
-
BigInteger add(BigInteger val)
Returns a BigInteger whose value is (this+val).
BigInteger subtract(BigInteger val)
Returns a BigInteger whose value is (this - val).
BigInteger multiply(BigInteger val)
Returns a BigInteger whose value is (this * val).
BigInteger divide(BigInteger val)
Returns a BigInteger whose value is (this / val).
BigInteger mod(BigInteger m)
Returns a BigInteger whose value is (this mod m).
int compareTo(BigInteger val)
Compares this BigInteger with the specified BigInteger.
static BigInteger valueOf(long val)
Returns a BigInteger whose value is equal to that of the specified long.
java.math.BIgDecimal
-
BigDecimal add(BigDecimal augend)
Returns a BigDecimal whose value is (this + augend), and whose scale is max(this.scale(), augend.scale()).
BigDecimal subtract(BigDecimal subtrahend)
Returns a BigDecimal whose value is (this - subtrahend), and whose scale is max(this.scale(), subtrahend.scale()).
BigDecimal multiply(BigDecimal multiplicand)
Returns a BigDecimal whose value is (this × multiplicand), and whose scale is (this.scale() + multiplicand.scale()).
BigDecimal divide(BigDecimal divisor,RoundingMode roundingMode)
Returns a BigDecimal whose value is (this / divisor), and whose scale is this.scale().
int compareTo(BigDecimal val)
Compares this BigDecimal with the specified BigDecimal.
static BigDecimal valueOf(long val)
Translates a long value into a BigDecimal with a scale of zero.
static BigDecimal
valueOf(long unscaledVal, int scale)
Translates a long unscaled value and an int scale into a BigDecimal.
数组
int a[];
该语句仅声明了变量还需要初始化
int [] a = new int[100];
创建字符数组时所有元素初始化为0。
获得数组元素数量可以使用array.length.
for (int i = 0; i < a.length; i++)
System.out.println(a[i]);
for each循环
for (variable: collection) statement
定义一个变量用于暂存集合中的每一个元素并执行相应的语句
collection集合表达式必须是一个数组或者是一个实现了Iterable接口的类对象
for (int element: a)
System.out.println(element);
等价于
for (int i = 0; i < a.length; i++)
System.oout.println(a[i]);
但是for each 循环更为简洁
有个更简单的方式打印一个集合的所有元素, 即使用Arrays类中的toString 方法, 返回被放置在方括号内的数组元素, 用逗号分隔。
System.out.println(Arrays.toString(a));
数组初始化及匿名数组
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 [] luckNumbers = smallPrimes;
luckNumber[5] = 12 // now smallPrimes[5] is also 12
如果希望是进行拷贝而不是引用同一个数组, 使用Arrays类的copyOf方法
int [] copiedLuckNumbers = Arrays.copyOf(luckNumbers, 2 * luckNumbers.length);
第二个参数是新数组的长度, 故该方法可以用来增加数组长度
luckNumbers = Arrays.copyOf(luckNumbers, 2 * luckNumbers.length);
java基本上与C++分配在堆上的数组指针一致
命令行参数
public class Message
{
public static void main(String[] args)
{
if (args.length == 0 || args[0].equals("-h"))
System.out.print("Hello,");
else if (args[0].equals("-g"))
System.out.print("Goodbye.");
for (int i = 1; i < args.length; i++)
System.out.print(" " + args[i]);
System.out.println("!");
}
}
在java程序中, 程序名不存在args数组中
数组排序
数值型数组使用Arrays类中的sort方法
int [] a= new int[1000];
...
Arrays.sort(a)
该方法使用优化的快速排序算法
import java.util.*;
/**
* This program demonstrates array manipulation.
* @author Cay Horstmann
*/
public class LotteryDrawing
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
System.out.print("How many numbers do you need to draw? ");
int k = in.nextInt();
System.out.print("What is the highest number you can draw? ");
int n = in.nextInt();
//file an array with number 1, 2, 3, 4, ...
int [] numbers = new int[n];
for (int i = 0; i < numbers.length; i++)
numbers[i] = i + 1;
//draw k numbers and put them into a second array
int[] result = new int[k];
for (int i = 0; i < result.length; i++)
{
//make random index between 0 and n - 1
int r = (int) (Math.random() * n);
// pick the element at the random location
result[i] = numbers[r];
//move the last element into the random location
numbers[r] = numbers[n - 1];
n--;
}
// print the sorted array
Arrays.sort(result);
System.out.println("Bet the following combination. It will make you rich!");
for (int r: result)
System.out.println(r);
}
}
Math.random方法将生成一个0到1的浮点数。
API
-
java.util.Arrays
-
static String toString(Type[] a)
Returns a string representation of the contents of the specified array.
Type could be int, short, byte, boolean, long, char, float, double or object
static Type[] copyOf(Type [] original, int newLength)
Copies the specified array, truncating or padding with zeros (if necessary) so the copy has the specified length.
Type could be byte, short, int, long , boolean, char, float, double, T.
static boolean[] copyOfRange(boolean[] original, int from, int to)
Copies the specified range of the specified array into a new array.
Type could be byte, short, int, long, boolean, char, float, double, T.
static void sort(Type[] a, int fromIndex, int toIndex)
Sorts the specified range of the array into ascending order.
Type could be byte, short, int , long , boolean, char, float, double , T.
fromIndex and toIndex are optional.
static Type binarySearch(Type[] a, int fromIndex, int toIndex, Type key)
Searches the specified array of bytes for the specified value using the binary search algorithm.
Type could be byte, short, int , long , boolean, char, float, double , T.
fromIndex and toIndex are optional.
static void fill(Type[] a, int fromIndex, int toIndex, Type val)
Assigns the specified float value to each element of the specified range of the specified array of floats.
Type could be byte, short, int , long , boolean, char, float, double , object.
fromIndex and toIndex are optional.
static boolean equals(Type[] a, int aFromIndex, int aToIndex, Type[] b, int bFromIndex, int bToIndex)
Returns true if the two specified arrays of shorts, over the specified ranges, are equal to one another.
Type could be byte, short, int , long , boolean, char, float, double , object, T.
aFromIndex, aToIndex, bFromIndex and bToIndex are optional.
多维数组
double [][] balances;
同样, 在初始化完成后才能使用
balances = new double[NYEARS][NRATES]
int magicSquare =
{
{16, 3, 2, 13},
{5, 10, 11, 8},
{9, 6, 7, 12},
{4, 15, 14, 1}
};
for each 循环不能自动处理二维数组每个元素
for (double[] row: a)
for (double value: row)
do something with value
要想快速打印一个二维数组, 可以调用
System.out.println(Arrays.deepToString(a));
/**
* This program shows how to store tabular data in a 2D array.
* @author Cay Horstmann
*/
public class CompoundInterest
{
public static void main(String[] args)
{
final double STARTRATE = 10;
final int NRATES = 6;
final int NYEARS = 10;
//set interest rates to 10.....15%
double[] interestRate = new double[NRATES];
for (int j = 0; j < interestRate.length; j++)
interestRate[j] = (STARTRATE + j) / 100.0;
double [][] balances = new double[NYEARS][NRATES];
//set initial balances to 10000
for (int j = 0; j < balances[0].length; j++)
balances[0][j] = 10000;
//compute interest for future years
for (int i = 1; i < balances.length; i++)
{
for (int j = 0; j < balances[i].length; j++)
{
//get last year's balances from previous now
double oldBalance = balances[i - 1][j];
//compute interest
double interest = oldBalance * interestRate[j];
//compute this year's balances
balances[i][j] = oldBalance + interest;
}
}
//print one row of interest rates
for (int j = 0; j < interestRate.length; j++)
System.out.printf("%9.0f%%", 100 * interestRate[j]);
System.out.println();
//print balance table
for (double[] row: balances)
{
for (double b: row)
System.out.printf("%10.2f", b);
System.out.println();
}
}
}
不规则数组
java实际上没有多维数组, 多维数组被解释为数组的数组
int[][] odds = new int[NMAX + 1][];
for (int n = 0; n <= NMAX; n++)
odds[n] = new int[n + 1];
分配数组后, 就可以采用通常的方式进行访问
for (int n = 0; n < odds.length; n++)
for (int k = 0; k < odds[i].length; k++)
{
//compute lotteryOdds;
...
odds[n][k] = lotteryOdds;
}
double[][] balances = new double[10][6];
该声明等同于C++中
double** balances = new double*[10];
for (int i = 0; i < 10; i++)
balances[i] = new double[6];
实例
杨辉三角打印
/**
* This program demostrates a triangular array.
* @author Cay Horstmann
*/
public class lotteryArray
{
public static void main(String[] args)
{
final int NMAX = 10;
//allocate triangular array
int[][] odds = new int[NMAX + 1][];
for (int n = 0; n <= NMAX; n++)
odds[n] = new int[n + 1];
//fill triangular array
for(int n = 0; n < odds.length; n++)
for(int k = 0; k < odds[n].length; k++)
{
/*
*compute binomial coefficient n*(n-1)*(n-2)*...*(n-k+1)/(1*2*3*...*k)
*/
int lotteryOdds = 1;
for (int i = 1; i <= k; i++)
lotteryOdds = lotteryOdds * (n-i + 1) / i;
odds[n][k] = lotteryOdds;
}
//print triangular array
for (int[] row: odds)
{
for (int odd : row)
System.out.printf("%4d", odd);
System.out.println();
}
}
}
算法优化:
/**
* This program demostrates a triangular array.
* @author Cay Horstmann
*/
public class lotteryArray
{
public static void main(String[] args)
{
final int NMAX = 10;
//allocate triangular array
int[][] odds = new int[NMAX + 1][];
for (int n = 0; n <= NMAX; n++)
{
odds[n] = new int[n + 1];
odds[n][0] = 1;
odds[n][n] = 1;
}
//fill triangular array
for(int n = 1; n < odds.length; n++)
for(int k = 1; k < odds[n].length - 1; k++)
odds[n][k] = odds[n - 1][k - 1] + odds[n - 1][k];
//print triangular array
for (int[] row: odds)
{
for (int odd : row)
System.out.printf("%4d", odd);
System.out.println();
}
}
}