Scanner 获取键盘输入
先来一个大家都会的输入,输入一个数值并将其输出
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println(sc.next());
}
如果我们想要一直输入呢?
首先需要介绍两个 Scanner 提供的两个方法用来扫描输入
- hasNextXxx():是否还有下一个输入项,其中Xxx可用来代表需要判断输入项的Int、Long等数据类型。
- nextXxx(): 获取下一个输入项,Xxx和前面的方法含义一样,也可以不加Xxx。
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
//进行判断是否进行输入
while(sc.hasNext()){
System.out.println("键盘输入的内容是:" + sc.next());
}
}
事实上,Scanner 提供了两个简单的方法帮助我们用于逐行读取。
- boolean hasNextLine():返回输入源中是否还有下一行。
- String nextLine():** 返回输入源中下一行的字符串。**
一般用于文件输入,因为设计到 I/O 流所以在这不再介绍。
System类
System 类常用的有 in、out、err分别代表系统标准输入、标准输出、错误输出流。System 类代表当前 Java 程序的运行平台,程序不能创建 System 类的对象。
还有不是很常用的获取系统当前时间的方法:
- **currentTimeMillis():**以毫秒为单位
- nanoTime():以纳秒作为单位
- 注意:实际上它们返回当前时间与 UTC 1970年1月1日午夜的时间差,并且这两个方法返回的时间粒度取决于底层操作系统,可能所在的操作系统根本不支持以毫秒、纳秒为计时单位
除此以外还有一个** identityHashCode(Object x) 方法,该方法返回指定对象的精确 hashCode 值**,也就是根据对象的地址计算得到的 hashCode 值。所以,如果两个对象的值相同,则两个对象绝对是同一个对象。
public static void main(String[] args) {
String s1 = new String("Hello");
String s2 = new String("Hello");
System.out.println(s1.hashCode());
System.out.println(System.identityHashCode(s1));
System.out.println(s2.hashCode());
System.out.println(System.identityHashCode(s2));
}
/*res:
69609650
1956725890
69609650
356573597
上述结果因为** String 重写了 hashCode() 方法——改为根据字符序列计算 hashCode 值,**所以 s1 和 s2 的字符序列相同,所以 hashCode() 方法的返回值相同。而 identityHashCode 值可以唯一标识该对象,因为这个方法是根据对象的地址计算得到的,所以任何两个对象的 identityHashCode 值总是不相等。
Runtime类
Runtime 类代表 Java 程序的运行时环境,每个 Java 程序都有一个与之对应的 Runtime 实例,应用程序通过该对象与其运行时环境相连。应用程序不能创建自己的 Runtime 实例,但可通过 getRuntime() 方法获取与之关联的 Runtime 对象。
Runtime 类代表 Java 程序运行时环境,可以访问 JVM 的相关信息,如处理器数量、内存信息等。如下程序所示。
public static void main(String[] args) {
///通过 getRuntime() 方法获取与之关联的 Runtime 对象
Runtime rt = Runtime.getRuntime();
System.out.println("处理器数量:" + rt.availableProcessors());
System.out.println("空闲内存数:" + rt.freeMemory());
System.out.println("总内存数" + rt.totalMemory());
System.out.println("可用最大内存数" + rt.maxMemory());
}
Object 类
Object 类是所有类、数组、枚举类的父类,也就是说 Java 允许把任何类型的对象赋给 Object 类型的变量。当定义一个类没有使用 extents 显式继承父类,则默认继承 Object 类。
因为 Java 类都是 Object 类的子类,所以任何 Java 对象都可调用 Object 类的方法。
常用方法:
- **boolean equals(Object obj):判断指定对象与该对象是否相等。相等标准是,两个对象时同一个对象。**和“==”作用是一样的,一般继承 Object 类的都会将该方法进行重写,以达到值相等的目的。
- **protected void finalize():**当系统中没有引用变量引用到该对象时,垃圾回收器会调用此方法来清理对象的资源。
- **Class<?>getClass():**返回该对象的运行时类。
- int hashCode(): 返回该对象的 hashCode 值。默认情况下,Object 类的 hashCode () 方法根据该对象的地址来计算。很多类都重写了 Object 类的 hashCode() 方法,例如String里的 hashCode() 方法根据字符序列计算 hashCode 值。
- String toString():返回该对象的字符串表示,当程序使用 System.out.println() 方法输出一个对象或者把某个对象和字符串进行连接运算时,系统会自动调用该对象的 toString() 方法返回该对象的字符串表示。**但很多类都重写了 Object 类的 toString() 方法,**用于返回可以表述该对象信息的字符串。
- 除此以外,Object 类还提供了 wait()、notify()、notifyAll()方法,用于控制线程的暂停和运行。
String、StringBuffer 和 StringBuilder 类
Java 提供了 String 和 StringBuffer 两个类来封装字符串,并提供了一系列方法来操作字符串对象。
String 类是不可变类,即一旦一个 String 对象被创建之后,包含在这个对象中的字符序列是不可改变,直至这个对象被销毁。
StringBuffer 对象则代表一个字符序列可变的字符串,当一个 StringBuffer 被创建之后,通过StringBuffer 提供的 append()、insert()、reverse()、setCharAt()、setLength()等方法可改变这个字符串对象的字符序列。通过这些方法生成想要的字符串后,可调用该类的 toString() 方法将其转换为一个 String 对象。
JDK1.5 新增了一个 StringBuilder 类,它也代表字符串对象。实际上,StringBuilder 和 Stringbuffer 基本相似,两个类的构造器和方法也基本相同。但不同的是,StringBuff 是线程安全的,而 StringBuilder 没有实现线程安全功能,所以性能越高。通常情况下创建一个内容可变的字符串对象,则优先考虑使用 StringBuilder 类。
下面是 String 类常用的构造器。
public static void main(String[] args) {
//创建字符串对象最常用的一种方式
String s1= "Hello World";
System.out.println(s1);
//这里只掌握常用的构造方法
byte[] bytes = {97,98,99};//97,98,99对应的ASCII码分别是a,b,c
String s2 = new String(bytes);
//输出一个引用的时候,会自动调用toString方法
//通过输出结果可知:String类已经重写toString()方法
//输出字符串对象,输出的不是对象的内存地址,而是字符串本身
System.out.println(s2);
//String(字节数组,数组元素下标的起始位置。长度)
//将byte数组中的一部分转换成字符串
String s3 = new String(bytes, 1, 2);
System.out.println(s3);
//将char数组全部转换成字符串
char[] chars = {'我', '爱', '你'};
String s4 = new String(chars);
System.out.println(s4);
//将char数组的一部分转换成字符串
String s5 = new String(chars, 1, 2);
System.out.println(s5);
}
String 类提供了大量方法来操作字符串对象,篇幅较长,我的水准很难超越这篇文章,所以阅读者可直接点击链接了解这些方法:https://www.cnblogs.com/mengta/p/10770774.html
StringBuilder、StringBuffer 有两个属性:length 和 capacity ,其中 length 属性表示其包含的字符序列的长度。与 String 对象的 length 不同的是,StringBuilder、StringBuffer 的 length 是可以改变的,可通过 length()、和 setLength(int len) 方法来访问和修改字符序列的长度。capacity 属性表示 StringBuilder 容量,程序通常无须关心 capacity 属性,因为其通常比 length大。
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
//追加字符串
sb.append("java"); //sb = "java"
//插入
sb.insert(0,"hello "); //sb = "hello java"
//替换
sb.replace(5,6,",");//sb = "hello,java"
//删除
sb.delete(5,6); //sb = "hellojava
System.out.println(sb);
//反转
sb.reverse();
System.out.println(sb);
System.out.println(sb.length());
System.out.println(sb.capacity());
//改变长度,只保留前面部分
sb.setLength(5);
System.out.println(sb);
}
Math 类
对于 Math 类需要记住一些比较常用的即可。
public static void main(String[] args){
/*
* 三角运算
*/
//将弧度转换为角度
System.out.println("Math.toDegrees(1.57):"+Math.toDegrees(1.57));
//将角度转换为弧度
System.out.println("Math.toRadians(90):"+Math.toRadians(90));
//计算反余弦,返回的角度范围在0.0到pi之间
System.out.println("Math.acos(1.2):"+Math.acos(1.2));
// 计算反正弦;返回的角度范围在 -pi/2 到 pi/2 之间。
System.out.println("Math.asin(0.8):" + Math.asin(0.8));
// 计算反正切;返回的角度范围在 -pi/2 到 pi/2 之间。
System.out.println("Math.atan(2.3):" + Math.atan(2.3));
// 计算三角余弦。
System.out.println("Math.cos(1.57):" + Math.cos(1.57));
// 计算值的双曲余弦。
System.out.println("Math.cosh(1.2 ):" + Math.cosh(1.2 ));
// 计算正弦
System.out.println("Math.sin(1.57 ):" + Math.sin(1.57 ));
// 计算双曲正弦
System.out.println("Math.sinh(1.2 ):" + Math.sinh(1.2 ));
// 计算三角正切
System.out.println("Math.tan(0.8 ):" + Math.tan(0.8 ));
// 计算双曲正切
System.out.println("Math.tanh(2.1 ):" + Math.tanh(2.1 ));
// 将矩形坐标 (x, y) 转换成极坐标 (r, thet));
System.out.println("Math.atan2(0.1, 0.2):" + Math.atan2(0.1, 0.2));
/*
* 取整运算
*/
// 取整,返回小于目标数的最大整数。
System.out.println("Math.floor(-1.2 ):" + Math.floor(-1.2 ));
// 取整,返回大于目标数的最小整数。
System.out.println("Math.ceil(1.2):" + Math.ceil(1.2));
// 四舍五入取整
System.out.println("Math.round(2.3 ):" + Math.round(2.3 ));
/*
* 下面是乘方、开方、指数运算
*/
// 计算平方根。
System.out.println("Math.sqrt(2.3 ):" + Math.sqrt(2.3 ));
// 计算立方根。
System.out.println("Math.cbrt(9):" + Math.cbrt(9));
// 返回欧拉数 e 的n次幂。
System.out.println("Math.exp(2):" + Math.exp(2));
// 返回 sqrt(x2 +y2)
System.out.println("Math.hypot(4 , 4):" + Math.hypot(4 , 4));
// 按照 IEEE 754 标准的规定,对两个参数进行余数运算。
System.out.println("Math.IEEEremainder(5 , 2):"
+ Math.IEEEremainder(5 , 2));
// 计算乘方
System.out.println("Math.pow(3, 2):" + Math.pow(3, 2));
// 计算自然对数
System.out.println("Math.log(12):" + Math.log(12));
// 计算底数为 10 的对数。
System.out.println("Math.log10(9):" + Math.log10(9));
// 返回参数与 1 之和的自然对数。
System.out.println("Math.log1p(9):" + Math.log1p(9));
/*
* 符号相关的运算
*/
// 计算绝对值。
System.out.println("Math.abs(-4.5):" + Math.abs(-4.5));
// 符号赋值,返回带有第二个浮点数符号的第一个浮点参数。
System.out.println("Math.copySign(1.2, -1.0):"
+ Math.copySign(1.2, -1.0));
// 符号函数;如果参数为 0,则返回 0;如果参数大于 0,
// 则返回 1.0;如果参数小于 0,则返回 -1.0。
System.out.println("Math.signum(2.3):" + Math.signum(2.3));
/*
* 大小相关的运算
*/
// 找出最大值
System.out.println("Math.max(2.3 , 4.5):" + Math.max(2.3 , 4.5));
// 计算最小值
System.out.println("Math.min(1.2 , 3.4):" + Math.min(1.2 , 3.4));
// 返回第一个参数和第二个参数之间与第一个参数相邻的浮点数。
System.out.println("Math.nextAfter(1.2, 1.0):"
+ Math.nextAfter(1.2, 1.0));
// 返回比目标数略大的浮点数
System.out.println("Math.nextUp(1.2 ):" + Math.nextUp(1.2 ));
// 返回一个伪随机数,该值大于等于 0.0 且小于 1.0。
System.out.println("Math.random():" + Math.random());
}
Random 和 ThreadLocalRandom
Random 类专门用于生成一个伪随机数的。而 ThreadLocalRandom 类是 Java 7 新增的一个类,是Random 的增强版。在并发访问环境下,使用 ThreadLocalRandom 来代替 Random 可以减少多线程资源竞争,保证系统有更好的线程安全性。
1、构造器。
Random() :创建一个新的随机数发生器。
Random(long seed) :用一个种子(长整型)创建一个随机数发生器。
2、方法。
- protected int next(int bits) :产生下一个伪随机数。
- boolean nextBoolean() :返回下一个从随机发生器的系列中得到的均匀分布的布尔值。
- void nextBytes(byte[] bytes) :产生随机字节数组放到指定的数组中。
- double nextDouble() :返回下一个从随机发生器的系列中得到的均匀分布的0.0到1.0的双精度类型值。
- float nextFloat() :返回下一个从随机发生器的系列中得到的均匀分布的0.0到1.0的浮点类型值。
- double nextGaussian() :返回下一个从随机发生器的系列中得到的符合均匀分布的0.0的平均数到1.0方差的高斯分布双精度类型值。
- int nextInt() :返回下一个从随机发生器的系列中得到的均匀分布的整型值。
- int nextInt(int n) :返回下一个从随机发生器的系列中得到的均匀分布的0到指定整型数(n)之间的整型值。
- long nextLong() :返回下一个从随机发生器的系列中得到的均匀分布的长整型值。
- void setSeed(long seed) :设置随机数发生器的种子为一个长整型数。
下面代码展示了这些方法的具体使用:
public static void main(String[] args) {
Random rand = new Random();
//返回下一个从随机发生器的系列中得到的均匀分布的布尔值。
System.out.println("rand.nextBoolean():"+rand.nextBoolean());
//产生随机字节数组放到指定的数组中。
byte[] buffer = new byte[4];
rand.nextBytes(buffer);
System.out.println(Arrays.toString(buffer));
//返回下一个从随机发生器的系列中得到的均匀分布的0.0到1.0的双精度类型值。
System.out.println("rand.nextDouble():"+rand.nextDouble());
//返回下一个从随机发生器的系列中得到的均匀分布的0.0到1.0的浮点类型值。
System.out.println("rand.nextFloat():"+rand.nextFloat());
//返回下一个从随机发生器的系列中得到的均匀分布的0到指定整型数(n)之间的整型值。
System.out.println("rand.nextInt():"+rand.nextInt());
//返回下一个从随机发生器的系列中得到的均匀分布的0到指定整型数(26)之间的整型值。
System.out.println("rand.nextInt(26):"+rand.nextInt(26));
//返回下一个从随机发生器的系列中得到的均匀分布的长整型值。
System.out.println("rand.nextLong():"+rand.nextLong());
//返回下一个从随机发生器的系列中得到的符合均匀分布的0.0的平均数到1.0方差的高斯分布双精度类型值。
System.out.println("rand.nextGaussian():"+rand.nextGaussian());
}
/*res:
rand.nextBoolean():false
[93, -7, -71, -98]
rand.nextDouble():0.28576150308425274
rand.nextFloat():0.9345345
rand.nextInt():1550984633
rand.nextInt(26):14
rand.nextLong():-558808779730933166
rand.nextGaussian():0.9807534516793011
在多线程下使用 ThreadLocalRandom 的方式与使用 Random 基本相似。但 ThreadLocalRandom 是通过 一个静态的 current() 方法来获取 ThreadLocalRandom 对象。代码如下:
ThreadLocalRandom rand = ThreadLocalRandom .current();
//生成一个4~20之间的伪随机整数
int vall = rand.nextInt(4,20);
//生成一个2.0~10.0之间的伪随机浮点数
int val2 = rand.nextDouble(2.0,10.0);
BigDecimal 类
因为 float、double 两个基本类型的浮点数容易引起精度丢失:
public static void main(String[] args) {
System.out.println("0.05+0.01=" + (0.05 + 0.01));
System.out.println("1.0-0.42=" + (1.0 - 0.42));
System.out.println("4.015*100=" + (4.015 * 100));
System.out.println("123.3/100=" + (123.3 / 100));
}
/*res:
0.05+0.01=0.060000000000000005
1.0-0.42=0.5800000000000001
4.015*100=401.49999999999994
123.3/100=1.2329999999999999
为了能精确表示、计算浮点数,Java 提供了 BigDecimal 类。
构造器
查看 BigDecimal 类的 BigDecimal(double val) 构造器说明时,看到不推荐使用该构造器的说明,主要是因为使用该构造器时有一定的不可预知性。当程序使用 new BigDecimal(0.1) 来创建一个对象时,它的值并不是 0.1 ,而是近似等于0.1的。这是因为 0.1 无法准确表示为 double 浮点数。如果需要使用double 的构造器时,不要直接将该 double 浮点数作为构造器的参数,而是通过 BigDecimal.valueOf(double val) 静态方法来创建 BigDecimal 对象。
如果使用 BigDecimal(String val) 构造器的结果是可预知的——写入 new BigDecimal(“0.1”)将创建一个 BigDecimal ,它正好等于预期的 0.1 。因此通常建议选择 BigDecimal(String val) 构造器。
BigDecimal 类提供了 add()、subtract()、multiply()、divide()、pow()等方法对精确浮点数进行常规算术运算。
下面的代码示范 BigDecimal 的基本运算:
public static void main(String[] args) {
BigDecimal f1 = new BigDecimal("0.05");
BigDecimal f2 = BigDecimal.valueOf(0.01);
BigDecimal f3 = new BigDecimal(0.05);
System.out.println("使用String作为BigDecimal构造器参数:");
System.out.println("0.05+0.01="+f1.add(f2));
System.out.println("0.05-0.01="+f1.subtract(f2));
System.out.println("0.05*0.01="+f1.multiply(f2));
System.out.println("0.05/0.01="+f1.divide(f2));
System.out.println("使用double作为BigDecimal构造器参数:");
System.out.println("0.05+0.01="+f3.add(f2));
System.out.println("0.05-0.01="+f3.subtract(f2));
System.out.println("0.05*0.01="+f3.multiply(f2));
System.out.println("0.05/0.01="+f3.divide(f2));
}
/*res:
使用String作为BigDecimal构造器参数:
0.05+0.01=0.06
0.05-0.01=0.04
0.05*0.01=0.0005
0.05/0.01=5
使用double作为BigDecimal构造器参数:
0.05+0.01=0.06000000000000000277555756156289135105907917022705078125
0.05-0.01=0.04000000000000000277555756156289135105907917022705078125
0.05*0.01=0.0005000000000000000277555756156289135105907917022705078125
0.05/0.01=5.000000000000000277555756156289135105907917022705078125
Process finished with exit code 0
从上面的运行结果,可以看出创建 BigDecimal 对象时,一定要用 String 对象作为构造器参数,而不是直接使用 double 数字。
Java 的日期、时间类
Java 提供了 Date 和 Calendar 用于处理日期、时间的类。其中由于 Date 不被官方推荐(因为 Date 类设计的很糟糕),所在本文着力介绍 Calendar 类。
Calender 类
**Calender 类是一个抽象类,用于表示日历。**所以不能使用构造器来创建 Calender 对象。它提供了几个静态 getInstance() 方法来获取 Calender 对象。通知 Calender 类提供了大量访问、修改日期时间的方法,常用方法如下:
- void add(int field,int amount):根据日历规则,为给定的日历字段添加或减去指定的时间量,若需要减少 amount 为负值即可。
- int get(int field):返回指定日历字段的值。
- int getActualMaximum(int field):返回指定日历字段可能拥有的最大值。例如月,最大值为11。
- int getActualMinimum(int field):返回指定日历字段可能拥有的最小值。例如月,最大值为0。
- void roll(int field,int amount):与 add() 方法相似,区别在于加上 amount 后超过该字段所能表示的最大范围时,也不会向上一个字段进位。
- void set(int field,int value):将给定的日历字段设置为给定值
- void set(int year,int month,int fate):设置 Calendar 对象的年、月、日三个字段的值
- void set(int year,int month,int fate,int hourOfDay,int minute,int second):设置 Calendar 对象的年、月、日、时、分、秒 6 个字段的值。
- field 是 Calendar 类的类变量。
public static void main(String[] args) {
Calendar c = Calendar.getInstance();
//分别取出年月日
System.out.println(c.get(Calendar.YEAR));
System.out.println(c.get(Calendar.MONTH));
System.out.println(c.get(Calendar.DATE));
//上面取出的月份比实际月份小一,是因为月份从0开始计数的
System.out.println("该日历最大的月份:"+c.getActualMaximum(Calendar.MONTH));
System.out.println("该日历最小的月份:"+c.getActualMinimum(Calendar.MONTH));
//分别设置年、月、日、时、分、秒 6 个字段的值
c.set(2022,2,24,00,00,00);
System.out.println(c.getTime());
//将 Calendar 的年往前推1年
c.add(Calendar.YEAR,-1);
System.out.println(c.getTime());
//将 Calendar 的月往前推2个月
c.roll(Calendar.MONTH,-2);
System.out.println(c.getTime());
}
/*res:
2022
1
23
该日历最大的月份:11
该日历最小的月份:0
Thu Mar 24 00:00:00 CST 2022
Wed Mar 24 00:00:00 CST 2021
Sun Jan 24 00:00:00 CST 2021
DateTimeFormatter 类
该类由 java.time.format 包提供的。该类相当于 DateFormat 和 SimpleDateFormat 的合体,功能非常强大,不仅可将日期、时间对象格式化成字符串,也可以将特定格式的字符串解析成日期、时间对象。
获取 DateTimeFormatter 对象有三种常见方式:
- 直接使用静态常量创建 DateTimeFormatter 格式器。 DateTimeFormatter 里包含了大量形如 ISO_LOCAL_DATE、ISO_LOCAL_TIME、ISO_LOCAL_DATE_TIME 等静态常量,都是 DateTimeFormatter 的实例。
- **使用代表不同风格的枚举值来创建 DateTimeFormatter 格式器。**在 FormatStyle 枚举类中定义了 FULL、LONG、MEDIUM、SHORT 四个枚举值,它们代表日期、时间的不同风格。
- 根据模式字符串来创建 DateTimeFormatter 格式器。
使用 DateTimeFormatter 将日期、时间(LocalDate、LocalDateTime、LocalTime等实例)格式换成字符串可通过下面方式:
- 调用 DateTimeFormatter 的 format(TemporalAccessor temporal) 方式执行格式化,其中LocalDate、LocalDateTime、LocalTime 等类都是 TemporalAccessor 接口的实现类。
- 调用 LocalDate、LocalDateTime、LocalTime 等日期、时间对象的 format(DateTimeFormatter formatter) 方法执行格式化。
以上两种方式用法相似,下面是程序示范:
public static void main(String[] args) {
DateTimeFormatter[] formatters = new DateTimeFormatter[]{
//直接使用常量创建DateTimeFormatter格式器
DateTimeFormatter.ISO_LOCAL_DATE,
DateTimeFormatter.ISO_LOCAL_TIME,
DateTimeFormatter.ISO_LOCAL_DATE_TIME,
//使用本地化不同风格来创建 DateTimeFormatter 格式器
DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL,FormatStyle.MEDIUM),
DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG),
//根据模式字符串来创建 DateTimeFormatter 格式器
DateTimeFormatter.ofPattern("Gyyyy%%MMM%%dd HH:mm:ss")
};
LocalDateTime date = LocalDateTime.now();
//依次使用不同格式器对 DateTimeFormatter 进行格式化
for(int i = 0;i < formatters.length;i++){
//下面两段代码作用一致
System.out.println(date.format(formatters[i]));
System.out.println(formatters[i].format(date));
}
使用 DateTimeFormatter 解析字符串
废话不多说,直接上代码。
public static void main(String[] args) {
//定义一个任意格式的日期、时间字符串
String str1 = "2022%%02%%26 06时36分08秒";
//根据需要选择格式器
DateTimeFormatter fomatter1 = DateTimeFormatter.ofPattern("yyyy%%MM%%dd HH时mm分ss秒");
//执行解析
LocalDateTime dt1 = LocalDateTime.parse(str1,fomatter1);
System.out.println(dt1);
}