小知识
ASCLL
A--65 a--97 0--48
常量 final
final int x=1;
Math.abs(x-y)//对x-y取绝对值
hasNext() :判断扫描器中当前扫描位置后是否还存在下一段。
一.练手速
public class Main{
public static void main(String[] args)
{
System.out.printin("Hello World");
}
}
二.变量
Java里的定义变量和c++里的一样
类型 字节数 举例
byte 1 123
short 2 12345
int 4 123456789
long 8 1234567891011L
float 4 1.2F
double 8 1.2, 1.2D
boolean 1 true, false
char 2 'A'
三.输入与输出
3.1输入
3.1.1方式1.效率较低,输入规模较小时使用
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
String str = sc.next(); // 读入下一个字符串
int x = sc.nextInt(); // 读入下一个整数
float y = sc.nextFloat(); // 读入下一个单精度浮点数
double z = sc.nextDouble(); // 读入下一个双精度浮点数
String line = sc.nextLine(); // 读入下一行
}
}
3.1.2方式2.效率较高,输入规模较大时使用。注意需要抛异常
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str = br.readLine();
System.out.println(str);
int x=Integer.parseInt(br.readLine());//读入整数
int y=Integer.parseInt(br.readLine());
System.out.println(x+y);
}
}
3.2输出
3.2.1方式1.效率较低,输出规模较小时使用
public class Main {
public static void main(String[] args) throws Exception {
System.out.println(123); // 输出整数 + 换行
System.out.println("Hello World"); // 输出字符串 + 换行
System.out.print(123); // 输出整数
System.out.print("yxc\n"); // 输出字符串
System.out.printf("%04d %.2f\n", 4, 123.456D); // 格式化输出,float与double都用%f输出
}
}
System.out.printf()中不同类型变量的输出格式:
(1) int:%d
(2) float: %f, 默认保留6位小数
(3) double: %f, 默认保留6位小数
(4) char: %c, 回车也是一个字符,用'\n'表示
(5) String: %s
3.2.2方式2.效率较高,输出规模较大时使用。注意需要抛异常
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
public class Main {
public static void main(String[] args) throws Exception {
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
bw.write("Hello World\n");
bw.flush(); // 需要手动刷新缓冲区
}
}
四.判断语句
4.1if语句
基本if-else语句
当条件成立时,执行某些语句;否则执行另一些语句。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
if (a > 5) {
System.out.printf("%d is big!\n", a);
System.out.printf("%d + 1 = %d\n", a, a + 1);
} else {
System.out.printf("%d is small!\n", a);
System.out.printf("%d - 1 = %d\n", a, a - 1);
}
}
}
else 语句可以省略:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
if (a > 5) {
System.out.printf("%d is big!\n", a);
System.out.printf("%d + 1 = %d\n", a, a + 1);
}
}
}
当只有一条语句时,大括号可以省略:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
if (a > 5)
System.out.printf("%d is big!\n", a);
else
System.out.printf("%d is small!\n", a);
}
}
4.2常用比较运算符
(1) 大于 >
(2) 小于 <
(3) 大于等于 >=
(4) 小于等于 <=
(5) 等于 ==
(6) 不等于 !=
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a = sc.nextInt(), b = sc.nextInt();
if (a > b) System.out.printf("%d > %d\n", a, b);
if (a >= b) System.out.printf("%d >= %d\n", a, b);
if (a < b) System.out.printf("%d < %d\n", a, b);
if (a <= b) System.out.printf("%d <= %d\n", a, b);
if (a == b) System.out.printf("%d == %d\n", a, b);
if (a != b) System.out.printf("%d != %d\n", a, b);
}
}
4.3if-else连写
输入一个0到100之间的分数,
如果大于等于85,输出A;
如果大于等于70并且小于85,输出B;
如果大于等于60并且小于70,输出C;
如果小于60,输出 D;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int s = sc.nextInt();
if (s >= 85) {
System.out.println("A");
} else if (s >= 70) {
System.out.println("B");
} else if (s >= 60) {
System.out.println("C");
} else {
System.out.println("D");
}
}
}
4.4条件表达式
(1) 与 &&
(2) 或 ||
(3) 非 !
例题:输入三个数,输出三个数中的最大值
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a = sc.nextInt(), b = sc.nextInt(), c = sc.nextInt();
if (a >= b && a >= c)
System.out.println(a);
else if (b >= a && b >= c)
System.out.println(b);
else
System.out.println(c);
}
}
4.5switch语句
注意: swtich语句中如果不加break语句,则从上到下匹配到第一个case后,会顺次执行后面每个case中的语句。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int day = sc.nextInt();
String name;
switch(day) {
case 1:
name = "Monday";
break;
case 2:
name = "Tuesday";
break;
case 3:
name = "Wednesday";
break;
case 4:
name = "Thursday";
break;
case 5:
name = "Friday";
break;
case 6:
name = "Saturday";
break;
case 7:
name = "Sunday";
break;
default:
name = "not valid";
}
System.out.println(name);
}
}
五.循环语句
5.1while循环
可以简单理解为循环版的if语句。if语句是判断一次,如果条件成立,则执行后面的语句; while是每次判断,如果成立,则执行循环体中的语句,否则停止。
public class Main {
public static void main(String[] args) {
int i = 0;
while (i < 10) {
System.out.println(i);
i ++ ;
}
}
}
5.2do while循环(不常用)
do while语句与while语句非常相似。唯一的区别是, do while语句限制性循环体后检查条件。不管条件的值如何,我们都要至少执行一次循环。
public class Main {
public static void main(String[] args) {
int x = 1;
while (x < 1) {
System.out.println("x!");
}
int y = 1;
do {
System.out.println("y!");
} while (y < 1);
}
}
5.3for循环
基本思想:把控制循环次数的变量从循环体中剥离。
for (init-statement; condition; expression) {
statement
}
init-statement可以是声明语句、表达式、空语句,一般用来初始化循环变量;
condition是条件表达式,和while中的条件表达式作用一样;可以为空,空语句表示true;
expression一般负责修改循环变量,可以为空。
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i ++ ) { // 循环体中只有一条语句时,可以不加大括号
System.out.println(i);
}
}
}
5.4break跳转语句
可以提前从循环中退出,一般与if语句搭配。
例题:判断一个大于1的数是否是质数:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
boolean isPrime = true;
for (int i = 2; i < n; i ++ )
if (n % i == 0) {
isPrime = false;
break;
}
if (isPrime)
System.out.println("yes");
else
System.out.println("no");
}
}
5.5continue
可以直接跳到当前循环体的结尾。作用与if语句类似
例题:求1~100中所有偶数的和
public class Main {
public static void main(String[] args) {
int sum = 0;
for (int i = 1; i <= 100; i ++ ) {
if (i % 2 == 1) continue;
sum += i;
}
System.out.println(sum);
}
}
5.6多层循环
将1~100打印到一个10 * 10的矩阵中:
public class Main {
public static void main(String[] args) {
for (int i = 0, k = 1; i < 10; i ++ ) {
for (int j = 0; j < 10; j ++, k ++ ) {
System.out.printf("%d ", k);
}
System.out.println();
}
}
}
六.数组
6.1一维数组
6.1.1数组定义
数组的定义方式和变量类似。
public class Main {
public static void main(String[] args) {
int[] a = new int[10], b;
float[] f = new float[33];
double[] d = new double[123];
char[] c = new char[21];
}
}
6.1.2数组的初始化
public class Main {
public static void main(String[] args) {
int[] a = {0, 1, 2}; // 含有3个元素的数组,元素分别是0, 1, 2
int[] b = new int[3]; // 含有3个元素的数组,元素的值均为0
char[] d = {'a', 'b', 'c'}; // 字符数组的初始化
}
}
6.1.3访问数组
通过下标访问数组。
public class Main {
public static void main(String[] args) {
int[] a = {0, 1, 2}; // 数组下标从0开始
System.out.printf("%d %d %d\n", a[0], a[1], a[2]);
a[0] = 5;
System.out.println(a[0]);
}
}
6.2多维数组
6.2.1定义
public class Main {
public static void main(String[] args) {
int[][] a = new int[3][4]; // 大小为3的数组,每个元素是含有4个整数的数组。
int[][][] b = new int[10][20][30]; // 将所有元素的初值为0
// 大小为10的数组,它的每个元素是含有20个数组的数组
// 这些数组的元素是含有30个整数的数组
}
}
public class Main {
public static void main(String[] args) {
int[][] a = { // 三个元素,每个元素都是大小为4的数组
{0, 1, 2, 3}, // 第1行的初始值
{4, 5, 6, 7}, // 第2行的初始值
{8, 9, 10, 11} // 第3行的初始值
};
for (int i = 0; i < 4; i ++ ) // 将第一行全部变成0
a[0][i] = 0;
for (int i = 0; i < 3; i ++ ) { // 输出二维数组
for (int j = 0; j < 4; j ++ ) {
System.out.printf("%d ", a[i][j]);
}
System.out.println();
}
}
}
6.2.2数组遍历
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
int[][] a = {
{0, 1, 2, 3},
{4, 5, 6, 7},
{8, 9, 10, 11},
};
for (int[] row: a) { // 范围遍历
for (int x: row) // 范围遍历
System.out.printf("%d ", x);
System.out.println();
}
}
}
6.3常用API
属性length:返回数组长度,注意不加小括号
Arrays.sort():数组排序
Arrays.fill(int[] a, int val):填充数组
Arrays.toString():将数组转化为字符串
Arrays.deepToString():将多维数组转化为字符串
数组不可变长
使用Arrays需要import java.util.Arrays
七.字符串
7.1字符与整数的联系——ASCII码
每个常用字符都对应一个-128 ~ 127的数字,二者之间可以相互转化。注意:目前负数没有与之对应的字符。
import java.util.Arrays;
pblic class Main {
public static void main(String[] args) {
char c = 'a';
System.out.println((int)c);
int a = 66;
System.out.println((char)a);
}
}
常用ASCII值:'A'- 'Z'是65 ~ 90,'a' - 'z'是97 - 122,0 - 9是 48 - 57。
字符可以参与运算,运算时会将其当做整数:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int a = 'B' - 'A';
int b = 'A' * 'B';
char c = 'A' + 2;
System.out.println(a);
System.out.println(b);
System.out.println(c);
}
}
7.2string类
初始化:
String a = "Hello World";
String b = "My name is ";
String x = b; // 存储到了相同地址
String c = b + "yxc"; // String可以通过加号拼接
String d = "My age is " + 18; // int会被隐式转化成字符串"18"
String str = String.format("My age is %d", 18); // 格式化字符串,类似于C++中的sprintf
String money_str = "123.45";
double money = Double.parseDouble(money_str); // String转double
只读变量,不能修改,例如:
String a = "Hello ";
a += "World"; // 会构造一个新的字符串
访问String中的字符:
String str = "Hello World";
for (int i = 0; i < str.length(); i ++ ) {
System.out.print(str.charAt(i)); // 只能读取,不能写入
}
7.3常用API
length():返回长度
split(String regex):分割字符串
indexOf(char c)、indexOf(String str)、lastIndexOf(char c)、lastIndexOf(String str):查找,找不到返回-1
equals():判断两个字符串是否相等,注意不能直接用==
compareTo():判断两个字符串的字典序大小,负数表示小于,0表示相等,正数表示大于
a.compareToIgnoreCase(b);compareTo()是比较字符串大小,compareToIgnoreCase同理,但是可以忽略大小写
startsWith():判断是否以某个前缀开头
endsWith():判断是否以某个后缀结尾
trim():去掉首尾的空白字符
toLowerCase():全部用小写字符
toUpperCase():全部用大写字符
replace(char oldChar, char newChar):替换字符
replace(String oldRegex, String newRegex):替换字符串
substring(int beginIndex, int endIndex):返回[beginIndex, endIndex)中的子串
toCharArray():将字符串转化成字符数组
7.4输入与输出
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str1 = sc.next(); // 输入字符串,遇到空格、回车等空白字符时停止输入
String str2 = sc.nextLine(); // 输入一整行字符串,遇到空格不会停止输入,遇到回车才会停止
System.out.println(str1); // 可以直接输出
System.out.printf("%s\n", str2); // 也可以格式化输出,用 %s 表示字符串
}
}
7.5String Builder,StringBuffer
String不能被修改,如果打算修改字符串,可以使用StringBuilder和StringBuffer。
StringBuffer线程安全,速度较慢;StringBuilder线程不安全,速度较快。
StringBuilder sb = new StringBuilder("Hello "); // 初始化
sb.append("World"); // 拼接字符串
System.out.println(sb);
for (int i = 0; i < sb.length(); i ++ ) {
sb.setCharAt(i, (char)(sb.charAt(i) + 1)); // 读取和写入字符
}
System.out.println(sb);
常用API:
reverse():翻转字符串
7.6将连续的空格换成一个
String s = cin.nextLine();
System.out.println(s.replaceAll ("\\s+", " "));
八.函数
8.1函数基础
一个典型的函数定义包括以下部分:修饰符、返回类型、函数名字、由0个或多个形参组成的列表以及函数体。
8.1.1调用函数
我们来编写一个求阶乘的程序。程序如下所示:
public class Main {
private static int fact(int val) {
int res = 1;
for (int i = 1; i <= val; i ++ )
res *= i;
return res;
}
}
函数名字是fact,它作用于一个整型参数,返回一个整型值。return语句负责结束fact并返回res的值。
修饰符包括private、static等,它们属于类相关的概念,会在下一章解释。
public class Main {
private static int fact(int val) {
int res = 1;
for (int i = 1; i <= val; i ++ )
res *= i;
return res;
}
public static void main(String[] args) {
int res = fact(5);
System.out.printf("5! is %d\n", res);
}
}
函数的调用完成两项工作:一是用实参初始化函数对应的形参,
二是将控制权转移给被调用函数。此时,主调函数的执行被暂
时中断,被调函数开始执行。
8.1.2形参和实参
实参是形参的初始值。第一个实参初始化第一个形参,第二个实参初始化第二个形参,依次类推。形参和实参的类型和个数必须匹配。
fact("hello"); // 错误:实参类型不正确
fact(); // 错误:实参数量不足
fact(42, 10, 0); // 错误:实参数量过多
fact(' '); // 正确:该实参能自动转换成int类型,' '的ASCII值为32,
所以该操作等价于fact(32);
8.1.3函数的形参列表
函数的形参列表可以为空,但是不能省略。
void f1() {/* …. */} // 空形参列表
形参列表中的形参通常用逗号隔开,其中每个形参都是含有一个声明符的声明。
即使两个形参的类型一样,也必须把两个类型都写出来:
int f3(int v1, v2) {/* … */} // 错误
int f4(int v1, int v2) {/* … */} // 正确
8.1.4函数返回类型
大多数类型都能用作函数的返回类型。一种特殊的返回类型是void,
它表示函数不返回任何值。
函数的返回类型也可以是数组、字符串或者其他对象:
import java.util.Arrays;
public class Main {
private static int[] newArray() {
int[] a = {1, 2, 3};
return a;
}
private static String newString() {
return "Hello World";
}
public static void main(String[] args) {
System.out.println(Arrays.toString(newArray()));
System.out.println(newString());
}
}
8.1.5变量的作用域
本章中我们只使用静态成员变量和静态成员函数,非静态成员变量/函数及其区别会在下一章中介绍。
函数内定义的变量为局部变量,只能在函数内部使用。
定义在类中的变量为成员变量,可以在类的所有成员函数中调用。
当局部变量与全局变量重名时,会优先使用局部变量。
public class Main {
private static int x = 4;
private static void f1() {
int x = 3;
System.out.println(x);
}
private static void f2() {
System.out.println(x);
}
private static void f3() {
System.out.println(x + 1);
}
public static void main(String[] args) {
f1();
f2();
f3();
}
}
8.2参数传递
8.2.1值传递
八大基本数据类型和String类型等采用值传递。
将实参的初始值拷贝给形参。此时,对形参的改动不会影响实参的初始值。
public class Main {
private static void f(int x) {
x = 5;
}
public static void main(String[] args) {
int x = 10;
f(x);
System.out.println(x);
}
}
8.2.2引用传递
除String以外的数据类型的对象,例如数组、StringBuilder等采用引用传递。
将实参的引用(地址)传给形参,通过引用找到变量的真正地址,然后对地址中的值修改。
所以此时对形参的修改会影响实参的初始值。
import java.util.Arrays;
public class Main {
private static void f1(int[] a) {
for (int i = 0, j = a.length - 1; i < j; i ++, j -- ) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}
private static void f2(StringBuilder sb) {
sb.append("Hello World");
}
public static void main(String[] args) {
int[] a = {1, 2, 3, 4, 5};
f1(a);
System.out.println(Arrays.toString(a));
StringBuilder sb = new StringBuilder("");
f2(sb);
System.out.println(sb);
}
}
8.3返回类型和return语句
return语句终止当前正在执行的函数并将控制权返回到调用该函数的地方。
return语句有两种形式:
return;
return expression;
8.3.1无返回值函数
没有返回值的return语句只能用在返回类型是void的函数中。
返回void的函数不要求非得有return语句,
因为在这类函数的最后一句后面会隐式地执行return。
通常情况下,void函数如果想在它的中间位置提前退出,可以使用return语句。
return的这种用法有点类似于我们用break语句退出循环。
public class Main {
private static void swap(int[] a) { // 交换a[0]和a[1]
// 如果两个值相等,则不需要交换,直接退出
if (a[0] == a[1])
return;
// 如果程序执行到了这里,说明还需要继续完成某些功能
int tmp = a[0];
a[0] = a[1];
a[1] = tmp;
// 此处无须显示的return语句
}
public static void main(String[] args) {
int[] a = {3, 4};
swap(a);
System.out.printf("%d %d\n", a[0], a[1]);
}
}
8.3.2有返回值函数
只要函数的返回类型不是void,则该函数内的每个分支都必须有return语句,
且每条return语句都必须返回一个值。
return语句返回值的类型必须与函数的返回类型相同,或者能隐式地转换函数的返回类型。
import java.util.Scanner;
public class Main {
private static int max(int a, int b) {
if (a > b)
return a;
return b;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int x = sc.nextInt(), y = sc.nextInt();
System.out.println(max(x, y));
}
}
8.4函数重载
函数重载是指:在同一个类中存在多个函数,函数名称相同但参数列表不同。
编译器会根据实参的类型选择最匹配的函数来执行。
import java.util.Scanner;
public class Main {
private static int max(int a, int b) {
System.out.println("int max");
if (a > b) return a;
return b;
}
private static double max(double a, double b) {
System.out.println("double max");
if (a > b) return a;
return b;
}
public static void main(String[] args) {
System.out.println(max(3, 4));
System.out.println(max(3.0, 4.0));
}
}
8.5函数递归
在一个函数内部,也可以调用函数本身。
import java.util.Scanner;
public class Main {
private static int fib(int n) { // 求斐波那切数列第n项
if (n <= 2) return 1;
return fib(n - 1) + fib(n - 2);
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
System.out.println(fib(n));
}
}
九.类与接口
9.1类与对象
类定义一种全新的数据类型,包含一组变量和函数;对象是类这种类型对应的实例。 例如在一间教室中,可以将Student定义成类,表示“学生”这个抽象的概念。
那么每个同学就是Student类的一个对象(实例)。
9.1.1源文件声明规则
一个源文件中只能有一个public类。
一个源文件可以有多个非public类。
源文件的名称应该和public类的类名保持一致。
每个源文件中,先写package语句,再写import语句,最后定义类。
9.1.2类的定义
public: 所有对象均可以访问
private: 只有本类内部可以访问
protected:同一个包或者子类中可以访问
不添加修饰符:在同一个包中可以访问
静态(带static修饰符)成员变量/函数与普通成员变量/函数的区别:
所有static成员变量/函数在类中只有一份,被所有类的对象共享;
所有普通成员变量/函数在类的每个对象中都有独立的一份;
静态函数中只能调用静态函数/变量;普通函数中既可以调用普通函数/变量,也可以调用静态函数/变量。
class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public String toString() {
return String.format("(%d, %d)", x, y);
}
}
9.1.3类的继承
每个类只能继承一个类。
class ColorPoint extends Point {
private String color;
public ColorPoint(int x, int y, String color) {
super(x, y);
this.color = color;
}
public void setColor(String color) {
this.color = color;
}
public String toString() {
return String.format("(%d, %d, %s)", super.getX(), super.getY(), this.color);
}
}
9.1.4类的多态
public class Main {
public static void main(String[] args) {
Point point = new Point(3, 4);
Point colorPoint = new ColorPoint(1, 2, "red");
// 多态,同一个类的实例,调用相同的函数,运行结果不同
System.out.println(point.toString());
System.out.println(colorPoint.toString());
}
}
9.2接口
interface与class类似。主要用来定义类中所需包含的函数。
接口也可以继承其他接口,一个类可以实现多个接口。
9.2.1接口的定义
接口中不添加修饰符时,默认为public。
interface Role {
public void greet();
public void move();
public int getSpeed();
}
9.2.2接口的继承
每个接口可以继承多个接口
interface Hero extends Role {
public void attack();
}
9.2.3接口的实现
每个类可以实现多个接口
class Zeus implements Hero {
private final String name = "Zeus";
public void attack() {
System.out.println(name + ": Attack!");
}
public void greet() {
System.out.println(name + ": Hi!");
}
public void move() {
System.out.println(name + ": Move!");
}
public int getSpeed() {
return 10;
}
}
9.2.4接口的多态
class Athena implements Hero {
private final String name = "Athena";
public void attack() {
System.out.println(name + ": Attack!!!");
}
public void greet() {
System.out.println(name + ": Hi!!!");
}
public void move() {
System.out.println(name + ": Move!!!");
}
public int getSpeed() {
return 10;
}
}
public class Main {
public static void main(String[] args) {
Hero[] heros = {new Zeus(), new Athena()};
for (Hero hero: heros) {
hero.greet();
}
}
}
十.常用容器
10.1list
接口:java.util.List<>。
实现:
java.util.ArrayList<>:变长数组
java.util.LinkedList<>:双链表
函数:
add():在末尾添加一个元素
clear():清空
size():返回长度
isEmpty():是否为空
get(i):获取第i个元素
set(i, val):将第i个元素设置为val
10.2栈
类:java.util.Stack<>
函数:
push():压入元素
pop():弹出栈顶元素,并返回栈顶元素
peek():返回栈顶元素
size():返回长度
empty():栈是否为空
clear():清空
10.3队列
接口:java.util.Queue<>
实现:
java.util.LinkedList<>:双链表
java.util.PriorityQueue<>:优先队列
默认是小根堆:new priorityQueue<>()
大根堆写法:new PriorityQueue<>(Collections.reverseOrder())
函数:
add():在队尾添加元素
remove():删除并返回队头
isEmpty():是否为空
size():返回长度
peek():返回队头
clear():清空
10.4set
接口:java.util.Set<K>
实现:
- java.util.HashSet<K>:哈希表
- java.util.TreeSet<K>:平衡树
函数:
add():添加元素
contains():是否包含某个元素
remove():删除元素
size():返回元素数
isEmpty():是否为空
clear():清空
java.util.TreeSet多的函数:
ceiling(key):返回大于等于key的最小元素,不存在则返回null
floor(key):返回小于等于key的最大元素,不存在则返回null
10.5map
接口:java.util.Map<K, V>
实现:
java.util.HashMap<K, V>:哈希表
java.util.TreeMap<K, V>:平衡树
函数:
put(key, value):添加关键字和其对应的值
get(key):返回关键字对应的值
containsKey(key):是否包含关键字
remove(key):删除关键字
size():返回元素数
isEmpty():是否为空
clear():清空
entrySet():获取Map中的所有对象的集合
Map.Entry<K, V>:Map中的对象类型
getKey():获取关键字
getValue():获取值 java.util.TreeMap<K, V>多的函数:
ceilingEntry(key):返回大于等于key的最小元素,不存在则返回null
floorEntry(key):返回小于等于key的最大元素,不存在则返回null
十一.异常处理
1. Error与Exception的区别
Error是程序无法处理的错误,比如OutOfMemoryError、ThreadDeath等。
这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。此类异常是程序的致命异常,是无法捕获处理的。
Exception是程序本身可以处理的异常,这种异常分两大类运行时异常和非运行时异常。
程序中应当尽可能去处理这些异常。
2. Exception类的继承关系
3. 运行时异常和非运行时异常的区别
运行时异常都是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException等,
这些异常是非检查型异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
非运行时异常是RuntimeException以外的异常,类型上都属于Exception类及其子类。
从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,这些是检查型异常。一般情况下不自定义检查型异常。
4. 内置异常类
非检查性异常
异常 描述
ArithmeticException 当出现异常的运算条件时,抛出此异常。例如,一个整数”除以零”时,抛出此类的一个实例。
ArrayIndexOutOfBoundsException 用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。
ArrayStoreException 试图将错误类型的对象存储到一个对象数组时抛出的异常。
ClassCastException 当试图将对象强制转换为不是实例的子类时,抛出该异常。
IllegalArgumentException 抛出的异常表明向方法传递了一个不合法或不正确的参数。
IllegalMonitorStateException 抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程。
IllegalStateException 在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。
IllegalThreadStateException 线程没有处于请求操作所要求的适当状态时抛出的异常。
IndexOutOfBoundsException 指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。
NegativeArraySizeException 如果应用程序试图创建大小为负的数组,则抛出该异常。
NullPointerException 当应用程序试图在需要对象的地方使用 null 时,抛出该异常。
NumberFormatException 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。
SecurityException 由安全管理器抛出的异常,指示存在安全侵犯。
StringIndexOutOfBoundsException 此异常由 String 方法抛出,指示索引或者为负,或者超出字符串的大小。
UnsupportedOperationException 当不支持请求的操作时,抛出该异常。
检查性异常:
异常 描述
ClassNotFoundException 应用程序试图加载类时,找不到相应的类,抛出该异常。
CloneNotSupportedException 当调用 Object 类中的 clone 方法克隆对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常。
IllegalAccessException 拒绝访问一个类的时候,抛出该异常。
InstantiationException 当试图使用 Class 类中的 newInstance 方法创建一个类的实例,而指定的类对象因为是一个接口或是一个抽象类而无法实例化时,抛出该异常。
InterruptedException 一个线程被另一个线程中断,抛出该异常。
NoSuchFieldException 请求的变量不存在
NoSuchMethodException 请求的方法不存在
5. 内置异常方法
方法 说明
public String getMessage() 返回关于发生的异常的详细信息。这个消息在Throwable 类的构造函数中初始化了。
public Throwable getCause() 返回一个 Throwable 对象代表异常原因。
public String toString() 返回此 Throwable 的简短描述。
public void printStackTrace() 将此 Throwable 及其回溯打印到标准错误流
public StackTraceElement [] getStackTrace() 返回一个包含堆栈层次的数组。下标为0的元素代表栈顶,最后一个元素代表方法调用堆栈的栈底。
public Throwable fillInStackTrace() 用当前的调用栈层次填充Throwable 对象栈层次,添加到栈层次任何先前信息中。
6. 捕获异常
import java.util.Scanner;
public class Main {
private static void foo() {
int[] array = new int[5];
for (int i = 0; i < 5; i ++ )
array[i] = i;
Scanner sc = new Scanner(System.in);
int k = sc.nextInt();
int x = sc.nextInt();
try {
array[k] /= x;
} catch (ArithmeticException e) {
System.out.println("除零错误!");
e.printStackTrace();
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组越界!");
e.printStackTrace();
} finally {
for (int i = 0; i < 5; i ++ ) {
System.out.println(array[i]);
}
}
}
public static void main(String[] args) {
foo();
}
}
7. 抛出异常
throw: 在函数内抛出一个异常。
throws:在函数定义时抛出一些可能的异常。
检查型异常必须被捕获或者抛出。
import java.io.IOException;
import java.util.Scanner;
public class Main {
private static void foo() throws IOException, NoSuchFieldException {
Scanner sc = new Scanner(System.in);
int x = sc.nextInt();
if (x == 1)
throw new IOException("找不到文件!!!");
else
throw new NoSuchFieldException("自定义异常");
}
public static void main(String[] args) {
try {
foo();
} catch (IOException e) {
System.out.println("IOException!");
e.printStackTrace();
} catch (NoSuchFieldException e) {
System.out.println("NoSuchFieldException!");
e.printStackTrace();
}
}
}
8. try-with-resources
JDK7 之后,Java 新增的 try-with-resource 语法糖来打开资源,并且可以在语句执行完毕后确保每个资源都被自动关闭 。
try 用于声明和实例化资源,catch 用于处理关闭资源时可能引发的所有异常。
import java.io.*;
public class Main {
public static void main(String[] args) {
String line;
try (
BufferedReader br = new BufferedReader(new FileReader("input.txt"));//读文件
BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"));
) {
while ((line = br.readLine()) != null) {
System.out.println("Line => " + line);
bw.write("copy: " + line + "\n");
}
bw.flush();
} catch (IOException e) {
System.out.println("IOException in try block =>" + e.getMessage());
}
}
}
十二.注解与反射
12.1注释
(1) 注解(Annotation)也被称为元数据(Metadata),用于修饰包、方法、属性、构造器、局部变量等数据信息。
(2) 注解不影响程序逻辑,但注解可以被编译或运行。
(3) 在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。 在JavaEE中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替JavaEE旧版中所遗留的繁冗代码和XML配置等。
12.1.1常用注释
(1) @Override: 限定某个函数必须重载其他函数,该注解只能用于函数
(2) @Deprecated:用于表示某个程序元素(类、函数)已过时
(3) @SuppressWarnings:抑制编译器警告
12.1.2元注释
修饰其他注解的注解,就被称为元注解。
(1) Retention:指定注解的作用范围
(2) Target:指定注解可以用在哪些地方
(3) Document:注定注解是否出出现在javadoc中
(4) Inherited:子类会继承父类的注解
12.2反射
反射:动态引入类、动态调用实例的成员函数、成员变量等。
12.2.1常用API
(1) java.lang.Class
(2) java.lang.reflect.Method
(3) java.lang.reflect.Field
(4) java.lang.reflect.Constructor
package org.yxc;
public class Calculator {
public String name;
public Calculator() {}
public Calculator(String name) {
this.name = name;
}
public int add(int a, int b) {
return a + b;
}
}
package org.yxc;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Class<?> cls = Class.forName("org.yxc.Calculator");
Object o = cls.newInstance();
Method method = cls.getMethod("add", int.class, int.class);
int res = (int)method.invoke(o, 3, 4);
System.out.println(res);
Field field = cls.getField("name");
field.set(o, "My Calculator!");
System.out.println(field.get(o));
Constructor<?> constructor = cls.getConstructor(String.class);
Object new_o = constructor.newInstance("New Calculator!");
System.out.println(new_o);
}
}
12.2.3优缺点
优点:可以动态创建和使用对象,使用灵活
缺点:执行速度慢
十三.多线程与锁
13.1多线程
13.1.1实现多线程
写法1:继承Thread类
class Worker extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i ++ ) {
System.out.println("Hello! " + this.getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class Main {
public static void main(String[] args) {
Worker worker1 = new Worker();
Worker worker2 = new Worker();
worker1.setName("thread-1");
worker2.setName("thread-2");
worker1.start();
worker2.start();
}
}
写法2:实现Runnable接口
class Worker1 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i ++ ) {
System.out.println("Hello! " + "thread-1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
class Worker2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i ++ ) {
System.out.println("Hello! " + "thread-2");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class Main {
public static void main(String[] args) {
new Thread(new Worker1()).start();
new Thread(new Worker2()).start();
}
}
13.1.2常用API
start():开启一个线程
Thread.sleep(): 休眠一个线程
join():等待线程执行结束
interrupt():从休眠中中断线程
setDaemon():将线程设置为守护线程。当只剩下守护线程时,程序自动退出
13.2锁
lock:获取锁,如果锁已经被其他线程获取,则阻塞
unlock:释放锁,并唤醒被该锁阻塞的其他线程
import java.util.concurrent.locks.ReentrantLock;
class Worker extends Thread {
public static int cnt = 0;
private static final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
for (int i = 0; i < 100000; i ++ ) {
lock.lock();
try {
cnt ++ ;
} finally {
lock.unlock();
}
}
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
Worker worker1 = new Worker();
Worker worker2 = new Worker();
worker1.start();
worker2.start();
worker1.join();
worker2.join();
System.out.println(Worker.cnt);
}
}
13.3同步
写法1:将Synchronized加到代码块上
class Count {
public int cnt = 0;
}
class Worker extends Thread {
public final Count count;
public Worker(Count count) {
this.count = count;
}
@Override
public void run() {
synchronized (count) {
for (int i = 0; i < 100000; i ++ ) {
count.cnt ++ ;
}
}
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
Count count = new Count();
Worker worker1 = new Worker(count);
Worker worker2 = new Worker(count);
worker1.start();
worker2.start();
worker1.join();
worker2.join();
System.out.println(count.cnt);
}
}
写法2:将Synchronized加到函数上(锁加到了this对象上)
class Worker implements Runnable {
public static int cnt = 0;
private synchronized void work() {
for (int i = 0; i < 100000; i ++ ) {
cnt ++ ;
}
}
@Override
public void run() {
work();
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
Worker worker = new Worker();
Thread worker1 = new Thread(worker);
Thread worker2 = new Thread(worker);
worker1.start();
worker2.start();
worker1.join();
worker2.join();
System.out.println(Worker.cnt);
}
}
13.3.1wait与notify
package org.yxc;
class Worker extends Thread {
private final Object object;
private final boolean needWait;
public Worker(Object object, boolean needWait) {
this.object = object;
this.needWait = needWait;
}
@Override
public void run() {
synchronized (object) {
try {
if (needWait) {
object.wait();
System.out.println(this.getName() + ": 被唤醒啦!");
} else {
object.notifyAll();
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
Object object = new Object();
for (int i = 0; i < 5; i ++ ) {
Worker worker = new Worker(object, true);
worker.setName("thread-" + i);
worker.start();
}
Worker worker = new Worker(object, false);
worker.setName("thread-" + 5);
Thread.sleep(1000);
worker.start();
}
}