话接上回,继续核心类与API的学习,这次介绍一下枚举类以及与系统、交互有关的类,需要了解并能使用即可。

一、枚举类

1、概述

枚举也称穷举,简单理解就是把所有可能一一列举出来(穷尽所有可能)。枚举是一个被命名的整型常数的集合,用于声明一组带标识符的常数。使用 enum 关键字来定义枚举类,各个常量使用逗号( , ) 分割。如一年的 4 个季节、12 个月份,一个星期的 7 天。

2、声明

必须使用 enum 关键字声明枚举,并定义枚举的名称、可访问性、基础类型和成员等。

注:如果没有显式地声明基础类型的枚举,则基础类型是 int。

3、案例

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
//定义一个表示颜色的枚举类型 Color
public enum Color {
RED,BLUE,GREEN,BLACK; //可通过枚举类型名直接引用常量,如 Color.RED
}
//使用枚举使switch语句的可读性更强
enum Signal {
// 定义一个枚举类型
GREEN,YELLOW,RED
}
public class TrafficLight {
Signal color = Signal.RED;
public void change() {
switch(color) {
case RED:
color = Signal.GREEN;
break;
case YELLOW:
color = Signal.RED;
break;
case GREEN:
color = Signal.YELLOW;
break;
}
}
}

4、枚举类

4.1 几点注意

1)每一个枚举都继承自 java.lang.Enum 类。
2)当定义一个枚举类型时,每一个枚举类型成员都可以看作是 Enum 类的实例,这些枚举成员默认都被 final、public, static 修饰,书写时可省略这些关键词。当使用枚举类型成员时,直接使用枚举名称调用成员即可。
3)所有枚举实例都可以调用 Enum 类的方法,主要有

values():以数组形式返回枚举类型的所有成员

valueOf():将普通字符串转换为枚举实例

compareTo():比较两个枚举成员在定义时的顺序

ordinal():获取枚举成员的索引位置等。

4.2 案例

1)创建一个包含3个成员的枚举类型Signal,并调用values()方法输出这些成员

1
2
3
4
5
6
7
8
9
enum Signal {  // 定义一个枚举类型
GREEN,YELLOW,RED
}
public class Color {
public static void main(String[] args){
for(int i=0;i<Signal.values().length;i++)
System.out.println("枚举成员:"+Signal.values()[i]);
}
}
1
2
3
4
//结果
枚举成员:GREEN
枚举成员:YELLOW
枚举成员:RED

2)调用valueOf()方法获取枚举的一个成员,再调用compareTo()方法进行比较

1
2
3
4
5
6
7
8
9
10
11
12
13
enum Sex {  // 定义一个枚举类型
male,female;
}
public class Gender {
public static void main(String[] args){
compare(Sex.valueOf("male"));
}
public static void compare(Sex s){
for(int i=0;i<Sex.values().length;i++){
System.out.println(s + "与" + Sex.values()[i] + "的比较结果是:" + s.compareTo(Sex.values()[i]));
}
}
}
1
2
3
//结果
male与male的比较结果是:0
male与female的比较结果是:-1

3)调用枚举类型实例的ordinal()方法,获取成员在枚举中的索引位置。

1
2
3
4
5
6
7
8
9
10
enum Sex {  // 定义一个枚举类型
male,female;
}
public class Gender {
public static void main(String[] args){
for(int i=0;i<Sex.values().length;i++){
System.out.println("索引" + Sex.values()[i].ordinal()+",值:" + Sex.values()[i]);
}
}
}
1
2
3
//结果
索引0,值:male
索引1,值:female

4.3 为枚举添加方法

1)必须在枚举实例的最后一个成员后添加分号,而且必须先定义枚举实例。看如下示例

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
40
41
42
43
44
enum WeekDay {  // 定义一个枚举类型
Mon("Monday"), Tue("Tuesday"), Wed("Wednesday"), Thu("Thursday"), Fri("Friday"), Sat("Saturday"), Sun("Sunday");
// 以上是枚举的成员,必须先定义,而且使用分号结束
private final String day;
private WeekDay(String day) {
this.day = day;
}
public static void printDay(int i) {
switch (i) {
case 1:
System.out.println(WeekDay.Mon);
break;
case 2:
System.out.println(WeekDay.Tue);
break;
case 3:
System.out.println(WeekDay.Wed);
break;
case 4:
System.out.println(WeekDay.Thu);
break;
case 5:
System.out.println(WeekDay.Fri);
break;
case 6:
System.out.println(WeekDay.Sat);
break;
case 7:
System.out.println(WeekDay.Sun);
break;
default:
System.out.println("wrong number!");
}
}
public String getDay() {
return day;
}
public static void main(String[] args){
for(WeekDay day:WeekDay.values()){ // for-each遍历
System.out.println(day+"--->"+day.getDay());
}
WeekDay.printDay(5);
}
}
1
2
3
4
5
6
7
8
9
//结果
Mon--->Monday
Tue--->Tuesday
Wed--->Wednesday
Thu--->Thursday
Fri--->Friday
Sat--->Saturday
Sun--->Sunday
Fri

