Java 语法笔记

Posted by WHZ0325 on 2023-01-11, Viewed times

版本问题

写这篇笔记时 Oracle 官网上的最新的 JDK 版本是 Java 19,兼容 Apple Silicon,然而目前最常用的 Java 8 和 Java 11 还没有适配,可以使用 Zulu JDK,关于如何配置 Sublime Text 3 快速编写简单的 Java 程序可以参考 如何在 macOS 下配置 Sublime Text 的可交互 Java 环境,集成开发环境推荐 IntelliJ IDEA。

编译运行

过程:代码编译成字节码(可以在 Java CPU 上运行),经 JVM 再转变为机器指令。

编译:javac file_name.java

运行:java file_name

打包:jar cvf file_name.jar *.*

注意:一个文件只能有一个 public class,且类名与文件名一致。

输入输出

标准
1
2
3
4
5
6
7
import java.util.Scanner;//注意分号
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println(in.nextLine());
}
}

in.next():读入一个字符串。

in.nextLine():读入一行,返回一个字符串。

可以使用 hasNextInt() 等方法来预判(以通过 while 循环读取任意数量的数据):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.util.Scanner;
public class test {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
if(in.hasNextInt()) {
int i = in.nextInt();
System.out.printf("The next integer is %d.\n",i);
}
else System.out.println("The next integer does not exist.");
}
}
/*
输入:
3.14
输出:
The next integer does not exist.
*/
/*
输入:
3
输出:
The next integer is 3.
*/
快读

关于字节流和字符流相关:待填坑。(StreamTokenizer)

1
2
3
4
5
6
7
8
9
10
11
import java.io.*;
public class test {
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
Integer n = Integer.parseInt(in.readLine());// read() 方法读取字符
out.write(n.toString());// 可以使用 String.format("") 方法
out.newLine();
out.flush();
}
}
  • 导入 java.io.*,主函数 throws IOException
  • BufferedReaderBufferedWriter 使用 InputStreamReaderOutputStreamWriter 初始化。
  • 输出后刷新缓冲区 flush()

【Kattio】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.io.*;
class Kattio extends PrintWriter {
private BufferedReader bf;
private StringTokenizer st;
public Kattio() {
super(System.out);
bf = new BufferedReader(new InputStreamReader(System.in));
}
public String next() {
try {
while(st == null || !st.hasMoreTokens()) {
st = new StringTokenizer(bf.readLine());
}
return st.nextToken();
} catch(Exception e) {}
return null;
}
public int nextInt() { return Integer.parseInt(next()); }
}

注意程序结束时需要执行 io.close()

变量

命名规范
  • 不能以数字开头,可以包含 _$
  • 函数、变量采用峰驼命名法,类、接口首字母大写,常量全部大写。
数据类型

常量使用 final 修饰。(final 方法不允许重写,final 类不允许继承)

基本数据类型(如 intdouble)及强制类型转换,语法与 C++ 类似,但布尔类型的关键字为 boolean

  • 整数常量默认 int,long 类型是 10000000L。
  • 浮点常量默认 double,float 类型是 3.14F。
  • 使用 Unicode 码,字符类型 char 为 16 位(0~65536)。
  • 空:null
  • &| 等在 Java 中也可以用于逻辑运算,不过不短路。
  • + 可以连接字符串。

分为基本数据类型和引用数据类型。

  • 数组是引用数据类型,不是基本数据类型。
  • 对于引用类型,== 比较指向相同,equals() 比较内容相同。
  • 基本类型放在栈中,引用类型放在堆中。
  • Java 只有值传递,引用类型存放的是其指向(指针),故传递的也是其指向。

数组

数组是引用类型而非基本数据类型。

一维数组

定义数组:int[] a = new int[100];,数组的元素个数可以为变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] a = new int[n];
for(int i = 0; i < n; ++i) a[i] = i;
for(int i = 0; i < n; ++i) {
System.out.print(a[i] + ((i == n - 1)?"\n":" "));
}
}
}
/*
输入:10
输出:0 1 2 3 4 5 6 7 8 9
*/

