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图吧:

java 自动生成toString java 自动生成变量_整数溢出


程序实例如下:

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

尽管最后交换的效果达到了,但是交换过程中出现了溢出的情况。
因此,这次留下两个问题,【第一个是溢出为什么不影响交换结果?】,【第二个是有没有其他方法实现变量值的交换?】。
下次再写!!!