4.4 EnumMap 与 EnumSet(了解,可不看)

为了能够更高效地操作枚举类型,java.util 中增加了两个新类:EnumMap 和 EnumSet
1)EnumMap
EnumMap 是专门为枚举类型量身定做的 Map 实现。虽然使用其他的 Map(如 HashMap)实现也能完成枚举类型实例到值的映射,但使用 EnumMap 更加高效。

注:HashMap 只能接收同一枚举类型的实例作为键值,并且由于枚举类型实例的数量相对固定并且有限,所以 EnumMap 使用数组来存放与枚举类型对应的值,使得 EnumMap 的效率非常高。

2)EnumSet
EnumSet 是枚举类型的高性能 Set 实现,它要求放入它的枚举常量必须属于同一枚举类型。

二、交互相关

1、Console类(简单了解)

JDK6中提供了java.io.Console类专用来访问基于字符的控制台设备。Console类的目的是使Java程序和控制台之间的交互更容易。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.io.Console; //导包
public class Demo1 {
public static void main(String[] args) {
Console console = System.console(); //通过调用 System.console() 方法获得该类唯一的实例
if (console != null) { //判断console是否可用
String user = console.readLine("Enter user:"); //读取整行字符
String pwd = new String(console.readPassword("Enter password:")); //读取密码,密码输入时不会显示
console.printf("User is:" + user + "\n");
console.printf("Password is:" + pwd + "\n");
} else {
System.out.println("Console is unavailable");
//Console is unavailable,表示Console不可获得,因为JVM不是在命令行中被调用的或者输入输出被重定向了
//如果JVM是在交互式命令行(比如Windows的cmd)中启动的,并且输入输出没有重定向到另外的地方,那么就可以得到一个可用的Console实例
}
}
}

2、Scanner类(掌握)

Scanner类用于获取用户输入,使用前先导包:import java.util.Scanner。以下是一些常用方法介绍。

2.1 next方法

直接看案例

1
2
3
4
5
6
7
8
9
10
11
import java.util.Scanner; //导包
public class ScannerDemo {
public static void main(String[] args){
Scanner sc=new Scanner(System.in); //从键盘接收数据
if(sc.hasNext()){ //判断是否还有输入
String s=sc.next();
System.out.println("输入的数据为:"+s);
}
sc.close(); //关闭输入通道,防止内存损耗
}
}

输入zhangsan lishi,如下

1
2
3
4
// 输入
zhangsan lishi
// 结果(可以看到 lishi 字符串并未输出)
输入的数据为:zhangsan

2.2 nextLine方法

直接看案例

1
2
3
4
5
6
7
8
9
10
11
import java.util.Scanner; //导包
public class ScannerDemo {
public static void main(String[] args){
Scanner sc=new Scanner(System.in); //从键盘接收数据
if(sc.hasNextLine()){ //判断是否还有输入
String s=sc.nextLine();
System.out.println("输入的数据为:"+s);
}
sc.close(); //关闭输入通道,防止内存损耗
}
}

输入zhangsan lishi,如下

1
2
3
4
// 控制台输入
zhangsan lishi
// 结果(可以看到 lishi 字符串已经输出)
输入的数据为:zhangsan lishi

2.3 总结

1)next() 与 nextLine() 区别
next():

  • 一定要读取到有效字符后才可以结束输入。(未输入有效字符前输入空格,按enter后不会结束)
  • 对输入有效字符之前遇到的空白,next() 方法会自动将其去掉。
  • 只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符。
  • next() 不能得到带有空格的字符串。

nextLine():

  • 以Enter为结束符,也就是说 nextLine()方法返回的是输入回车之前的所有字符。
  • 可以获得空白。

    pass:一般情况nextLine()方法使用得较多。

2.4 输入类型