可以使用 a.length 访问数组大小,数组中元素默认为 $0$。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] a = new int[n];
for(int i = 0; i < n / 2; ++i) a[i] = i;
for(int i = 0; i < a.length; ++i) {
System.out.print(a[i] + ((i == n - 1)?"\n":" "));
}
}
}
/*
输入:10
输出:0 1 2 3 4 0 0 0 0 0
*/

初始化:

  • int[] a = {0, 1, 2, 3, 4, 5};

  • 初始化:a = new int[]{0, 1, 2, 3, 4, 5};

  • 维表达式:a = new int[6];

而这样是错误的 a = new int[6]{0, 1, 2, 3, 4, 5};,不能同时用维表达式和初始化创建数组。

二维数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Scanner in = new Scanner(System.in);
int n = in.nextInt(), m = in.nextInt();
/* 使用变量定义二维数组 */
int[][] a = new int[n][m];
for(int i = 0, cnt = 1; i < n; ++i) {
for(int j = 0; j < m; ++j) {
a[i][j] = cnt++;
}
}
/* 使用 for-each 访问二维数组 */
for(int[] b: a) {
for(int c: b) {
System.out.print(c + " ");
}
System.out.println();
}
1
2
3
4
5
6
7
8
9
10
11
12
/* 初始化 */
int[][] a = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
/* 使用 length 访问二维数组 */
for(int i = 0; i < a.length; ++i) {
for(int j = 0; j < a[i].length; ++j) {
a[i][j] = 0;
}
}

允许不规则数组:

1
2
3
4
int arr[][] = new int[3][];
arr[0] = new int[2];
arr[1] = new int[3];
arr[2] = new int[5];
Arrays

java.util.Arrays

数组拷贝:int[] dest = Arrays.copyOf(src, src.length)

数组排序

  1. 引入:import java.util.Arrays;
  2. 基本用法:Arrays.sort(a); 对数组 a 进行递增排序。
  3. 时间复杂度:$O(nlog_2n)$。
  4. 指定排序范围:Arrays.sort(a, 0, 5); 对数组 a 的前 6 个元素进行排序。
  5. 自定义排序规则:实现 Comparable 接口,实现 public int compareTo(Object o) 方法;创建实现 Comparator 接口的类,实现 public int compare(Object a, Object b) 方法。

数组查找:int loc = Arrays.binarySearch(src, element);

注释

用法与 C++ 类似。

分支

if 语句和 switch 语句与 C++ 类似。

就近原则:

1
2
3
if()
if() {}
else {}

等同于

1
2
3
4
if() {
if() {}
else {}
}

也就是说,第一部分代码中的 else 无视缩进,与第二个 if 形成一组。

switch 语句中的 default 不是必要的。

循环

while 语句和 do-while 语句与 C++ 类似。

for 语句与 C++ 类似,可使用 break 语句和 continue 语句,也可以使用 goto

类似 for-infor-each 遍历数组元素:

1
2
3
for(int x: a) {
System.out.println(x);
}

注意,上述代码中改变 x 的值并不会改变原数组中对应项的值(引用类型的数组除外),例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Main {
public static void main(String[] args) {
int[] a = new int[10];
for(int i = 0; i < 10; ++i) {
a[i] = i;
}
for(int x: a) {
x = 0;// 原数组中的值没有被修改
System.out.print(x + " ");
}
System.out.println();
for(int x: a) {
System.out.print(x + " ");
}
System.out.println();
}
}
/*
输出:
0 0 0 0 0 0 0 0 0 0
0 1 2 3 4 5 6 7 8 9
*/

breakcontinue 语句可以给出标号,跳出制定的代码块。

数据类型

字符类型

Java 使用 Unicode 编码,用单引号表示字符,可与 int 相互赋值。

