Java: 从用户界面启动时如何获得确定性方法结果?
Java: How can I get a deterministic method result when it is launched from a user interface?
我正在使用 java 来处理模拟,
如果我从静态主函数启动模拟,一切都是确定的,每次我点击 运行 as -> Java 应用程序时我都会得到相同的模拟,即使我关闭并重新打开 eclipse,这是足以调试程序。
但是当我使用相同的参数多次从 GUI(libgdx)启动模拟时,结果每次都会改变。
我怀疑在 GUI 期间执行的代码不完全相同(因为我不是机器人),这导致某些 类 例如 HashSet 具有不确定的迭代。
如何获得与静态 main 方法相同的行为?
如有任何建议,我们将不胜感激
编辑:如询问代码,有一个问题实例:
public class Test{
private static final int n = 4;
public static void main(final String[] args)
{
// random HashSet in my GUI uses Object.hashcode
for(int i = 0; i < n; i ++)
{
new Test().hashCode();
}
// at some point launches the simulation
simulation();
}
public static void simulation()
{
// HashSet anywere in the simulation uses hashcode
System.out.println(new Test().hashCode());
}
}
simulation() 的结果取决于 n(取决于 GUI 期间发生的事情),所以我只想摆脱 GUI 的影响和 运行 静态方法模拟分开,但如何?
Object#hashCode
可能在 运行s
之间变化
您的代码正在调用 hashCode
method on an instance of your Test
class, a method inherited from Object
。
Java 的实现通常通过散列对象内存地址的等价物或某些此类值来实现该方法。引用 Object#hashCode
.
的 Javadoc
The hashCode may or may not be implemented as some function of an object's memory address at some point in time.
虽然不一定如此,但如果实现使用内存地址方案,可以想象控制台应用程序的连续 运行s 可能最终在每个 [=84] 上具有相同的哈希码值=].但你当然不应该期望那样。引用 Java 文档:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
与控制台应用程序相比,GUI 应用程序要复杂得多,它与主机 OS 交互以建立 windows、菜单等。人们可以在这里想象,在 GUI 应用程序的执行 运行 上建立的对象可能会产生稍微不同的对象,足以使根据与内存布局相关的东西计算的哈希码在 运行 之间可能会有所不同。
你说:
If I launch the the simulation from a static main function, everything is deterministic and I get the same simulation each time I hit Run as -> Java application
正如上面引用的 Javadoc 的最后一句话所说:您可能会或可能不会在单独的 运行 上获得相同的哈希码 你的应用程序。
➥ 在一天结束时,none 这很重要。 您不应依赖于在您的应用程序执行之间从 hashCode
方法 返回的相同值。在 应用程序执行期间,您只能依赖相同的哈希码 。
所以你的问题“我怎样才能获得与静态 main 方法相同的行为?”是没有实际意义的。 您不应该期望 运行 之间的散列码相同 。为什么不?因为文档是这么说的。
UUID
从字里行间看出,我猜您正试图将哈希码值用作永久唯一标识符。那是不是散列码的目的。
相反,请考虑使用 universally unique identifier (UUID). Java bundles the UUID
class 来表示这些 128 位值。
如果你想为你的对象指定一个 UUID 值,你可以使用工厂方法构造一个,该方法将规范的文本表示解析为带有连字符分隔的数字分组的十六进制字符串。您可以使用 this 等网站手动生成一些值。或者使用软件手动生成UUID值。
record Dog ( UUID id , String name ) {}
Dog spot =
new Dog(
UUID.fromString( "05ffbad6-b75b-11eb-8529-0242ac130003" ) ,
"Spot"
)
;
在 Java 16 中使用 record 时,编译器通过使用每个成员自动覆盖从 Object
继承的 equals
和 hashCode
方法场.
或者,使用 UUID
作为标识符,您可能只想为 equals
/hashCode
使用一个成员字段。在这种情况下,您自己手动覆盖这两个方法。同上传统的 class 代替记录。
public record Dog( UUID id , String name )
{
@Override
public boolean equals ( final Object o )
{
if ( this == o ) return true;
if ( o == null || getClass() != o.getClass() ) return false;
final Dog dog = ( Dog ) o;
return id.equals( dog.id );
}
@Override
public int hashCode ( )
{
return Objects.hash( id );
}
}
有了这些覆盖,狗的名字上的拼写错误将不计入相等性或 hashCode。
Dog x =
new Dog(
UUID.fromString( "05ffbad6-b75b-11eb-8529-0242ac130003" ) ,
"Spot"
);
Dog y =
new Dog(
UUID.fromString( "05ffbad6-b75b-11eb-8529-0242ac130003" ) ,
"spoht"
);
boolean sameDog = x.equals( y );
boolean sameHashCode = ( x.hashCode() == y.hashCode() );
sameDog = true
sameHashCode = true
我正在使用 java 来处理模拟, 如果我从静态主函数启动模拟,一切都是确定的,每次我点击 运行 as -> Java 应用程序时我都会得到相同的模拟,即使我关闭并重新打开 eclipse,这是足以调试程序。
但是当我使用相同的参数多次从 GUI(libgdx)启动模拟时,结果每次都会改变。
我怀疑在 GUI 期间执行的代码不完全相同(因为我不是机器人),这导致某些 类 例如 HashSet 具有不确定的迭代。
如何获得与静态 main 方法相同的行为?
如有任何建议,我们将不胜感激
编辑:如询问代码,有一个问题实例:
public class Test{
private static final int n = 4;
public static void main(final String[] args)
{
// random HashSet in my GUI uses Object.hashcode
for(int i = 0; i < n; i ++)
{
new Test().hashCode();
}
// at some point launches the simulation
simulation();
}
public static void simulation()
{
// HashSet anywere in the simulation uses hashcode
System.out.println(new Test().hashCode());
}
}
simulation() 的结果取决于 n(取决于 GUI 期间发生的事情),所以我只想摆脱 GUI 的影响和 运行 静态方法模拟分开,但如何?
Object#hashCode
可能在 运行s
之间变化
您的代码正在调用 hashCode
method on an instance of your Test
class, a method inherited from Object
。
Java 的实现通常通过散列对象内存地址的等价物或某些此类值来实现该方法。引用 Object#hashCode
.
The hashCode may or may not be implemented as some function of an object's memory address at some point in time.
虽然不一定如此,但如果实现使用内存地址方案,可以想象控制台应用程序的连续 运行s 可能最终在每个 [=84] 上具有相同的哈希码值=].但你当然不应该期望那样。引用 Java 文档:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
与控制台应用程序相比,GUI 应用程序要复杂得多,它与主机 OS 交互以建立 windows、菜单等。人们可以在这里想象,在 GUI 应用程序的执行 运行 上建立的对象可能会产生稍微不同的对象,足以使根据与内存布局相关的东西计算的哈希码在 运行 之间可能会有所不同。
你说:
If I launch the the simulation from a static main function, everything is deterministic and I get the same simulation each time I hit Run as -> Java application
正如上面引用的 Javadoc 的最后一句话所说:您可能会或可能不会在单独的 运行 上获得相同的哈希码 你的应用程序。
➥ 在一天结束时,none 这很重要。 您不应依赖于在您的应用程序执行之间从 hashCode
方法 返回的相同值。在 应用程序执行期间,您只能依赖相同的哈希码 。
所以你的问题“我怎样才能获得与静态 main 方法相同的行为?”是没有实际意义的。 您不应该期望 运行 之间的散列码相同 。为什么不?因为文档是这么说的。
UUID
从字里行间看出,我猜您正试图将哈希码值用作永久唯一标识符。那是不是散列码的目的。
相反,请考虑使用 universally unique identifier (UUID). Java bundles the UUID
class 来表示这些 128 位值。
如果你想为你的对象指定一个 UUID 值,你可以使用工厂方法构造一个,该方法将规范的文本表示解析为带有连字符分隔的数字分组的十六进制字符串。您可以使用 this 等网站手动生成一些值。或者使用软件手动生成UUID值。
record Dog ( UUID id , String name ) {}
Dog spot =
new Dog(
UUID.fromString( "05ffbad6-b75b-11eb-8529-0242ac130003" ) ,
"Spot"
)
;
在 Java 16 中使用 record 时,编译器通过使用每个成员自动覆盖从 Object
继承的 equals
和 hashCode
方法场.
或者,使用 UUID
作为标识符,您可能只想为 equals
/hashCode
使用一个成员字段。在这种情况下,您自己手动覆盖这两个方法。同上传统的 class 代替记录。
public record Dog( UUID id , String name )
{
@Override
public boolean equals ( final Object o )
{
if ( this == o ) return true;
if ( o == null || getClass() != o.getClass() ) return false;
final Dog dog = ( Dog ) o;
return id.equals( dog.id );
}
@Override
public int hashCode ( )
{
return Objects.hash( id );
}
}
有了这些覆盖,狗的名字上的拼写错误将不计入相等性或 hashCode。
Dog x =
new Dog(
UUID.fromString( "05ffbad6-b75b-11eb-8529-0242ac130003" ) ,
"Spot"
);
Dog y =
new Dog(
UUID.fromString( "05ffbad6-b75b-11eb-8529-0242ac130003" ) ,
"spoht"
);
boolean sameDog = x.equals( y );
boolean sameHashCode = ( x.hashCode() == y.hashCode() );
sameDog = true
sameHashCode = true