C枚举的Java代表

发布于 2025-02-04 08:41:42 字数 820 浏览 1 评论 0原文

编译器编写的C。

typedef enum {
  SOME_OP,
  ANOTHER_OP,
  //Etc.
} Operations;

uint8_t* opsAndArgs;

Java a intecode

{SOME_OP, 42, ANOTHER_OP, 99, 03, DIFFERENT_OP, RANDOM_OP, 14, etc.}

正在移植到 C程序中的功能通过OPSANDARGS和打开操作员进行迭代,适当地消费参数:

int i = 0;

while (i < opsAndArgs.length) {
  switch (opsAndArgs[i] {
    case SOME_OP:
      handleSomeOp(opsAndArgs[i+1]);
      i = i + 2; break;
    case ANOTHER_OP:
      handleAnotherOp(opsAndArgs[i+1], opsAndArgs[i+2]);
      i = i + 3; break;
    case DIFFERENT_OP:
      handleDifferentOp();
      i = i + 1; break;
    Etc.
  }
}

有没有办法在Java中做同样的事情?即,创建一个枚举,我可以将其混合成具有数字值的数组,并且仍然可以在将剩余值视为参数的同时打开枚举定义的运算符?

似乎原始程序正在利用C枚举的某些功能,使它们与UINT8_T值可混合。

I am porting to Java a bytecode compiler written in C. In the C implementation, the set of operations is represented in an enum:

typedef enum {
  SOME_OP,
  ANOTHER_OP,
  //Etc.
} Operations;

Operations are then mixed with numeric arguments in an array defined as:

uint8_t* opsAndArgs;

For example, opsAndArgs might hold:

{SOME_OP, 42, ANOTHER_OP, 99, 03, DIFFERENT_OP, RANDOM_OP, 14, etc.}

Finally, a function in the C program iterates through opsAndArgs and switches on operators, consuming arguments as appropriate:

int i = 0;

while (i < opsAndArgs.length) {
  switch (opsAndArgs[i] {
    case SOME_OP:
      handleSomeOp(opsAndArgs[i+1]);
      i = i + 2; break;
    case ANOTHER_OP:
      handleAnotherOp(opsAndArgs[i+1], opsAndArgs[i+2]);
      i = i + 3; break;
    case DIFFERENT_OP:
      handleDifferentOp();
      i = i + 1; break;
    Etc.
  }
}

Is there a way I can do the same thing in Java? I.e., create an Enum that I can mix into an array with numeric values, and still have the ability to switch on Enum-defined operators while treating the remaining values as arguments?

It seems like the original program is taking advantage of some feature of C enums such that they are mix-able with uint8_t values.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不忘初心 2025-02-11 08:41:42

与C中不同,Java中的枚举是一个对象。这意味着将它们与数字混合的唯一方法是与list&lt; object&gt;object []

每个枚举确实都有一个ordinal()值,即int。这些不是编译时常数,因此您不能在开关语句中使用它们*。

我认为您有一些选项:

  1. 去获取list&lt; object&gt;/object []解决方案。如果仅执行打开操作,则可以使用instance Ofswitch> switch
if (opsAndArgs[i] instanceof Operation operation) { // **
    switch (operation) {
        case SOME_OP: ...
    }
}
  1. 忘记枚举并进行常数类别的组合来完成此操作:
final class Operation {
    public static final int SOME_OP = 1;
    // etc

    private Operation() {}
}
  1. 为每个枚举定义INT常数持续的。每个枚举常数必须返回其中之一,并且您需要在枚举类上进行查找(静态方法),以根据int常数找到枚举常数。不要相信ordinal()作为常数,因为如果您更改枚举的顺序,序数值也会更改。

我认为您要问自己的主要问题是:您是否需要枚举?还是常数班足够好?因为这绝对是解决方案的更容易。

* 然而?我没有完全最新的速度,以切换模式匹配的最新更改...

**在Java 16中最终确定语法。在较旧版本中,使用opsandargs [i] Instanceof操作在组合中在if中具有新变量:操作操作=(操作)opsandargs [i];

Unlike in C, an enum in Java is an object. That means that the only way to mix the them with numbers is with a List<Object> or Object[].

Every enum does have an ordinal() value that is an int. These are not compile-time constants though, so you can't use them in switch statements*.

I think that you have some options:

  1. Go for the List<Object> / Object[] solution. If you only perform switching on the operations, you can do this with a combination of instanceof and switch
if (opsAndArgs[i] instanceof Operation operation) { // **
    switch (operation) {
        case SOME_OP: ...
    }
}
  1. Forget the enum and go for a constants class:
final class Operation {
    public static final int SOME_OP = 1;
    // etc

    private Operation() {}
}
  1. Define int constants for each enum constant. Each enum constant must return one of these, and you'll need to have a lookup (static method) on the enum class to find the enum constant based on the int constant. Don't trust on ordinal() as constants because if you change the order of enum constants the ordinal values change as well.

I think the main question you have to ask yourself is: do you need an enum? Or is the constants class good enough? Because that's definitely the easier of the solutions.

* Yet? I'm not fully up-to-speed with the latest changes to switch pattern matching...

** That's syntax finalized in Java 16. In older versions, use opsAndArgs[i] instanceof Operation in combination with a new variable inside the if: Operation operation = (Operation) opsAndArgs[i];

我的奇迹 2025-02-11 08:41:42

从我的角度来看:

  • 保持C字节代码解释器的结构,否则生活变得太复杂了!

  • opsandargs必须是字节数组。我们在这里谈论Java字节代码。某些值必须解释为字节,有些值为短裤,并且程序计数器需要以字节大小的步骤前进。

  • 使用静态最终字节 for opcodes。

From my point of view:

  • Keep the structure of the C byte code interpreter, else life gets too complicated!

  • opsAndArgs has to be a byte array. We are talking about Java byte code here. Some values have to be interpreted as bytes, some as shorts, ... and the program counter needs to advance in byte-sized steps.

  • Use static final byte for opcodes.

抽个烟儿 2025-02-11 08:41:42

这是Java的一个工作解决方案。显然,有些事情不清楚(例如,我不知道您的Handlexxxxop方法做了什么),因此进行了自由。否则,这在Java 17中可以正常工作。

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

public class SOQ_20220605_2
{

   private sealed interface Value
   {
   
      public static List<Value> asList(Object... uncheckedValues)
      {
      
         Objects.requireNonNull(uncheckedValues);
         
         final List<Value> values = new ArrayList<>();
         
         for (var each : uncheckedValues)
         {
         
            values.add(
               switch(each)
               {
               
                  case null         -> throw new NullPointerException("No nulls allowed");
                  case Integer i    -> new Argument(i);
                  case String s     -> Operation.valueOf(s.toUpperCase());
                  case Argument a   -> a;
                  case Operation o  -> o;
                  default           -> throw new IllegalArgumentException("Unexpected type! each = " + each);
               
               }
            );
         
         }
         
         return values;
      
      }
   
   }
   
   private enum Operation implements Value
   {
      
      SOME_OP,
      ANOTHER_OP,
      DIFFERENT_OP,
      RANDOM_OP,
      ;
      
   }
   
   private record Argument(int num) implements Value {}

   public static void main(String[] args)
   {
   
      final List<Value> opsAndArgs =
         Value.asList
         (
            "SOME_OP",
            42,
            "ANOTHER_OP",
            99,
            3,
            "DIFFERENT_OP",
            "RANDOM_OP",
            14
         );

         final int result = calculateResult(opsAndArgs);
         
         System.out.println(result);

   }
   
   private static int calculateResult(List<Value> opsAndArgs)
   {
   
         int i = 0;

         while (i < opsAndArgs.size())
         {
         
            if (opsAndArgs.get(i) instanceof Operation operation)
            {
            
               i = 
                  switch (operation)
                  {
               
                     case SOME_OP -> 
                     {
                     
                        handleSomeOp(
                              opsAndArgs.get(i + 1)
                           );
      
                        yield i + 2;
                     
                     }
                     
                     case ANOTHER_OP ->
                     {
                     
                        handleAnotherOp(
                              opsAndArgs.get(i + 1),
                              opsAndArgs.get(i + 2)
                           );
      
                        yield i + 3;
                     
                     }
                  
                     case DIFFERENT_OP ->
                     {
                     
                        handleDifferentOp();
      
                        yield i + 1;
                     
                     }
                     
                     case RANDOM_OP ->
                     {
                        
                        yield i + 4;
                        //throw new UnsupportedOperationException("This has not been implemented yet.");
                     
                     }
                  
                  };
               
            }
         
         }
         
         return i;
   
   }
   
   private static void handleSomeOp(Value value)
   {
   
      //do something
   
   }

   private static void handleAnotherOp(Value value1, Value value2)
   {
   
      //do something
   
   }

   private static void handleDifferentOp()
   {
   
      //do something
   
   }

}

我们创建一个称为value的通用接口,以便我们可以为我们的list&lt; value&gt;具有可接受值的域。然后,我们将其密封,因此只有我们允许的类型才能被视为value。这两种类型是参数操作。我们还拥有一个方法aslist,可以处理您在问题中描述的数组。现在,您可以将操作和参数作为参数传递。如果您想传递some_op,则可以将其传递为operation.some_op “ some_op” 。该方法当前可以处理两种方式,但是我选择以String的方式传递每个操作。参数也一样。如果您想传递42,则可以将其作为新参数(42)将其传递给,或者可以将其作为int 通过42。该方法当前可以处理两种方式,但是我选择以int的方式传递每个参数。

操作enum,它保留了您定义的所有操作。如果要添加更多操作,只需将它们添加到此枚举中,进行编译,然后更新任何现在失败编译的交换语句。

参数记录保存参数。拥有明确的类型有助于我们在在一起时将参数与操作分开。

主要方法基本上以相同的方式收集值,然后使用我们的list&lt; value&gt;值作为参数。

calculateresult基本上是开关语句,而您在原始问题中有循环。这是大多数自由的地方。而且您的开关案例没有指定参数遇到的情况,因此我构建了我的解决方案,以默默地忽略switch语句中的参数。

Here's a working solution in Java. Obviously, there are some things that were unclear (for example, I don't know what your handleXXXXOp methods do), so liberties were taken. Otherwise, this works just fine in Java 17.

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

public class SOQ_20220605_2
{

   private sealed interface Value
   {
   
      public static List<Value> asList(Object... uncheckedValues)
      {
      
         Objects.requireNonNull(uncheckedValues);
         
         final List<Value> values = new ArrayList<>();
         
         for (var each : uncheckedValues)
         {
         
            values.add(
               switch(each)
               {
               
                  case null         -> throw new NullPointerException("No nulls allowed");
                  case Integer i    -> new Argument(i);
                  case String s     -> Operation.valueOf(s.toUpperCase());
                  case Argument a   -> a;
                  case Operation o  -> o;
                  default           -> throw new IllegalArgumentException("Unexpected type! each = " + each);
               
               }
            );
         
         }
         
         return values;
      
      }
   
   }
   
   private enum Operation implements Value
   {
      
      SOME_OP,
      ANOTHER_OP,
      DIFFERENT_OP,
      RANDOM_OP,
      ;
      
   }
   
   private record Argument(int num) implements Value {}

   public static void main(String[] args)
   {
   
      final List<Value> opsAndArgs =
         Value.asList
         (
            "SOME_OP",
            42,
            "ANOTHER_OP",
            99,
            3,
            "DIFFERENT_OP",
            "RANDOM_OP",
            14
         );

         final int result = calculateResult(opsAndArgs);
         
         System.out.println(result);

   }
   
   private static int calculateResult(List<Value> opsAndArgs)
   {
   
         int i = 0;

         while (i < opsAndArgs.size())
         {
         
            if (opsAndArgs.get(i) instanceof Operation operation)
            {
            
               i = 
                  switch (operation)
                  {
               
                     case SOME_OP -> 
                     {
                     
                        handleSomeOp(
                              opsAndArgs.get(i + 1)
                           );
      
                        yield i + 2;
                     
                     }
                     
                     case ANOTHER_OP ->
                     {
                     
                        handleAnotherOp(
                              opsAndArgs.get(i + 1),
                              opsAndArgs.get(i + 2)
                           );
      
                        yield i + 3;
                     
                     }
                  
                     case DIFFERENT_OP ->
                     {
                     
                        handleDifferentOp();
      
                        yield i + 1;
                     
                     }
                     
                     case RANDOM_OP ->
                     {
                        
                        yield i + 4;
                        //throw new UnsupportedOperationException("This has not been implemented yet.");
                     
                     }
                  
                  };
               
            }
         
         }
         
         return i;
   
   }
   
   private static void handleSomeOp(Value value)
   {
   
      //do something
   
   }

   private static void handleAnotherOp(Value value1, Value value2)
   {
   
      //do something
   
   }

   private static void handleDifferentOp()
   {
   
      //do something
   
   }

}

We create a common interface called Value, so that we can have a domain of acceptable values for our List<Value>. Then, we make it sealed, so that only the types we allow can be considered a Value. Those 2 types are Argument and Operation. We also have a method asList that handles taking in the array that you described in your question. Now, you can pass in your operations and arguments as parameters. If you wanted to pass in SOME_OP, you can either pass it in as Operation.SOME_OP or as a String via "SOME_OP". The method can handle both ways currently, but I am choosing to pass in each operation as a String. Same for the arguments. If you wanted to pass in 42, you could either pass it in as new Argument(42), or you could pass it in naked as an int via 42. The method can handle both ways currently, but I am choosing to pass in each argument as an int.

Operation is an enum that holds all of the operations you defined. If you want to add more operations, simply add them to this enum, compile, then update any of the switch statements that now fail compilation.

Argument is a record that holds arguments. Having it be an explicit type helps us separate the arguments from the operations when they are together.

The main method gathers up the values in basically the same way you did, then calls the method calculateResult, with our List<Value> values as the parameter.

calculateResult is basically the switch statement and while loop that you had in your original question. This is where most of the liberties were taken. And your switch case didn't specify what happens when it comes across an argument, so I built my solution to silently ignore arguments in the switch statement.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文