对不起标题: - /
我为计算器编写了一个解析器。它有效,但我不喜欢我的令牌层次结构。解析器应该不知道具体的数字类型,例如它应该可以配置为Double,BigDecimal等。所以我有一个通用的令牌接口
public interface Token<T> { }
public class NumToken<T> {
private final value T;
...
}
public class OperatorToken<T> {
...
}
现在我的问题是如何处理无论数字类型如何都相同的“结构”标记,例如括号和分隔符。泛型参数不仅在这种情况下无用,它阻止我使用该类型的枚举。但是,枚举非常有用,例如它可以在switch语句中使用。
现在我已经“解决”了这个问题:
public enum CharToken implements Token<Object> {
OPEN('('),
CLOSE(')'),
SEPARATOR(','),
EOL(';');
private final char ch;
private CharToken(char ch) {
this.ch = ch;
}
}
这很有效,但是迫使我在List<Token<? super T>>
之类的解析器中编写所有内容,并假设在我转换时所有其他类型实际上都是Token<T>
。我明显地使用类型系统来对付谷物:从类型理论的角度来看,我正在撞墙,因为Java在Scala中没有像“Nothing”这样的“底部”类型(这将是一个完美的契合)。有更好的解决方案吗?
[澄清]
T是我的解析器应该处理的预期数字类型,而不是令牌的“内容”。例如。对于OperatorToken<T>
,我有一个方法calc(T op1, T op1)
。我希望能够通过T对整个解析器进行参数化,因此它使用的所有令牌都需要相同的T(如果你不像我那样欺骗super
),那么{{1}不会很有用。
答案 0 :(得分:1)
JDK中使用的解决方案(例如java.util.Collections.emptyList()
)正在利用擦除 - 类型参数并不存在,您可能还记得 - 并为方法输入参数推断:
@SuppressWarnings("unchecked")
public enum CharToken implements Token { // Note: No type parameter specified!
OPEN('('),
CLOSE(')'),
SEPARATOR(','),
EOL(';');
public static <T> Token<T> open(){ return OPEN; }
public static <T> Token<T> close(){ return CLOSE; }
public static <T> Token<T> separator(){ return SEPARATOR; }
public static <T> Token<T> eol(){ return EOL; }
private final char ch;
private CharToken(char ch) {
this.ch = ch;
}
}
// Usage:
Token<BigDecimal> bdOpen = CharToken.open();
Token<Integer> intOpen = CharToken.open();
看起来不是很漂亮,但至少它很容易使用。 (为清洁起见,您可能希望将枚举封装在仅暴露泛型方法的类中。)
答案 1 :(得分:0)
Java中有Void
类型,设计用于类似用途。但是,正如Bozho所暗示的那样,IMO的类型参数应该是Character
。