转义字符:\t\b\n\r\\\'\"……

Wrap 类型

将基本类型转化为对象,

1
2
3
4
5
6
7
8
9
// 首字母大写
int -> Integer
short -> Short
long -> Long
float - > Float
double -> Double
boolean -> Boolean
char -> Charater
byte -> Byte

Integer.parseInt(String s, int radix) 方法可以将字符串转化为整数,radix 参数用于指定基数,默认为 10。

类似的还有 Long.parseLong(String s)Double.parseDouble(String s) 等等。

Integer 类型

可自由赋值给 int 类型。

1
2
3
4
5
6
7
8
9
10
11
12
Integer I = Integer(1024);// Java 8
Integer I = Integer.valueOf(1024);// Java 19
System.out.println(I);
int i = I;
System.out.println(i);
/*
输出:
1024
1024
*/
System.out.println(Integer.MIN_VALUE + " " + Integer.MAX_VALUE);
// 输出:-2147483648 2147483647
  • 成员函数 toString()Integer.toString(int i) 方法可返回整数对应的字符串。
  • Integer.MAX_VALUE 返回最大值。
Character 类型
1
2
3
4
5
6
7
8
9
char c = 'C';
System.out.println(Character.isDigit(c));
System.out.println(Character.isLetter(c));
System.out.println(Character.isLetterOrDigit(c));
System.out.println(Character.isLowerCase(c));
System.out.println(Character.isUpperCase(c));
System.out.println(Character.isWhitespace(c));
System.out.println(Character.toLowerCase(c));// 返回改变后的字符,不改变 c 的值
System.out.println(Character.toUpperCase(c));// 返回改变后的字符,不改变 c 的值
String 类型

字符串的连接是从左向右的,例如:

1
2
System.out.println(1 + 2 + "3");// 33
System.out.println("1" + 2 + 3);// 123

判断相等时应当使用 s1.equals(s2),在 Java 中,类的名称类似于指针,使用运算符 == 相当于判断两者是否指向同一对象。

两种声明方式:

1
2
String s = new String("Hello World!");
String s = "Hello World!";

这两种初始化的方式是有所不同的,例如:

1
2
3
4
5
6
String s1 = "Hello";
String s2 = "Hello";
System.out.println(s1 == s2);// true
String s1 = new String("Hello");
String s2 = new String("Hello");
System.out.println(s1 == s2);// false

可见,使用 new 初始化相同内容的字符串时创建了新的对象,这里用到了 Java 中“常量池”的概念。

注意:在 Java 中采用值传递而非引用传递。

一些函数的用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/* compareTo() 在小于时返回 -1,等于时返回 0,大于时返回 1. */
/* compareToIgnoreCase() 无视大小写 */
String s1 = "ABC";
String s2 = "BCD";
System.out.println(s1.compareTo(s2));// -1
/* charAt() */
System.out.println(s1.charAt(0));// A
/* substring() */
System.out.println(s1.substring(1));// BC
/* 区间左闭右开 */
System.out.println(s1.substring(0, 2));// AB
/* indexOf() 不存在返回 -1 */
System.out.println(s1.indexOf('B'));// 1
System.out.println(s1.indexOf('Z'));// -1
/* 第二个参数表示查找的开始位置 */
System.out.println(s1.indexOf('A', 1));// -1
/* lastIndexOf 用法相同,从字符串末尾开始搜索 */
/* 其它函数 */
System.out.println(s1.startsWith("AB"));// true
System.out.println(s1.endsWith("BA"));// true
/* trim() 删去头尾空白符 */
s1 = " ABABA ";
System.out.println(s1.trim());// "ABABA"
System.out.println(s1.replace('A', 'C'));// CBCBC
System.out.println(s1.toLowerCase());// ababa
/* 执行 toLowerCase() 和 toUpperCase() 不改变原字符串的内容 */
Scanner in = new Scanner(System.in);
String s = in.next();
switch(s) {
case "Happy": System.out.println("You are happy.");break;
case "Sad": System.out.println("You are sad.");break;
}