除了nextLine()方法,还有其他很多类型,这里列举几种,直接看如下案例。

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.util.Scanner; //导包
public class ScannerDemo {
public static void main(String[] args){
Scanner sc=new Scanner(System.in); //从键盘接收数据
String name = sc.nextLine(); //字符串输入
int age = sc.nextInt(); //数字输入
double salary = sc.nextDouble();
sc.close(); //关闭输入通道,防止内存损耗
System.out.println("Name: " + name);
System.out.println("Age: " + age);
System.out.println("Salary: " + salary);
}
}

结果

1
2
3
4
5
6
7
8
// 控制台输入
zhangsan
21
10000.88
// 输出结果
Name: zhangsan
Age: 21
Salary: 10000.88

2.5 综合案例(使用Scanner类求总和及平均数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.Scanner; //导包
public class ScannerDemo {
public static void main(String[] args){
System.out.println("请输入数字:");
Scanner sc = new Scanner(System.in);
double sum = 0; //初始化
int m = 0;
while (sc.hasNextDouble()) { //输入非数字结束循环
double x = sc.nextDouble();
m = m + 1; //计数
sum = sum + x; //累加求和
}
System.out.println(m + "个数的和为" + sum);
System.out.println(m + "个数的平均值是" + (sum / m));
sc.close();
}
}

结果

1
2
3
4
5
6
7
请输入数字:
10
20
30
end
3个数的和为60.0
3个数的平均值是20.0

二、系统相关

1、System类

1.1 概述

System类代表当前java程序的运行平台,系统级的很多属性和控制方法都放置在该类的内部。由于该类的构造方法是 private 的,无法创建该类的对象,即无法实例化该类。

1.2 System类的成员变量(了解)

PrintStream out:标准输出流。
InputStream in:标准输入流。
PrintStream err:标准的错误输出流。

1.3 System类的成员方法

System 类中提供了一些系统级的操作方法,常用有 arraycopy()、currentTimeMillis()、exit()、gc() 和 getProperty()。
1)arraycopy()方法
数组复制,即从指定源数组中复制一个数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//arraycopy(Object src,int srcPos,Object dest,int destPos,int length)
//参数说明:(源数组,从源数组复制的起始位置,目标数组,要复制到的目标数组的起始位置,复制的个数)
public class SystemDemo {
public static void main(String[] args) {
char[] srcArray={'A','B','C','D'};
char[] destArray={'E','F','G','H'};
System.arraycopy(srcArray,1,destArray,1,2);
System.out.println("源数组:");
for(int i=0;i<srcArray.length;i++){ //遍历输出
System.out.println(srcArray[i]); //源数组:A B C D (纵向)
}
System.out.println("目标数组:");
for(int j=0;j<destArray.length;j++){
System.out.println(destArray[j]); //目标数组:E B C H (纵向)
}
}
}

2)currentTimeMillis()方法
返回当前的计算机时间。long m = System.currentTimeMillis(); ,获得一个长整型的数字,是以差值表达的当前时间(当前计算机时间与 GMT 时间(格林尼治时间)1970 年 1 月 1 日 0 时 0 分 0 秒所差的毫秒数)。

作用:测试不同算法程序的执行效率高低,用于后期线程控制时的精确延时实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class SystemDemo {
public static void main(String[] args) {
long start=System.currentTimeMillis();
int a=0;
for(int i=0;i<100000000;i++){ //循环100000000次
a++; //a=a+1,自增加一
}
long end=System.currentTimeMillis();
long time=end-start; //for循环执行所需要的毫秒数
System.out.println(a); //100000000
System.out.println(("程序运行前时间"+start+"秒")); //程序运行前时间1673702597732秒
System.out.println(("程序运行后时间"+end+"秒")); //程序运行后时间1673702597734秒
System.out.println(("程序执行时间为"+time+"秒")); //程序执行时间为2秒
}
}

3)exit()方法
终止当前正在运行的 Java 虚拟机。exit(int status),status = 0 时为正常退出,非零为异常退出,较常应用在图形界面编程中实现程序的退出功能等。
4)gc()方法
请求系统进行垃圾回收,完成内存中的垃圾清除。
5)getProperty()方法
使用该方法可以获得很多系统级的参数以及对应的值。

1
2
3
4
5
6
7
8
9
10
public class SystemDemo {
public static void main(String[] args) {
String jversion = System.getProperty("java.version");
String oName = System.getProperty("os.name");
String user = System.getProperty("user.name");
System.out.println("Java运行时环境版本:"+jversion);
System.out.println("当前操作系统是:"+oName);
System.out.println("当前用户是:"+user);
}
}

结果

1
2
3
Java运行时环境版本:11.0.14
当前操作系统是:Windows 10
当前用户是:ASUS