本文最后更新于:2023年12月10日 16:55:06
本文中使用到的工具是Intellij IDEA和JDK 8,需要安装两款工具的请查看这两篇教程:点我查看安装JDK8/11/17教程 、点我查看安装Intellij IDEA教程 。
一、控制台输入类Scanner 假设今天我想在瓜摊买一个西瓜(西瓜的重量是10斤),西瓜两块钱一斤,此时使用Java程序代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class MyWatermelonDemo1 { public static void main (String[] args) { int price = 2 ; int weight = 10 ; int totalPrice = price * weight; System.out.println("西瓜的价格是: " + totalPrice + "元" ); } }
运行结果:
然而现实生活中西瓜的单价和重量是变化的,我们需要手动输入单价和重量,再将输入的内容进行计算。如果在Java代码中实现这一功能,就需要使用到控制台输入类Scanner
。
要想执行输入操作,需要创建一个Scanner
类型的对象,Scanner
类位于java.util
包中(包的概念后续会讲到),需要我们在类的上方手动导入。
1 import java.util.Scanner;
导入完成后,我们就可以在main
方法中创建Scanner
类型的对象了,在Scanner
的构造器中还需要传入一个参数System.in
表示从控制台输入,代码如下:
1 Scanner scanner = new Scanner (System.in);
此时我们就完成了scanner
对象的创建,此时我们就可以调用Scanner
类中的方法了,由于我们定义的是int
类型的变量,此时我们就可以使用Scanner
类中的nextInt()
方法实现输入功能,例如:
1 int price = scanner.nextInt();
在控制台输入的内容就会赋值给当前变量并且可以参与后续的运算。
以下是解决上述方案的完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import java.util.Scanner; public class MyWatermelonDemo2 { public static void main (String[] args) { Scanner scanner = new Scanner (System.in); System.out.println("请输入西瓜的单价: " ); int price = scanner.nextInt(); System.out.println("请输入西瓜的重量(按斤计算): " ); int weight = scanner.nextInt(); int totalPrice = price * weight; System.out.println("西瓜的单价是" + price + "元, 重量是" + weight + "斤, 价格是" + totalPrice + "元" ); } }1
运行结果:
除了boolean
和char
类型以外,其他七种数据类型都可以调用nextXxx()
方法,使用方式和上述过程完全相同:
基本数据类型
调用方法
byte
nextByte()
short
nextShort()
int
nextInt()
long
nextLong()
float
nextFloat()
double
nextDouble()
除了能输入数字以外,Scanner
类还提供了字符串输入的方法:next()
和nextLine()
。这两个方法都能在控制台输入字符串,二者的区别是:
next()
方法读取字符串,直到遇到空格、制表符Tab 和回车Enter 为止,如果这三个符号后面还存在其他字符,next()
方法都会省略。
nextLine()
方法读取字符串,直到遇到回车Enter 为止。即使当前行存在空格,也能正常输出。
以下是两种方法的使用案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.util.Scanner;public class MyWatermelonDemo3 { public static void main (String[] args) { Scanner scanner = new Scanner (System.in); System.out.println("请使用nextLine()方法输入内容,按回车键结束: " ); String strValue1 = scanner.nextLine(); System.out.println("使用nextLine()输出结果是: " + strValue1); System.out.println("请使用next()方法输入内容,按回车键结束: " ); String strValue2 = scanner.next(); System.out.println("使用next()输出结果是: " + strValue2); } }
运行结果:
二、数学类Math 在初高中我们学习的一些数学函数在Java中同样使用。这些数学函数都在Math
类中。
2.1 绝对值、两数的最小值和最大值 绝对值的概念:正数的绝对值是其本身,0的绝对值是0,负数的绝对值是其相反数。在Math
类中,我们可以调用静态方法Math.abs(number)
来获取number
的绝对值,其中number
的类型只能是int
、long
、float
、double
中的一种。
两数的最小值可以调用Math.min(number1, number2)
,如果number1 > number2
,那么得到的结果是number2
,反之,得到的结果是number1
。
两数的最大值可以调用Math.max(number1, number2)
,如果number1 > number2
,那么得到的结果是number1
,反之,得到的结果是number2
。
其中number1
和number2
需要保证是int
、long
、float
、double
中的一种。
以下是示例代码:
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 public class MathDemo1 { public static void main (String[] args) { int intValue1 = 20 ; int result1 = Math.abs(intValue1); double doubleValue1 = -2.45 ; double result2 = Math.abs(doubleValue1); float floatValue1 = 0.0f ; float result3 = Math.abs(floatValue1); System.out.println("----------取绝对值----------" ); System.out.println("result1 = " + result1); System.out.println("result2 = " + result2); System.out.println("result3 = " + result3); int intValue2 = 30 ; int intValue3 = 40 ; int result4 = Math.min(intValue2, intValue3); int result5 = Math.max(intValue2, intValue3); System.out.println("----------取最小值、最大值----------" ); System.out.println("result4 = " + result4); System.out.println("result5 = " + result5); } }
运行结果:
那么Math.abs()
、Math.min()
、Math.max()
为什么只支持int
、long
、float
、double
四种类型。我们使用Ctrl 和鼠标左键点击abs()
方法进入源码:
此时按Alt 和7 键,会列举出当前类所有的方法,此时我们在列表中直接输入abs
搜索,发现只有四个结果:
此时我们依次点击进入查看源码,发现它们支持的数据类型只有int
、long
、float
和double
。以int
类型的abs(int)
方法为例,我们发现方法内部就是一个三元运算符组成的表达式:
1 2 3 public static int abs (int a) { return (a < 0 ) ? -a : a; }
如果a < 0
,那么得到的结果就是其相反数-a
,反之,0和正数得到的绝对值就是其本身。long
、float
和double
的abs()
方法亦同理。
此时我们可以按照上述的方式找到min
和max
方法,发现二者也是仅支持int
、long
、float
和double
,方法列表如下:
以min(int, int)
方法为例,此时我们点击查看源码,发现这个方法体中也用到了三元表达式:
1 2 3 public static int min (int a, int b) { return (a <= b) ? a : b; }
如果a
小于等于b
,那么最小值就是a
,反之为b
。
而浮点类型的min(double, double)
方法源码则在此基础上做了进一步判断:
1 2 3 4 5 6 7 8 9 10 11 public static double min (double a, double b) { if (a != a) return a; if ((a == 0.0d ) && (b == 0.0d ) && (Double.doubleToRawLongBits(b) == negativeZeroDoubleBits)) { return b; } return (a <= b) ? a : b; }
如果参数a
的值是NaN(NaN是一个特殊的浮点类型的数值,表示无效或者无意义的数值结果,例如:0.0 / 0.0得到的结果没有意义,其结果就是NaN),由于NaN是无意义的结果,因此两个NaN的值比较结果就是false
。源码中的第一个if
判断就是针对NaN结果的判断,如果a
的确是NaN,那么比较的结果没有意义,返回的结果也就是变量a
本身的值NaN。
第二个比较主要是针对a
的值是0.0,b
的值是-0.0的情况,0.0在默认情况下无论前面加上正负号都是0.0,第三个条件中Double.doubleToRawLongBits()
方法是将当前按浮点数转换成64位的long
类型数,negativeZeroDoubleBits
就是上述方法默认的-0.0转换成long
类型的数字,如果此时Double.doubleToRawLongBits(b)
得到的结果和negativeZeroDoubleBits
的值完全相同,那么得到的结果是b
的值-0.0。
如果上述两个条件都不符合,那么就使用三元运算符进行比较,如果a
小于等于b
,返回值是a
,反之为b
。
2.2 数学常量$\pi$和$e$ 数学常量是指在数学领域中经常使用的,具有特定数值的量。在中学阶段,我们接触到的两个常量是圆周率$\pi$(3.1415926…)和自然对数$e$(2.7182818…)。这两个常量在Java的Math
类有存储,我们只需要调用Math.PI
即可获取$\pi$值,调用Math.E
即可获取$e$值。
1 2 3 4 5 6 7 8 9 10 11 12 public class MathDemo2 { public static void main (String[] args) { System.out.println("圆周率的值是: " + Math.PI); System.out.println("自然对数的值是: " + Math.E); } }
运行结果:
从运行结果中我们可以发现,Math.PI
和Math.E
只输出了小数点后的一部分,这是因为在Math
类中关于PI
和E
使用的是double
类型,由于double
的精度只有15位,因此输出结果保留了小数点后15位。
2.3 三角函数 在Math
类中定义了很多和三角函数相关方法,所有的三角函数得到的结果都是double
类型,这里选择了3个具有代表性的三角函数:
方法
说明
sin(a)
正弦函数
cos(a)
余弦函数
tan(a)
正切函数
和数学上的使用基本上一样,我们只需要确定a
的值即可。例如:$sin(\frac{\pi}{6})=0.5,cos(\frac{\pi}{3}=0.5),tan(\frac{\pi}{4})=1$,此时我们可以使用程序来检验一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class MathDemo3 { public static void main (String[] args) { double sinResult = Math.sin(Math.PI / 6 ); double cosResult = Math.cos(Math.PI / 3 ); double tanResult = Math.tan(Math.PI / 4 ); System.out.println("sinResult = " + sinResult); System.out.println("cosResult = " + cosResult); System.out.println("tanResult = " + tanResult); } }
运行结果:
但是从运行结果中我们可以发现得到的结果和预期的值相差“一点点”,出现上述情况的原因主要有两点:首先,计算机本身处理浮点类型的数值就不准确。另外,Math.PI
的值是小数点的后15位,做不到十分精确。因此得到的结果和期望值存在误差。
2.4 指数函数和对数函数 Math
类中定义了如下常用的指数函数和对数函数:
方法名
说明
sprt(a)
求a的平方根
pow(a, b)
求a的b次方,即$a^b$
exp(a)
求自然对数$e$的a次方,即$e^a$
log(a)
求以自然对数$e$为底,a的对数,即$ln(a)$
log10(a)
求以10为底,a的对数,即$log_{10}a$
以下是这些数学函数在代码中的应用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class MathDemo4 { public static void main (String[] args) { int number1 = 49 ; double result1 = Math.sqrt(number1); int number2 = 3 ; int number3 = 4 ; double result2 = Math.pow(number2, number3); double result3 = Math.exp(3 ); double result4 = Math.log(2 * Math.E); double result5 = Math.log10(100 ); System.out.println("result1 = " + result1); System.out.println("result2 = " + result2); System.out.println("result3 = " + result3); System.out.println("result4 = " + result4); System.out.println("result5 = " + result5); } }
运行结果:
2.5 数字的舍入操作 在进行数学运算时,我们可能需要对小数进行舍入操作(例如:四舍五入),Math
类为我们提供了以下四种关于小数舍入的方法:
方法名
返回类型
说明
ceil(x)
double
获取大于或等于当前数值的最小整数
floor(x)
double
获取小于或等于当前数值最大整数
rint(x)
double
获取当前数值最接近的整数,如果有两个相同接近的整数,取偶数
round(x)
double
四舍五入,舍入数字以第一位小数为基准
以下是这些数学函数在代码中的应用:
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 public class MathDemo5 { public static void main (String[] args) { double number1 = 2.46 ; double number2 = -2.34 ; double result1 = Math.ceil(number1); double result2 = Math.ceil(number2); System.out.println("result1 = " + result1); System.out.println("result2 = " + result2); System.out.println("--------------------" ); double result3 = Math.floor(number1); double result4 = Math.floor(number2); System.out.println("result3 = " + result3); System.out.println("result4 = " + result4); System.out.println("--------------------" ); double result5 = Math.rint(number1); double result6 = Math.rint(number2); double result7 = Math.rint(5.5 ); System.out.println("result5 = " + result5); System.out.println("result6 = " + result6); System.out.println("result7 = " + result7); System.out.println("--------------------" ); double result8 = Math.floor(number1); double result9 = Math.floor(number2); System.out.println("result7 = " + result8); System.out.println("result8 = " + result9); } }
运行结果:
2.6 随机数 Math
类中为我们提供了一个获取随机数的方法random()
,它默认在$[0,1)$范围内生成小数。我们可以利用这个范围,生成任意范围的数字。
例如:利用Math.random()
所给的范围,生成$[15, 60]$之间的随机数。
首先,整数范围$[15, 60]$可以等价写成$[15, 61)$。
再获取范围差:$61 - 15 = 46$,
利用不等式的性质,将原有的$[0, 1)$乘以46得到$[0, 46)$,再将现有的范围再加上15,即可获得目标范围:$[15, 61)$
总结:从$[0,1)$转换到$[15,61)$先乘以46,再加15即可。
以下上述案例在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 public class MathDemo6 { public static void main (String[] args) { double result1 = Math.random(); double result2 = Math.random(); double result3 = Math.random(); System.out.println("result1 = " + result1); System.out.println("result2 = " + result2); System.out.println("result3 = " + result3); System.out.println("--------------------" ); int randomNumber1 = (int ) (Math.random() * 46 + 15 ); int randomNumber2 = (int ) (Math.random() * 46 + 15 ); int randomNumber3 = (int ) (Math.random() * 46 + 15 ); System.out.println("randomNumber1 = " + randomNumber1); System.out.println("randomNumber2 = " + randomNumber2); System.out.println("randomNumber3 = " + randomNumber3); } }
每次得到的结果都不相同:
三、随机数类Random 前面我们学过Math.random()
方法来生成随机数,但是这个方法存在一个局限是它默认生成的范围是$[0,1)$之间的浮点数值,如果需要更大范围的随机数需要进行一定的计算并且需要进行强制类型转换,可能会导致代码可读性变低。
而接下来要提到的Random
类可以避免强制类型转换的问题,并且包含Math.random()
方法所不包含的一些特性。
3.1 随机数相关的概念 伪随机数:伪随机数是计算机利用特定的算法计算出来的$[0,1)$均匀分布的随机序列。虽然伪随机数并不是真正的随机数,但是它们具有类似随机数的统计特征:均匀性和独立性。在计算伪随机数时,如果使用的初始值(也称作随机数种子)不变,那么生成伪随机数的序列也不会改变。伪随机数可以使用程序大量生成。
随机数种子:随机数种子是在伪随机数生成器中用于生成伪随机数的初始数值 ,随机数种子一般是数字。在伪随机数生成器中,给定相同的种子值,将会生成相同的伪随机数的序列。
3.2 随机数类Random的使用 和前面讲过的Scanner
类一样,Random
类也在java.util
包中。创建随机数的方法如下:
1. 在类的上方导入Random
类:
1 import java.util.Random;
2. 创建一个Random
对象:有两种方式:一种是给定随机数,另外一种就是不给随机数:
构造方法
说明
Random(long)
传入一个long
类型的随机数种子,后续生成一个固定的随机数序列
Random()
如果构造方法中没有随机数,计算机会给定一个随机数种子。当然,后续生成的随机数列就不是固定的
1 2 Random random1 = new Random (20 ); Random random2 = new Random ();
3. 根据要生成的随机数类型,调用随机数方法,支持整数类型(int
和long
)、浮点型(float
和double
)和布尔类型(boolean
)。方法列表如下:
方法名称
说明
nextInt()
生成int
范围内的随机数
nextInt(int)
生成1到int
最大值范围内(不包含int
最大值)的随机数
nextLong()
生成long
范围内的随机数
nextFloat()
生成float
范围内的随机数
nextDouble()
生成double
范围内的随机数
nextBoolean()
随机生成true
或false
以下是上述方法的使用:
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 import java.util.Random;public class RandomDemo1 { public static void main (String[] args) { Random random1 = new Random (); int result1 = random1.nextInt(); int result2 = random1.nextInt(60 ); long result3 = random1.nextLong(); float result4 = random1.nextFloat(); double result5 = random1.nextDouble(); boolean result6 = random1.nextBoolean(); System.out.println("result1 = " + result1); System.out.println("result2 = " + result2); System.out.println("result3 = " + result3); System.out.println("result4 = " + result4); System.out.println("result5 = " + result5); System.out.println("result6 = " + result6); System.out.println("--------------------" ); Random random2 = new Random (20 ); for (int i = 0 ; i < 5 ; i++) { int randomValue = random2.nextInt(); System.out.println("randomValue" + (i + 1 ) + " = " + randomValue); } } }
运行结果:
我们也可以使用Random
解决上述生成随机数问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import java.util.Random;public class RandomDemo2 { public static void main (String[] args) { Random random = new Random (); int result = random.nextInt(46 ) + 15 ; System.out.println("result = " + result); } }
多运行几次程序,我们发现生成的随机数确实在$[15,60]$范围内:
以上是使用Random
类生成随机数,相对于Math.random()
而言,生成随机数可以省去强制类型转换,相对方便了一些。
Random
类是一个方便实用的工具类,它提供了各种方法来获取不同类型和范围的随机数,适用于各种模拟、游戏、密码学等方面应用。通过使用Random
类,开发人员可以轻松地生成具有良好随机性和不可预测性的伪随机数,从而提高应用程序的灵活性和效率。