我有一个二进制文件,它使用4个字符集来形成具有"含义"的整数。例如,4个字节'0005'
,等于整数形式的808464437。
我宁愿在我的Java代码中将它们表示为'0005'
而不是808464437.我也不想设置final int V0005 = 808464437
之类的常量。
在C ++中,我可以执行以下操作:
fileStream->read((byte*) &version, 4); //Get the next bytes and stuff them into the uint32 version
switch (version) {
case '0005':
//do something
case '0006':
//do something
case '0007':
//do something
}
在Java中,我的问题是没有读取4个字节并将它们放入某种数据类型。我的问题是将一些数据类型与const char数组'0005'
进行比较。
如何将int或其他形式与Java中的'0005'
等const字符数组进行比较? 我需要尽可能高效地完成这项工作!
答案 0 :(得分:4)
感谢您解答答案。
以下是如何将4个字节转换为int,然后可以将其与所讨论的int进行比较:
int v0005 = ByteBuffer.wrap("0005".getBytes()).asIntBuffer().get();
遗憾的是,这是我能看到的唯一方式......可能没有您想要的那么高效,但也许这就是您所需要的。
我建议在其中一个类中将其中一些设置为“常量”,如下所示:
public static final int V0005 = ByteBuffer.wrap("0005".getBytes()).asIntBuffer().get();
public static final int V0006 = ByteBuffer.wrap("0006".getBytes()).asIntBuffer().get();
public static final int V0007 = ByteBuffer.wrap("0007".getBytes()).asIntBuffer().get();
public static final int V0008 = ByteBuffer.wrap("0008".getBytes()).asIntBuffer().get();
然后打开V0005等,因为打开基本类型(int)是有效的。
答案 1 :(得分:3)
java中的char数组只不过是java中的String
。您可以在Java7中使用switch-cases中的字符串,但我不知道比较的效率。
因为只有你char数组的最后一个元素似乎有意义,你可以用它做一个switch case。像
这样的东西private static final int VERSION_INDEX = 3;
...
char[] version = // get it somehow
switch (version[VERSION_INDEX]) {
case '5':
break;
// etc
}
...
修改强> 更多面向对象的版本。
public interface Command {
void execute();
}
public class Version {
private final Integer versionRepresentation;
private Version (Integer versionRep) {
this.versionRepresentation = versionRep;
}
public static Version get(char[] version) {
return new Version(Integer.valueOf(new String(version, "US-ASCII")));
}
@Override
public int hashCode() {
return this.versionRepresentation.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Version) {
Version that = (Version) obj;
return that.versionRepresentation.equals(this.versionRepresentation);
}
return false;
}
}
public class VersionOrientedCommandSet {
private final Command EMPTY_COMMAND = new Command() { public void execute() {}};
private final Map<Version, Command> versionOrientedCommands;
private class VersionOrientedCommandSet() {
this.versionOrientedCommands = new HashMap<Version, Command>();
}
public void add(Version version, Command command) {
this.versionOrientedCommands.put(version, command);
}
public void execute(Version version) throw CommandNotFoundException {
Command command = this.versionOrientedCommands.get(version);
if (command != null) {
command.execute();
} else {
throw new CommandNotFoundException("No command registered for version " + version);
}
}
}
// register you commands to VersionOrientedCommandSet
char[] versionChar = // got it from somewhere
Version version = Version.get(versionChar);
versionOrientedCommandSet.execute(version);
很多代码hehe你会有一点预热成本,但如果你的程序执行多次,你将获得地图的效率:P
答案 2 :(得分:2)
从其他一些答案中得到一些答案(@marvo和@vikingsteve),我出来了:
public enum Version {
V0005 {
@Override
public void doStuff() {
// do something
}
},
V0006 {
@Override
public void doStuff() {
// do something else
}
};
private final int value;
private static final Map<Integer, Version> versions = new HashMap<>();
private Version() {
final byte[] bytes = name().substring(1).getBytes(); //remove the initial 'V'
this.value = ByteBuffer.wrap(bytes).asIntBuffer().get();
}
static {
for (Version v : values()) {
versions.put(v.value, v);
}
}
public abstract void doStuff();
public Version valueOf(int i){
return versions.get(i);
}
}
这提供了一种良好的面向对象方法,因为动作是用数据表示封装的。每个常量决定在调用doStuff时要做什么,避免切换客户端代码。用法是:
int code = readFromSomewhere();
Version.valueOf(i).doStuff();
valueOf
方法在加载类时填充的地图中找到Version
。我不知道这是否有效,因为int
被设置为Integer
但只会在您分析时找到,其他一切是纯粹的猜测。
另请注意,在构造函数中为您计算整数值,因此您只需要使用正确的名称定义enums
,它将自动完成。
答案 3 :(得分:1)
你在找value1.intValue() == value2.intValue()
之类的东西吗?或者你可以输入演员。
char myChar = 'A';
int myInt = (int) myChar;
相同的手杖反过来。
int myInt = 6;
char myChar = (char) myInt;
答案 4 :(得分:1)
唯一的方法是字节[]到字符串转换非常低效。
switch (new String(version, "US-ASCII")) {
case "0005":
break;
...
}
使用(哈希)地图会使其再次变快。
但我认为你不会满意这个解决方案。
答案 5 :(得分:1)
最有效的方法是使用整数 - 比如final int V0005 = 0x30303035(这里看到的几个不同想法的组合)是可管理的。 Java只是没有你想要的那种整数文字。
如果你真的想使用字符串,你需要首先读取字节数组中的字符,然后将其转换为字符串(默认字符集通常可以工作,因为它是ASCII的超集)。但是,效率会降低。
您可以编写一个函数来计算简单数字(如5)中的常量值,以获得更好的可读性,但这可能有点过分。
答案 6 :(得分:1)
鉴于这似乎是数据包中的版本字符串或其他东西,那么值的数量是有限的并且是合理的数量。所以它们可以封装在枚举中。枚举可以封装有效的代码,用于将输入数据中的四个字节转换为代表枚举。 (我执行转换的代码不一定是最有效的。也许,给定少量版本,一个不错的内部数组或内联到枚举的映射都可以。)
class enum Version {
UNKNOWN(0),
V0005(0x30303035), // whatever the int value is
V0006(0x30303036);
private int id;
private Version(int value) {
id = value;
}
public static Version valueOf(int id) {
for (Version version : values()) {
if (version.getId() == id) {
return version;
}
}
return UNKNOWN;
}
public static Version valueOf(String sId) {
return valueOf(computeId(sId));
}
public static int computeId(String sId) {
// efficiently convert from your string to its int value
}
}
然后在我的开关中:
String s = methodThatReadsFourChars(...);
switch (Version.valueOf(s)) {
case V0005 : doV0005Stuff(); break;
case V0006 : doV0006Stuff(); break;
default :
throw new UnknownVersionException();