另:可使用 indexOf 进行字符串查找,内部实现为嵌套循环的朴素算法,时间复杂度为 $O(nm)$,但只能返回一个位置,却可以指定查找的起始位置来实现连续查找。

未初始化的 String 不能调用 length() 方法,而初始化为 "" 的 String 调用 length() 会返回数字 0。

split 方法可以对字符串进行拆分,得到拆分后的字符串数组:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.Scanner;
public class test {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String str = in.nextLine();
String s[] = str.split(" ");// 也可以使用 "," 作为分隔符
for(String ss: s) {
System.out.println(ss);
}
}
}
/*
输入:
Hello World Java Programming File
输出:
Hello
World
Java
Programming
File
*/

format 方法可以获得格式化的字符串:

1
2
3
4
5
6
7
8
9
import java.util.Scanner;
public class test {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
double d = in.nextDouble();// 3.1415926
String s = String.format("Double Value is %.7f\n",d);// Double Value is 3.1415926
System.out.print(s);
}
}

(Java 中 float 类型和 double 类型变量都使用 %f 表示,byte 类型、short 类型、int 类型、long 类型都使用 %d 表示)

函数

只能按值传递。

枚举类型

public enum Name { TYPE1, TYPE2, TYPE3 };

Name name = TYPE1 or Name.TYPE1

面向对象

继承性,封装性,多态性。

Type object = new Type();

  • Type object:声明
  • new:实例化
  • Type():初始化

没有析构函数,自动垃圾回收(GC,Garbage Collection)。【finilize() 被 Java 9 弃用】

耦合性(依赖关系)与可扩展性:硬编码 -> 框架+数据。

注意:类的赋值语句并不是对象赋值,而是改变变量管理的对象。

调用成员函数时可以直接使用成员变量名或成员函数名,可不使用 this 指定(若与成员函数某个参数重名则须要指定),this 像指针一样管理着调用成员函数的对象(就像一个快捷方式 )。

成员变量会被给予初始值 $0$,与本地变量(函数中的变量)不同,本地变量不被赋值就使用则编译失败。

创建对象的时候会对所有变量依次初始化,然后调用构造函数(如果存在的话),若有多个构造函数则调用与 new 时参数对应的构造函数。

1
2
3
4
5
6
7
8
9
10
11
public class test {
int x;// 0
test() {}// 构造函数,使用类名,没有返回类型
public void f(int x) {
System.out.println(x);// 1
System.out.println(this.x);// 0
}
public static void main(String[] args) {
test t = new test();t.f(1);
}
}

可以在构造函数中使用 this 调用其它构造函数,例如:

1
2
3
4
5
6
7
8
9
10
11
public class test {
int x;
test() {System.out.println("test");}
test(int x) {
this();
this.x = x;
}
public static void main(String[] args) {
test t = new test(1);
}
}

但是 this() 只能作为该构造函数的第一个语句,否则就会报错:

访问控制

public 属性:public 关键字修饰的类必须在它自己的 java 文件中,即文件名与类名相同。【同一个类,同一个包,子类,不同类不同包非子类】

protected 属性:protected 关键字保证包内的类和子类可以访问。【同一个类,同一个包,子类】

default 属性:默认属性,仅可以在同一个包内访问。【同一个类、同一个包】

private 属性:private 关键字只适用于成员变量和成员函数,仅类中可使用,在类外实例化的对象不可访问(但对于同一个类的私有成员变量,只要代码写在类中,两个不同的对象之间可以相互访问)。【仅同一个类】

package 包
  • 包与目录对应,可以嵌套子目录:package parent.child
  • 开头添加 package package_name; 表明文件属于这个包,使用小写,且只有一条
  • 成员变量、成员函数和类前没有 privatepublic 关键字,则意味着它仅可以在同一个包内访问。
  • import java.lang.*; 默认添加,无需指明。
  • 导入其它包内声明的类:import package_name.class_name;,不选择导入则需要使用 package_name.class_name 作为全名调用包外的类,import package_name.*; 表明导入包内的所有内容。
