【问题标题】:Cannot infer type arguments for Generic Class无法推断通用类的类型参数
【发布时间】:2021-04-06 03:26:35
【问题描述】:

我正在尝试使用后缀表达式创建表达式树。 这需要一个可以容纳树对象的堆栈。 我创建了一个通用的 Stack 类,除了 <TreeTemp> 作为类型参数。

在尝试使用以下语句初始化堆栈时,它给出“无法推断 TreeStack 的类型参数”错误。 private TreeStack<TreeTemp> stack1 = new TreeStack<>(new TreeTemp()); 堆栈类:

public class TreeStack<T> {

    private T [] stackElem;
    private final int MAXSTACKSIZE;
    private int top;
    
    public TreeStack(Class<T> t) {
        top = -1;
        MAXSTACKSIZE = 20;
        final T[] stackElem = (T[]) Array.newInstance(t, MAXSTACKSIZE);
        this.stackElem = stackElem;
        
    }
    
    public void push(T elem) throws Exception{
        if(isFull()) {
            stackElem[++top] = elem;
        }
        else
            throw new Exception("Stack is already Full");
    }
    
    public T pop() throws Exception {
        
        if(isEmpty()) {
            return stackElem[top--];
        }
        else
            
            throw new Exception("Stack is Empty");
    }
    
    public boolean isEmpty() {return top == -1;}
    
    public boolean isFull() {return top==MAXSTACKSIZE-1;}
}

Postfix.class(具有创建树方法的类)

public class PostFix {

    private String expression = new String("A*B+C");
    private char [] expElem = expression.toCharArray();
/*Error on below Statement*/

    private TreeStack<TreeTemp> stack1 = new TreeStack<>(new TreeTemp());
    
    public TreeTemp makeTree() throws Throwable {
        try {
        for(int i=0;i<expElem.length;i++) {
            ExpNode eNode = new ExpNode();
            eNode.setiData(expElem[i]);
            TreeTemp t = new TreeTemp();
            t.setRoot(eNode);
            if(!Character.isLetter(expElem[i])) {
                t.setLeftTree(stack1.pop());
                t.setRightTree(stack1.pop());   
                }
            stack1.push(t);
        }
        return stack1.pop();
        }catch (Exception e) {
            throw new Exception("Stack Error while creating a Tree", e);
        }
    }
    
    public static void main(String[] args) throws Throwable {
        PostFix pf = new PostFix();
        TreeTemp t = pf.makeTree();
        
        
    }

树类(我想添加到堆栈中的类型):

public class TreeTemp {
    
    private ExpNode root;
    private TreeTemp leftTree;
    private TreeTemp rightTree;
    
    /*public TreeTemp(ExpNode expNode) {
        root = expNode;

        }*/

    public TreeTemp getLeftTree() {
        return leftTree;
    }

    public void setLeftTree(TreeTemp leftTree) {
        this.leftTree = leftTree;
    }

    public TreeTemp getRightTree() {
        return rightTree;
    }

    public void setRightTree(TreeTemp rightTree) {
        this.rightTree = rightTree;
    }

    public ExpNode getRoot() {
        return root;
    }
    public void setRoot(ExpNode node) {
        this.root = node;
    }
}

谁能指点一下。

【问题讨论】:

    标签: java generics


    【解决方案1】:

    您的TreeStack 只有一个构造函数。这里是:

    public TreeStack(Class<T> t) {
    

    因此,要调用它,您需要传递表示与 T 类型关联的类的类对象。因此,class 本身,而不是“T 的某个特定实例”。当您在错误行上调用它时:

    private TreeStack<TreeTemp> stack1 = new TreeStack<>(new TreeTemp());
    

    您正在传递一个 TreeTemp 实例。不是“TreeTemp,类”的概念。试试new TreeStack&lt;&gt;(TreeTemp.class);

    请注意,作为一般规则,传递Class&lt;T&gt; 是代码异味;您正在尝试使泛型成为它不是的东西(您正在尝试运行时具体化)。这在客观上很糟糕:例如,这意味着您不能创建TreeStack&lt;List&lt;String&gt;&gt;,因为您被限制在泛型和j.l.Class 实例都可以代表事物的重叠范围内,这很简单,非泛型的非原始类。

    final T[] stackElem = (T[]) Array.newInstance(t, MAXSTACKSIZE);

    看起来您想要该类的唯一原因是确保您的数组类型正确。

    这不是必须的。只需创建一个新的Object[] 数组,并在需要返回 T 时转换为 T。现在您的 TreeStack 构造函数根本不需要任何参数。

    查看java.util.ArrayList的来源,符合这个评价;它由 Object 数组支持,而不是 T[]。

    【讨论】:

    • new TreeStack(TreeTemp.class) 完美运行。关于使用 Object [] 代替,我更喜欢使用 T [] 以不失去类型安全性,如线程 *.com/questions/529085/… 中所述
    • 您并没有通过使用 Object.您 正在 使得不可能制作例如 TreeStack一个AtomicReference&lt;String&gt;。我会假设像 ArrayList 这样重要的东西的作者有一个观点,当他们决定使用 Object[] 而不是 T[] 时。
    【解决方案2】:

    TreeStack 构造函数接受Class&lt;T&gt;,而不是T,所以你应该这样做:

    new TreeStack<>(TreeTemp.class);
    

    由于这是一个创建表达式树的练习,因此您实际上不需要从头开始实现堆栈。您应该通过 Java Collections API 中的Deque 接口使用ArrayDeque 类。

    private Deque<TreeTemp> stack1 = new ArrayDeque<>();
    

    Deque 拥有您的 TreeStack 拥有的所有方法,还有更多。

    【讨论】:

      最近更新 更多