随机数的类为Random,命名空间为System。
转到Random的定义可以看到如下代码(我把注释删掉了):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | namespace System { public class Random { public Random(); public Random( int Seed);<br> public virtual int Next(); public virtual int Next( int minValue, int maxValue); public virtual int Next( int maxValue); public virtual void NextBytes( byte [] buffer); public virtual double NextDouble(); protected virtual double Sample(); } } |
我们从易到难挨个说说。
Random();
这是无参构造方法,比如在程序中这样写:
Random a = new Random(); |
得到的a就是一个随机数生成器,它可以用来生成随机数。
int Next();
这个方法返回值为int类型,调用它就能得到一个随机数,反复调用就能反复得到随机数。
例:
1 2 3 4 5 6 7 8 9 10 | static void Main( string [] args) { Random a = new Random(); for ( int i = 0; i < 10; i++) { Console.WriteLine(a.Next()); } Console.ReadKey(); } |
这样就得到了10个随机数,运行结果如下:
需要注意的是,虽然看上去Next方法返回值是int类型,但实际上它只返回非负整数,而且不包括int类型能表示的最大的那个整数(2^31 - 1)
int Next(int minValue, int maxValue);
这个方法能指定随机数的生成范围,左闭右开区间,即生成的数能包含minValue,不包含maxValue。可以包含负数。但是maxValue的值不能大于minValue的值,否则运行时会抛出异常。
int Next(int maxValue);
这个方法指定随机数的最大值(不包含maxValue),并且它也只能生成非负整数,与Next(0, maxValue)是一个道理,如果传入的maxValue为负数,那么运行时抛出异常,如果maxValue的值为0或1,那么生成的随机数只能是0。
double NextDouble();
这个方法能返回一个大于或等于 0.0 且小于 1.0 的随机浮点数。
void NextBytes(byte[] buffer);
这个方法传入指定长度的byte类型的数组,用byte类型的随机数填充数组,如:
1 2 3 4 5 6 7 8 9 10 11 12 13 | static void Main( string [] args) { Random a = new Random(); byte [] b = new byte [10]; a.NextBytes(b); foreach ( byte i in b) { Console.WriteLine(i); } Console.ReadKey(); } |
运行结果:
double Sample();
这个方法比较特殊,从声明可以看出来,其他的方法权限都是public,这个方法是protected。从方法的描述上能看到,这个方法返回的也是大于或等于 0.0 且小于 1.0 的随机浮点数,它与NextDouble看上去似乎只是权限不一样,看了下面这段代码就知道了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | namespace sdq { class MyRandom : Random { protected override double Sample() { return 0.125; } } class Program { static void Main( string [] args) { MyRandom a = new MyRandom(); for ( int i = 0; i < 10; i++) { Console.WriteLine(a.NextDouble()); } Console.ReadKey(); } } } |
代码分析:
首先定义了一个类MyRandom,继承至Random,由于Random中的Sample()是虚方法,因此可以在派生类中将Sample()重写,我在这里是将它固定返回0.125。在Main方法中构造了a这个对象,并且调用了a.NextDouble()去生成10个随机数,运行结果如下:
从结果可以看出来,Random的Sample方法可以改变NextDouble()方法的行为,如果用户想自定义获取随机数的方法,则可以通过重写Sample来实现。
Random(int Seed);
最后再说一下这个带参构造函数,它用来在构造对象时指定随机数生成器的种子,而不带参的构造函数则是以时间作为种子。至于种子是个什么东西,我也不知道,通过下面这个例子也许能说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | using System; using System.Threading; namespace test { class Program { static void Main( string [] args) { Random a = new Random(123); Thread.Sleep(1000); Random b = new Random(123); for ( int i = 0; i < 10; i++) { Console.WriteLine( "{0}\t{1}" , a.Next(), b.Next()); } Console.ReadKey(); } } } |
执行结果:
可见a对象和b对象是使用相同的种子123构造出来的,之后它们每次生成的随机数的值都是一样的。而如果使用默认的构造方法(以时间为种子)则不会有这种情况。
注:之所以调用Thread.Sleep(1000);是为了错开两次构造随机数对象的时间,如果不这么做的话,使用默认构造方法,连续两次调用Random()得到的结果仍然可能会一样,因为两次调用Random()时的时间是一样的。
我还没有去研究过windows系统时间的最小单位,按一般经验判断可能是us,想想1us内调用两次构造方法时间是够够的吧。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
2021-02-02 保护临界资源——互斥锁