static 属性

最先初始化。

同一个类的类(静态)变量为所有对象共有,可以使用 object_name.var_name 也可以使用 class_name.var_name 访问,可以称为类变量。

静态函数(用 static 修饰的属性的函数)与静态变量类似,静态函数只能访问类(静态)变量,不能访问成员变量(因为静态函数属于这个类,而成员变量属于一个特定的对象)。

泛型类

ArrayList<String> arr = new ArrayList<String>();,声明 String 类型的容器,否则默认是 Object 类型。

定义:class A<E> { E e; }(如 HashSet)、class B<X, Y> { X x; Y y; }(如 HashMap)。

接口中也可以定义泛型

`` `` 注意:Java 中泛型只能是引用类型(如 `Integer`),不能是基本类型(如 `int`)。 ##### 类数组 1. 基本数据类型的数组中存放数据,类数组中存放管理数据用的“指针”(初始为 `null`)。 2. 对于类数组,修改 `for-each` 语句中 `x` 的值将会影响原数组中的值,例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class I {// 须要写在外面
public int i;
I(int i) {
this.i = i;
}
}
public class Main {
public static void main(String[] args) {
I[] a = new I[10];// 初始化:第一步
for(int i = 0; i < 10; ++i) {
a[i] = new I(i);// 初始化:第二步
}
for(I x: a) {
System.out.print(x.i + " ");
x.i = 0;// 原数组中的值被修改了
}
System.out.println();
for(I x: a) {
System.out.print(x.i + " ");
}
System.out.println();
}
}
/*
输出:
0 1 2 3 4 5 6 7 8 9
0 0 0 0 0 0 0 0 0 0
*/
类的对象名仅仅为指向该对象的指针,赋值时也仅仅是指针的赋值,让两者管理同一个对象:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class I {
public int i;
I(int i) {
this.i = i;
}
}
public class Main {
public static void main(String[] args) {
I a = new I(128);
I b = new I(64);
b = a;
a.i = 32;
System.out.println(b.i);
}
}
/*
输出:
32
*/
##### 继承(`extends`) final 修饰不允许继承。 所有类均默认为 Object 的子类:`toString()`、`equals(Object object)`…… 继承是为了方便复用代码,避免重复编写代码,不利于维护。 如果父类和子类出现重名,则会生成两个变量,不加 `super.` 会默认为当前类的变量或函数。 覆盖:子类与父类出现同名函数。
1
@Override
##### Object 类: `public String toString()`:定义在父类 `Object` 里,在类中重写来改变 `System.out` 时的输出:
1
2
@Override
public String toString() {}
`toString()` 会自动调用,如 `"str" + object` 等同于 `"str" + object.toString()`。 `public boolean equals(Object obj)`:定义在父类 `Object` 里,在类中没有重写时调用很大概率返回与预期不符的结果。
1
2
3
4
5
@Override
public boolean equals(Object obj) {// 类型必须是 Object
Class object = (Class)obj;
return element.equals(object.element);
}
##### 多态 子类(动态类型)可以被当作父类(声明类型)使用:如父类容器可以放入继承自同一父类的不同子类的元素、向上造型【向上转型】(`FatherClass object = new ChildClass();`)。 特殊:
1
2
FatherClass object = new ChildClass();
ChildClass newObject = (ChildClass)object;// 需要造型(没有被转换)成子类
造型:当作…来看待;转换:变更。 **动态绑定**:“动态”是“运行时”绑定的意思。尽管声明类型不同,调用时还是会调用**动态类型**的函数。 **变量与函数不同,使用的是静态类型的变量,只能封装为函数访问动态类型的变量 getXXX()** object instanceof Class:是其或其子类的对象 ##### 构造函数 执行顺序:变量初始化 -> 父类构造函数 -> 当前类构造函数。 调用父类构造函数:`super(items)`,如果不写的话在执行子类构造函数时会**默认执行父类不带参数的构造函数**(不存在则报错)。 ##### super 和 this - 如果调用 super() 和 this() 都必须作为第一语句,因此两者不能同时出现。 - 子类中出现与父类同名变量用 super 区分。 ##### 抽象 (abstract) - 含有抽象函数 `abstruct func` 的一定是抽象类 `abstract class`。 - 继承自抽象类就要实现其所有抽象方法。 - 构造方法、static 方法、final 方法不能定义为抽象函数。 注:这里的“抽象”表示的含义是不具体,面向对象中另一种“抽象“的含义是封装使看不到底层细节。 final 类的方法都是 final 方法,因为不能继承自然就不能被重写。 final 方法可以提高执行效率。 final 变量可以先定义,随后初始化。 抽象类允许有 private 成员,但其抽象函数不能同时用 abstract 和 private/final/static 修饰。 ##### 接口(interface) 纯抽象类 接口内的只有 public static final 常量,无需指明,必须初始化。 只有 public abstract 方法,无需指明。 接口不能实现 implements 接口,只能继承 extends 接口(可以继承多个)。 可以直接使用接口的常量 Interface.constant. 常量可以用 Math.random() 初始化。 ##### 内部类 内部类:需要先有外部类的对象。**out_object.new**,`Out.this`
1
2
3
class Out { class In { } }
Out out = new Out();
Out.In in = out.new In();
静态类:嵌套类。 局部内部类:可以访问外部。 匿名内部类:`new superclass_or_interface() {}`,传递排序规则时经常用到,若继承的父类只有含参构造函数则在参数列表中指明。 ##### 重载(Overload) 参数列表不同的同名函数,返回值等均不能用于区分。 多个构造函数也叫重载 ##### 重写(Override) - 名称、参数、返回值必须相同。 - 子类重写的访问控制只能更宽松。 - 与 C++ 不同,默认类似虚函数,无论静态类型一律调用动态类型的方法。 ### 输入输出 InputStream OutputStream:字节流 Reader/Writer:字符流 FileInputStream/FileOutputStream Buffered:缓冲流 PrintStream/PrintWriter:打印流 DataInputStream/DataOutputStream:数据流 ObjectInputStream/ObjectOutputStream:对象流 ### GUI AWT(Abstract Window Toolkit)重量级组件 Swing 轻量级组件 SWT(Standard Widget Toolkit) Container 与 Component,Component 父类,Container 容纳 Component。 ### 多线程 1. implements Runnable public void run() {} Thread thread = new Thread(ClassName) 同一实例的多个进程 2. extends Thread public void run() {} Thread thread = new ClassName() 多个实例 getPriority() setPriority(int) 1-10, 5 is normal synchronized 放在函数前 sychronized(object) {} wait() notify() ### 数据库 Structure Query Language create table name drop table name select xxx from xxx insert into xxx update xxx delete from xxx ### 网络编程 import java.net.*;
1
2
3
4
5
6
7
InetAddress address = InetAddress.getLocalHost

