如何将非泛型类集成到泛型层次结构中? [英] How to integrate non-generic classes in a generic hierarchy?

查看:135
本文介绍了如何将非泛型类集成到泛型层次结构中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对不起,标题为: - / / $ / $>

我为计算器写了一个解析器。它有效,但我不喜欢我的令牌层次结构。解析器应该不知道具体的数字类型,例如它应该可以配置为Double,BigDecimal等。所以我有一个通用的标记接口

  public interface Token< T> {} 

公开课NumToken< T> {
私人终值T;
...
}

公共类OperatorToken< T> {
...
}

现在我的问题是如何处理结构性令牌,不管数字类型如何,都是相同的括号和分隔符。通用参数不仅在这种情况下是无用的,它阻止我使用该类型的枚举。然而,枚举是非常有用的,例如它可以在switch语句中使用。



现在我已经解决了这个问题:

  public enum CharToken实现了Token< Object> {

OPEN('('),
CLOSE(')'),
SEPARATOR(','),
EOL(';');

private final char ch;

private CharToken(char ch){
this.ch = ch;


$ / code $ / pre
$ b $ p

这有效,但是迫使我无处不在解析器的东西,如 List< Token< super T>> ,并假设所有其他类型实际上是 Token< T> 。我在这里明确地使用类型系统来反对谷物:从类型理论的角度来看,我撞到了墙上,因为Java没有Scala中的Nothing这样的底部类型(这将非常合适)。有没有更好的解决方案?



[澄清]



T是我的解析器应该工作的预期数字类型,而不是令牌的内容。例如。对于 OperatorToken< T> 我有一个方法 calc(T op1,T op1)。我希望能够通过T来参数化整个解析器,所以它使用的所有令牌都需要相同的T(好吧,如果你没有用 super> 作弊,因为我),因此 CharToken实现了令牌< Character> 并不是非常有用。

解决方案在JDK中使用的解决方案(例如 java.util.Collections.emptyList())正在利用删除 - 类型参数不真正存在,你可能会记得 - 并为方法键入参数推断:

  @SuppressWarnings(unchecked) 
public enum CharToken实现Token {//注意:没有指定类型参数!

OPEN('('),
CLOSE(')'),
SEPARATOR(','),
EOL(';');

public static< T>令牌LT; T> open(){return OPEN; }
public static< T>令牌LT; T> close(){return CLOSE; }
public static< T>令牌LT; T> separator(){return SEPARATOR; }
public static< T>令牌LT; T> eol(){return EOL; }

private final char ch;

private CharToken(char ch){
this.ch = ch;
}
}

//用法:
令牌< BigDecimal> bdOpen = CharToken.open();
令牌<整数> intOpen = CharToken.open();

不是很漂亮,但至少很容易使用。 (为了清洁起见,你可能希望将枚举封装在仅暴露泛型方法的类中。)


Sorry for the title :-/

I wrote a parser for a calculator. It works, but I don't like my token hierarchy. The parser should be unaware of the concrete number type, e.g. it should be configurable for Double, BigDecimal etc. So I have a generic token interface

public interface Token<T> { }

public class NumToken<T> {
  private final value T;
  ...
} 

public class OperatorToken<T> {
  ... 
} 

Now my question is how to handle "structural" Tokens that are the same regardless of the number type, e.g. parentheses and separators. The generic parameter is not only useless in that case, it prevents me from using an enum for that type. However, an enum would be very useful, e.g. it can be used in switch statements.

Right now I have "solved" the problem that way:

public enum CharToken implements Token<Object> {

    OPEN('('),
    CLOSE(')'),
    SEPARATOR(','),
    EOL(';');

    private final char ch;

    private CharToken(char ch) {
       this.ch = ch;
    }
} 

This works, but forces me to write everywhere int the parser things like List<Token<? super T>>, and to assume that all other types are actually Token<T> when I cast. I'm clearly using the type system against the grain here: From a type-theoretical point of view I'm hitting the wall because Java has no "bottom" type like "Nothing" in Scala (which would be a perfect fit). Is there a better solution?

[Clarification]

T is the expected number type my parser should work on, not the "content" of the Token. E.g. for OperatorToken<T> I have a method calc(T op1, T op1). And I want to be able to parametrize the whole parser by T, so all Tokens used by it need the same T (well, if you don't cheat with super as I did), and hence CharToken implements Token<Character> would be not very useful.

解决方案

A solution used in the JDK (in e.g. java.util.Collections.emptyList()) is exploiting erasure - the type parameters don't really exist, as you might recall - and type parameter inference for methods:

@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();

Not very pretty looking at, but at least it's easy to use. (And for cleanliness' sake, you might want to encapsulate the enum in a class which only exposes the generic methods.)

这篇关于如何将非泛型类集成到泛型层次结构中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