gpt4 book ai didi

java - 打开 EnumSet

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:25:45 26 4
gpt4 key购买 nike

旧方法,如果我们想在一些复杂的位掩码上切换,我们可以很容易地这样做(我头脑中的一个随机示例只是为了演示这个问题):

private static final int   MAN = 0x00000001;
private static final int WOMAN = 0x00000002;
// ...alive, hungry, blind, etc.
private static final int DEAD = 0xFF000000;

public void doStuff(int human) {
switch (human) {
case MAN | DEAD:
// do something
break;
// more common cases
}
}

如今,由于我们使用 enumsEnumSets,有时我想做类似的事情:

enum Human {
MAN, WOMAN, DEAD; // etc.
}

public void doStuff(EnumSet human) {
switch (human) {
case Human.MAN | Human.DEAD:
// do something
break;
// more common cases
}
}

这是行不通的,因为我们只能在 intenumString 值上switch .在这一点上,我意识到这是不可能的,即使 enum 值基本上只是隐藏的整数。但我喜欢四处挖掘,这个功能看起来非常有用,所以:

private static final EnumSet<Human> DEAD_MAN = EnumSet.of(Human.MAN, Human.DEAD);

public void doStuff(EnumSet human) {
switch (human) {
case DEAD_MAN:
// do something
break;
// more common cases
}
}

仍然没有运气。 Knowing the trick for switch on Strings并且 EnumSets 实际上是 64 位字段(或它们的数组),我也会尝试:

    switch (human.hashCode()) {
case (Human.MAN.hashCode() | Human.DEAD.hashCode()):
// do something
break;
// more common cases
}

认为当 Human hashCode() 被正确实现以提供一致的结果时,它可以工作。不:

java.lang.Error: Unresolved compilation problem: case expressions must be constant expressions


现在,我想知道为什么不可能这样做。我一直认为 Java 中的 enumsEnumSets 是那些老式位域的适当替代品,但在这里,新方法似乎无法处理更复杂的情况。

与任何 switch 可能性相比,正确 解决方案有点糟糕:

public void doStuff(EnumSet human) {
if (human.contains(Human.MAN) && human.contains(Human.DEAD)) {
// do something
} else {
// more common cases
}
}

特别是,自从在 Strings 上引入了 switch 以来,我相信 上的 switch 至少有两种可能的实现方式枚举集:

  1. case (Human.MAN | Human.DEAD) 表达式中,简单地使用编译时类型检查和 ordinal() 而不是枚举本身。
  2. 使用the same trick as for Strings .
    • 在编译时,计算枚举值的 hashCode() name(可能还有一些额外的东西 - 值的数量在枚举中,ordinal() 等 - 从编译时开始,一切都是静态和常量)。是的,这意味着要更改 EnumSet 类或 Enum 类的 hashCode()
    • 使用而不是枚举本身

现在,是否有任何我没有考虑到的严重障碍(我可以想出一些,所有都可以很容易地克服)会导致这不可能轻易实现?或者我是对的,这确实是可能的,但对于 Oracle 来说还不够理想,因为它不经常使用?


另外,让我声明这是一个纯粹的学术问题可能没有好的答案(不知道,否则我不会问)。如果它被证明是无法回答的,我可能会把它变成社区 wiki。但是,我在任何地方都找不到答案(甚至没有人讨论过),所以就在这里。

最佳答案

在 Java 和面向对象的世界中,你会在对象上拥有带有 setter 和 getter 的类,你会使用它们

public void doStuff(Human human) {
if(human.isDead()) {
if(human.isMale()) {
// something
} else if (human.isFemale()) {
// something else
} else {
// neither
}
}
}

注意:switch 不是一个好主意,因为它只接受精确匹配。例如案例 MAN | DEAD: 将不匹配 MAN |饿了 | DEAD 除非你只想匹配那些死前不饿的人。 ;)


我会看到你的“绝对足够”的基准测试,并向你提出另一个有缺陷的基准测试,它“显示”它只需要一个时钟周期的一小部分(因为你想知道,这很难相信)

public static void main(String... args) {
Human human = new Human();
human.setMale(true);
human.setDead(true);
for(int i=0;i<5;i++) {
long start = System.nanoTime();
int runs = 100000000;
for(int j=0;j< runs;j++)
doStuff(human);
long time = System.nanoTime() - start;
System.out.printf("The average time to doStuff was %.3f ns%n", (double) time / runs);
}
}

public static void doStuff(Human human) {
if (human.isDead()) {
if (human.isMale()) {
// something
} else if (human.isFemale()) {
// something else
} else {
// neither
}
}
}

static class Human {
private boolean dead;
private boolean male;
private boolean female;

public boolean isDead() {
return dead;
}

public boolean isMale() {
return male;
}

public boolean isFemale() {
return female;
}

public void setDead(boolean dead) {
this.dead = dead;
}

public void setMale(boolean male) {
this.male = male;
}

public void setFemale(boolean female) {
this.female = female;
}
}

打印

The average time to doStuff was 0.031 ns
The average time to doStuff was 0.026 ns
The average time to doStuff was 0.000 ns
The average time to doStuff was 0.000 ns
The average time to doStuff was 0.000 ns

在完全优化之前,我的机器上有 0.1 个时钟周期。

关于java - 打开 EnumSet,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14073836/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com