InetAddress address = InetAddress.getByName

address.getHostName

address.getHostAddress
ServerSocket()(int port) Socket accept() close() Socket()(String host, int port)(InetAddress address, int port) close() getInputStream getOutputStream ### 异常处理 异常(Exception)和错误(Error) 不受检异常(Unchecked Exception):Runtime Exception/Error…… 受检异常(Checked Exception):IOException/FileNotFoundException……
1
2
3
4
5
6
7
try {
//
} catch(Exception e) {
//
} finally {
//
}
throws 让上一级处理 - `getMessage()` - `printStackTrace()` - `toString()`:返回异常名与 `getMessage()` 的信息。
1
2
3
public static void main(string[] args) throws Exception {
throw Exception;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import java.io.*;
import javax.swing.*;
class CustomException extends Exception {
CustomException() {
System.out.println("init()");
}
public String toString() {
return super.toString();
}
public String getMessage() {
return super.getMessage() + " and " + "getMessage()";
}
}
public class Main {
static void test() throws CustomException {
throw new CustomException();
}
public static void main(String[] args) {
try {
test();
} catch(Exception e) {
e.printStackTrace();
System.out.println(e);
JOptionPane.showMessageDialog(null, e.getMessage());
} finally {
System.out.println("Final");
}
System.out.println("Hello world!");
}
}
/*
init()
CustomException: null and getMessage()
Final
Hello world!
CustomException: null and getMessage()
at Main.test(Main.java:16)
at Main.main(Main.java:20)
*/
### 常用库/函数 ##### Math - 常数:`Math.PI`,`Math.E`. - 绝对值:`Math.abs(int/long/double var)` - 转整数:`Math.ceil(double var)`(上界),`Math.floor(double var)`(下界),`Math.rint(double var)`(最接近)。 - 四舍五入:`Math.round(double var)`。 - 比较:`Math.max(a, b)`,`Math.min(a, b)`。 - 数学:`exp()`、`log()`、`pow()`、`sqrt()`、`sin()`、`cos()`、`tan()`、`asin()`、`acos()`、`atan()`。 - 笛卡尔坐标转极坐标:`atan2()`。 - 随机数:`Math.random()` 得到一个 $[0,1)$ 的随机数。 ##### 系统信息
1
2
System.getProperty("os.name");
System.getProperty("java.version");
##### 时间统计 `System.currentTimeMillis()` 作差可得代码段的运行时间(以毫秒为单位)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* 第一种方式 */
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
long st = System.currentTimeMillis();
for(int i = 0; i < 1000000; ++i) {
out.write(String.format("%d\n", (int)(Math.random() * 100000)));
}
out.flush();
long et = System.currentTimeMillis();
System.out.println(et - st);// 1117 ms
/* 第二种方式 */
long st = System.currentTimeMillis();
for(int i = 0; i < 1000000; ++i) {
System.out.println((int)(Math.random() * 100000));
}
long et = System.currentTimeMillis();
System.out.println(et - st);// 2240 ms
##### Random
1
2
3
4
5
import java.util.Random;
Random r = new Random();
r.nextInt();
r.nextInt(10);
r.nextDouble();
##### Date - 头文件:`import java.util.Date;` - `long getTime()` 返回 1970.1.1 00:00:00 过去的秒数。 - `setTime(long)` 设置 1970.1.1 00:00:00 过去的秒数。 ##### Calendar - 头文件:`import java.util.Calendar;` - 初始化:`Calendar cal = Calendar.getInstance();` - 设置日期(年月日):`cal.set(year, month, day)`。 - 设置日期(设置一项):`cal.set(Calendar.YEAR, 2023)`。 - 修改日期:`cal.add(Calendar.YEAR, -10)` - 获取日期:`cal.get(Calendar.YEAR)` 附: - Calendar.YEAR - Calendar.MONTH - Calendar.DATE - Calendar.HOUR_OF_DAY:24小时制 - Calendar.MINUTE - Calendar.SECOND - Calendar.DAY_OF_WEEK:星期 GregorianCalendar 继承自 Calendar,日期计算很方便。 注意:月的范围是 [0, 11],而非 [1,12]。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import java.util.GregorianCalendar;
public class Main {
public static void main(String[] args) {
GregorianCalendar cal = new GregorianCalendar(2000, 1, 2);
while(cal.get(GregorianCalendar.YEAR) <= 2023) {
int year = cal.get(GregorianCalendar.YEAR);
if(cal.isLeapYear(year)) {
System.out.println(year);
}
cal.add(GregorianCalendar.YEAR, 1);
}
}
}
/*
2000
2004
2008
2012
2016
2020
*/
import java.util.GregorianCalendar;
public class Main {
public static void main(String[] args) {
GregorianCalendar cal1 = new GregorianCalendar(2000, 1, 1);
GregorianCalendar cal2 = new GregorianCalendar(2000, 2, 1);
System.out.println((cal2.getTime().getTime() - cal1.getTime().getTime()) / (1000L * 24 * 60 * 60));
}
}
/*
29
*/
##### 更快的 StringBuilder append(), insert(), delete(), replace(); charAt(); 重要:Java 中容器类型只能为 Wrap 类型,不能是基本数据类型。 引入:`import java.util.*;`。 遍历:`for-each`。 ##### ArrayList 基本用法: - 插入:`add(value)` - 修改:`set(index, value)` - 删除:`remove(index or value)` - 大小:`size()` - 取值:`get(index)` - 转数组:`toArray(newArrayName)` ##### LinkedList add/get/remove + First/Last - `add(value)`,`addFirst` - `removeFirst()` - `getFirst()`、`getLast()` - `peekFirst()`、`peekLast()` ##### HashSet 特点:无序集合。 基本用法: - 插入:`add(value)` - 删除:`remove(value)` - 判断是否存在:`contains(value)` - 大小:`size()` - 清空:`clear()` ##### TreeSet 特点:有序集合。 ##### HashMap 基本用法: - 插入:`put(key, value)`。 - 取值:`get(key)`,不存在返回 `null`。 - 判断是否存在:`containsKey(key)`。 - 键集合:`keySet()`。 - entrySet() - values() - 遍历:`for(KeyType key: hashMap.keySet()) {}` LinkedHashSet/LinkedHashMap ##### Collections sort binarySearch reverse copy min max ##### PriorityQueue `add(_element_)` `peek()` `poll()`
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.PriorityQueue;
import java.util.Comparator;
public class Main {
public static void main(String[] args) {
PriorityQueue<Integer> pq = new PriorityQueue<Integer>(new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return a < b ? -1 : 1;
}
});
pq.add(64);
pq.add(32);
pq.add(128);
System.out.println(pq.peek());
pq.poll();
System.out.println(pq.peek());
pq.poll();
System.out.println(pq.peek());
pq.poll();
}
}
##### Deque
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.util.Deque;
import java.util.LinkedList;

