0.开头
今天在看书的时候,随手把简单的减法程序又写了一下;如下:
import java.util.Random;
import java.util.Scanner;
import static java.lang.System.*;
public class SubtractionQuiz {
public static void main(String[]args){
int number1,number2;
//创建[0,10)之间整数的第一种方法
number1 = (int)(Math.random()*10);
number2 = (int)(Math.random()*10);
//不创建新变量的情况下,交换两个变量的值
if(number1<number2){
number1 = number2-number1;
number2 = number2-number1;
number1 = number2+number1;
}
Scanner input = new Scanner(System.in);
System.out.println("What is "+number1+"-"+number2+":");
int answer = input.nextInt();
if(answer==(number1-number2)){
System.out.println("Your answer is right!");
}else{
System.out.println("Your answer is wrong!");
}
}
}
- 大概就是随机生成两个数,求他们相减的结果。
- 虽然程序简单,但是其中涉及到的随机数和变量值交换值得记一下。
- 当然,其中的变量值不需要交换也可以完成这个程序,这里只是针对这个书上的程序说一下。
1.随机数的生成
Java生成随机数通常有两种方法:Math.random()和Random类。
- Math.random()方法
这个方法返回[0,1)这个区间的double类型的数,注意是左闭右开。
看一下源码的注释:
Returns a {@code double} value with a positive sign, greater than or equal to {@code 0.0} and less than {@code 1.0}. - Random类
(1)通过创建Random类的实例,调用其中的方法可以实现多种数据类型数据的随机生成。
(2)构造方法有两个,Random()和Random(long seed),其中的参数被称为种子,如果不传入则默认以seedUniquifier()^System.nanoTime()【不知道这个nanoTime方法是什么的话,可以查看我的另一篇博客】为种子;
源码如下:
public Random() {
this(seedUniquifier() ^ System.nanoTime());
}
public Random(long seed) {
if (getClass() == Random.class)
this.seed = new AtomicLong(initialScramble(seed));
else {
// subclass might have overriden setSeed
this.seed = new AtomicLong();
setSeed(seed);
}
}
我们暂时不管这里的种子seed问题,先看一下创建对象之后可以调用什么方法如何实现随机数。
这里给出方法表格:
方法 | 解释 |
boolean nextBoolean() | 随机生成一个布尔值 |
double nextDouble() | 随机生成一个double值 ,范围是[0,1),这个方法和Math.random()效果一致 |
int nextInt() | 随机生成一个int值,范围是整个int取值范围,即[-2 ^ 31, 2 ^ 31-1] |
int nextInt(int n) | 随机生成一个int值,范围是[0, n) |
其他类似。
顺便附一下API图吧:
程序实例如下:
import java.util.Random;
public class RandomDemo {
public static void main(String[]args){
Random random1 = new Random();
Random random2 = new Random(10);
System.out.println(random1.nextBoolean());
System.out.println(random1.nextDouble());
System.out.println(random1.nextInt());
System.out.println(random2.nextInt());
System.out.println(random1.nextInt(5));
}
}
结果如下:
false
0.9248622022817408
1943808773
-1157793070
1
2.seed种子问题
已经基本解决了Math.random()和Random()的用法之后,我们来讨论一下seed到底是什么东东?????
引用一下其他大佬的结论:
种子就是产生随机数的第一次使用值,机制是通过一个函数,
将这个种子的值转化为随机数空间中的某一个点上,
并且产生的随机数均匀的散布在空间中。以后产生的随机数都与前一个随机数有关。
总之:种子确定的情况下,其实是可以推出或者说预测下面的数据的。所以我们说生成的随机数其实是伪随机数pseudorandom.不信的话,我们举个例子来看,创建两个种子一样的Random类。
import java.util.Random;
public class RandomDemo {
public static void main(String[]args){
Random random1 = new Random(10);
Random random2 = new Random(10);
System.out.println("random1生成的第一个数:"+random1.nextInt());
System.out.println("random2生成的第一个数:"+random2.nextInt());
System.out.println("random1生成的第二个数:"+random1.nextInt());
System.out.println("random2生成的第二个数:"+random2.nextInt());
System.out.println("random1生成的第三个数:"+random1.nextInt());
System.out.println("random2生成的第三个数:"+random2.nextInt());
}
}
结果如下:
random1生成的第一个数:-1157793070
random2生成的第一个数:-1157793070
random1生成的第二个数:1913984760
random2生成的第二个数:1913984760
random1生成的第三个数:1107254586
random2生成的第三个数:1107254586
我们发现相同的种子产生的随机数是一个固定的序列。
我们将程序稍微改一下:
import java.util.Random;
public class RandomDemo {
public static void main(String[]args){
Random random1 = new Random(10);
Random random2 = new Random(10);
System.out.println("random1生成的第一个数:"+random1.nextInt(100));
System.out.println("random2生成的第一个数:"+random2.nextInt(100));
System.out.println("random1生成的第二个数:"+random1.nextInt(100));
System.out.println("random2生成的第二个数:"+random2.nextInt(100));
System.out.println("random1生成的第三个数:"+random1.nextInt(100));
System.out.println("random2生成的第三个数:"+random2.nextInt(100));
}
}
random1生成的第一个数:13
random2生成的第一个数:13
random1生成的第二个数:80
random2生成的第二个数:80
random1生成的第三个数:93
random2生成的第三个数:93
结论是一样的!所以在使用的时候,其实不添加seed生成的随机数其实才更“随机”。
3.变量值交换的问题
本章先介绍两种常见的简单方法。
- 引入temp第三个变量实现:
这个比较好理解,如下:
int i1 = 88;
int i2 = 99;
int temp = i1;
i1 = i2;
i2 = temp;
但是这个方法需要创建temp变量,实际上不需要第三方变量也能实现。
- 两个变量自身加减法实现(不引入第三个变量):
//减法
int number1 = 11;
int number2 = 33;
number1 = number2-number1;
number2 = number2-number1;
number1 = number2+number1;‘
//加法
int number3 = 22;
int number4 = 66;
number3 = number4+number3;
number4 = number3-number4;
number3 = number3-number4;
我们仔细观察其实能看出来,上面这种不引入第三方变量的方法存在一个隐患。那就是如果number1-number2或者number3+number4存在[整数溢出]的风险。
比如下面这种情况:
public class ValueExchange {
public static void main(String[]args){
int number3 = 2147483647;
int number4 = 2147483647-2;
System.out.println("Number3="+number3);
System.out.println("Number4="+number4);
number3 = number4+number3;
System.out.println("Number3中间值="+number3);
number4 = number3-number4;
number3 = number3-number4;
System.out.println("Number3="+number3);
System.out.println("Number4="+number4);
}
}
Number3=2147483647
Number4=2147483645
Number3中间值=-4
Number3=2147483645
Number4=2147483647
尽管最后交换的效果达到了,但是交换过程中出现了溢出的情况。
因此,这次留下两个问题,【第一个是溢出为什么不影响交换结果?】,【第二个是有没有其他方法实现变量值的交换?】。
下次再写!!!