当前位置: 首页 > 知识库问答 >
问题:

对象,如随机变量(局部变量和实例变量)

虞俊美
2023-03-14

假设我有下面的类:每次Meow调用时,都会在堆上创建一个新的随机对象。

public class Cat {
    public void Meow() {
        Random rand = new Random(); 
        if (rand.nextInt() == 0) {
            System.out.println("Meow...");
        }
    }
}

我是否应该将随机对象从Meow方法中取出,并像这样将它从局部变量改为实例变量?因此,每次Meow调用相同的随机对象时,将使用在堆上创建的cat对象,而不是像上面的方法那样使用一个新的对象。

public class Cat {
    Random rand; 
    public Cat(){
        rand = new Random(); 
    }

    public void Meow() {
        if (rand.nextInt() == 0) {
            System.out.println("Meow...");
        }
    }
}

我试图理解第二种方法是否是一个最佳实践,因为即使我的程序很小,它也不会是一个大问题,也许以后如果程序变大了,它会帮助我防止性能问题。

共有2个答案

慕承恩
2023-03-14

两者都可以。如果要在其他方法上使用随机数,可以全局声明它。但是,如果您只在声明它的方法中使用它,则可以在本地声明它。

至于表现。我不认为会有问题,因为我在编码时没有遇到性能问题。试着查看这篇帖子上的评论“在你有性能问题之前不要太担心性能”。

明阳旭
2023-03-14

是的,您应该--我甚至要说必须--重用单个random对象。否则,如果快速连续调用该方法,您将得到相同的数字。

PRNG(伪随机数生成器)的工作原理是获取初始种子值,然后一遍又一遍地变换它,以产生一个确定的数字序列。同样的种子会产生同样的“随机”数字。

NB如果你需要(真的吗?)随机性适用于加密或安全敏感操作,不惜一切代价避免类random和同级类ThreadLocalRandom。在这种情况下,至关重要的是使用一个提供加密性强的随机数生成器的类,例如securerandom

Edit:我刚刚检查了Random类的OpenJDK源代码,它似乎做了特殊的处理,使new Random()的多个调用产生不同的序列(即,植入不同的初始值)。但是,你不能依赖它。

使用静态字段,您不依赖于random构造函数的实现细节。

但继续读下去…

比实例字段更好的是类字段(即static)。否则,多个实例可能再次产生相同的结果序列。

public class Cat {
  private static final Random RANDOM = new Random();
  public void Meow() {
    if (RANDOM.nextBoolean()) {
      // do meow
    }
  }
}

为什么这很重要?new Random()将随机数生成器作为当前进程正常运行时间的种子。请考虑以下内容:

final Cat cat = new Cat();
cat.meow();
cat.meow(); // likely to produce the same random number as the previous line.

转换为实例变量也有同样的缺点:

final Cat garfield = new Cat();
final Cat hobbes = new Cat(); // again likely to use the same seed
garfield.meow();
hobbes.meow();

静态字段还有另一个好处:节省内存。全局上(对于该类)只存在Random的一个实例,而不是每个CAT有一个随机实例。根据你计划在你的计划中养猫的数量,节省的费用会有很大的不同。

不过有一个警告:random实例是线程安全的(这很好),但是如果从多个线程访问,它们可能是一个瓶颈。

random的JavaDoc:

java.util.random的实例是线程安全的。但是,跨线程并发使用相同的java.util.random实例可能会遇到争用和随之而来的性能差。考虑在多线程设计中使用java.util.concurrent.ThreadLocalRandom。

如何使用ThreadLocalRandom

public void meow() {
  if (ThreadLocalRandom.current().nextBoolean()) {
    // do meow
  }
}

您不能将当前的ThreadLocalRandom存储在字段中,因为这样它就会泄漏到不同的线程。确保该类的一个实例仅由单个线程访问。如果在紧密循环中使用,则将其存储在局部变量中,并重用该变量。

 类似资料:
  • 主要内容:局部变量,全局变量,局部变量和全局变量的综合示例在《 C语言形参和实参的区别》中提到,形参变量要等到函数被调用时才分配内存,调用结束后立即释放内存。这说明形参变量的作用域非常有限,只能在函数内部使用,离开该函数就无效了。 所谓 作用域( Scope ) ,就是变量的有效范围。 不仅对于形参变量,C语言中所有的变量都有自己的作用域。决定变量作用域的是变量的定义位置。 局部变量 定义在函数内部的变量称为 局部变量(Local Variable) ,

  • 问题内容: 我读到Java为类属性提供了默认值,但没有为局部变量提供默认值。那是对的吗?如果是这样,背后的原因是什么?当您做某件事时,为什么不一直这样做呢? 谢谢你, 罗杰 问题答案: 标准局部变量存储在堆栈中,直到初始化后才真正创建。如果未使用局部变量,则它不会进入堆栈。但是,成员变量在堆中分配,因此具有默认的占位符(空引用或默认原语)。

  • 主要内容:Python局部变量,Python全局变量,获取指定作用域范围中的变量所谓 作用域(Scope),就是变量的有效范围,就是变量可以在哪个范围以内使用。有些变量可以在整段代码的任意位置使用,有些变量只能在函数内部使用,有些变量只能在 for 循环内部使用。 变量的作用域由变量的定义位置决定,在不同位置定义的变量,它的作用域是不一样的。本节我们只讲解两种变量, 局部变量和 全局变量。 Python局部变量 在函数内部定义的变量,它的作用域也仅限于函数内部,出了函数就不能

  • 问题 你想创建类变量和实例变量(属性)。 解决方案 类变量 class Zoo @MAX_ANIMALS: 50 MAX_ZOOKEEPERS: 3 helpfulInfo: => "Zoos may contain a maximum of #{@constructor.MAX_ANIMALS} animals and #{@MAX_ZOOKEEPERS} zoo keep

  • 和 C 语言一样,按照变量的作用域,我们可以把变量划分为局部变量和全局变量 Go 语言中局部变量的概念以及全局变量的概念和C语言一模一样 局部变量: 定义在函数内部的变量以及函数的形参称为局部变量 作用域:从定义哪一行开始直到与其所在的代码块结束 生命周期:从程序运行到定义哪一行开始分配存储空间到程序离开该变量所在的作用域 全局变量: 定义在函数外面的变量称为全局变量 作用域范围:从定义哪行开始直

  • 局部变量使用关键字 def 来声明,其只在声明它的地方可见 . 局部变量是 Groovy 语言的一个基本特性. 例子 13.2 . 使用局部变量 def dest = "dest" task copy(type: Copy) { form "source" into dest }