Deque<Integer> dq = new LinkedList<Integer>();// 不能接受基本数据类型

System.out.println(dq.size());// 大小

dq.addLast(512);// 插入元素,失败返回异常
dq.offerLast(1024);// 插入元素,失败返回 null

System.out.println(dq.getFirst());// 获取元素,失败返回异常
System.out.println(dq.peekLast());// 获取元素,失败返回 null

System.out.println(dq.removeFirst());// 删除元素,失败返回异常
System.out.println(dq.pollLast());// 删除元素,失败返回 null
##### 迭代器
1
for(Iterator<String> it = s.iterator(); s.hasNext(); ) System.out.println(s.next());
For-each 只能遍历数组和实现了Iterable接口的实例。 ##### hashCode public int hashCode() { return 123; } ##### 排序 - Arrays.sort() 用于数组排序,还有 `Collections.sort()`. - 可以指定后两个参数 fromIndex 和 toIndex,左闭右开。 - 返回值:负数表示在前,返回零表示相等,返回整数表示在后。
1
2
3
4
5
6
7
8
9
10
11
12
/* 头文件 */
import java.util.Arrays;
/* 数组排序 */
Arrays.sort(a);// 可以加两个参数表示排序区间,左闭右开
/* 自定义排序规则 */
Arrays.sort(a, new Comparator<typename>() {
@Override
int compare(typename a, typename b) {
if(a.x == b.x) return a.y < b.y ? -1 : 1;
return a.x < b.x ? -1 : 1;
}
})
对类排序可以实现 Comparable 接口。
1
2
3
4
5
6
public class ClassName implements Comparable<ClassName> {
@Override
public int compareTo(Classname rhs) {
return -1;
}
}