3

首先,我会说我是 Java(/编程)新手,这是我在网站上的第一个问题。

刚刚学习了如何使用递归节点在 Java 中创建有序列表。一切都很简单,直到我遇到这个练习,要求我编写一个方法,将每个节点中包含的任何值加倍。这是我尝试编写的代码:

public class ListaInteri<E extends Integer>
{
    private NodoLista inizio;

    // Private inner class each instance of these has a raw type variable and a
    // ref
    // to next node in the list
    private class NodoLista
    {
        E dato;
        NodoLista pros;
    }

    // method that adds whatever is meant by x to the begging of the list

    public void aggiungi(E x)
    {
        NodoLista nodo = new NodoLista();
        nodo.dato = x;
        if (inizio != null)
            nodo.pros = inizio;
        inizio = nodo;
    }

    // a method that switches last and first elements in the list
    public void scambia()
    {
        E datoFine;

        if (inizio != null && inizio.pros != null) {
            E datoInizio = inizio.dato;
            NodoLista nl = inizio;

            while (nl.pros != null)
                nl = nl.pros;

            datoFine = nl.dato;
            inizio.dato = datoFine;
            nl.dato = datoInizio;
        }
    }

    // and here is the problem
    // this method is supposed to double the value of the raw type variable dato
    // of each node
    public void raddoppia()
    {

        if (inizio != null) {
            NodoLista temp = inizio;
            while (temp != null) {
                temp.dato *= 2;
            }
        }
    }

    // Overriding toString from object (ignore this)
    public String toString(String separatore)
    {
        String stringa = "";
        if (inizio != null) {
            stringa += inizio.dato.toString();
            for (NodoLista nl = inizio.pros; nl != null; nl = nl.pros) {
                stringa += separatore + nl.dato.toString();
            }
        }
        return stringa;
    }

    public String toString()
    {
        return this.toString(" ");
    }

}

这是编译器给我的错误。

    ListaInteri.java:39: inconvertible types
found   : int
required: E
  temp.dato*=2;         
             ^
1 error

现在请记住,无论如何,任何形式的帮助都将不胜感激,这是我想要回答的问题。

  1. 为什么会这样?在编译期间是否存在原始类型的类型擦除这样的事情,其中​​所有与参数或参数类型有关的信息都被忽略了?
  2. 我该如何解决?第二种方法(第一个和最后一个切换的那个)表明编译器实际上可以更改节点中的字段,只要它通过另一种原始类型传递,而如果我们尝试将它乘以 2,例如它不再可以因为编译器现在知道我们在谈论一个 int/Integer,所以返回这个错误。提前感谢您的任何答案。

编辑; 抱歉,必须让它可读现在应该没问题了。EDIT2:几乎可读啊!

4

5 回答 5

6

Integer是最终的,不能延长。因此,您对泛型的使用毫无意义(尽管在语法上是有效的),您不妨只使用int- 问题就会消失。

于 2010-02-19T23:16:46.397 回答
3

类型擦除不是这里的问题(泛型类型被擦除,因此它们在运行时不可用,但在编译时,类型必须是可转换的)。

我可能会解决这个问题,根本不使用类型参数。Integer是最终类,因此没有必要让它使用更通用的类型,例如E extends Integer.

于 2010-02-19T23:16:15.933 回答
1

一个澄清,只是为了确保你理解一些东西:你问,

在编译期间是否存在原始类型的类型擦除这样的事情,其中​​所有与参数或参数类型有关的信息都被忽略了?

人们经常谈论 Java 中的“类型擦除”,部分原因是类型擦除是 Java 和 C++ 之间许多有趣的区别之一,部分原因是当您将更新版本(Java 5 及更高版本)与较旧的 Java 代码。

然而,类型擦除并不意味着“所有与参数或参数类型有关的信息都被忽略”——它意味着比这更窄的东西。此外,正如您所说,类型擦除是“在编译时”应用的,但它是编译器检查程序中的所有类型和声明以查看是否存在任何类型错误之后应用的。

第一个问题:什么是类型擦除?类型擦除只发生在泛型类型上。 Integer不是泛型类型,而是ArrayList<T>泛型类型,因为您可以声明ArrayList<Integer>or ArrayList<String>。在编译器检查完程序中的类型以使它们都匹配后,它会丢弃有关泛型类型的所有信息,因此 anArrayList<Integer>和 anArrayList<String>都变成了ArrayList. 这就是您可以用if (foo instanceof String)Java 编写,但不能编写的原因if (foo instanceof ArrayList<String>):当if在运行时评估该语句时,无法区分 anArrayList<String>与 anArrayList<Integer>或任何其他类型的ArrayList.

第二个问题:什么时候应用类型擦除?在检查代码是否存在编译错误后,当编译器生成编译代码(“字节码”)时应用类型擦除。这意味着即使 Java 使用类型擦除,以下代码在 Java 中也会出现编译错误:

ArrayList<String> foo = new ArrayList<String>();
foo.add(new Integer(3)); // Error - Compiler knows that String is expected

我知道我没有回答您的问题,但我想确保您首先了解类型擦除。:-)

回到你原来的问题:为什么类需要用 声明<E extends Integer>?这是家庭作业特别需要的吗?我只是将您的代码复制并粘贴到 Eclipse 中,删除了<E extends Integer>顶部的,并将所有E声明替换为Integer,它编译得很好。

(顺便说一句,raddoppia你在这里写的仍然有问题,即使你摆脱<E extends Integer>它并让它编译 - 你找到它了吗?尝试raddoppia使用包含多个元素的列表进行测试,然后你应该看到问题...)

于 2010-02-22T00:11:12.167 回答
0

我认为应该是

<E extends Number>

那么你可以说

tmp.dato = tmp.dato.intValue() * 2;

我认为这会编译,但是如果有人将您的数据结构用于非整数,则此方法不会产生正确的答案。

于 2010-02-19T23:51:16.483 回答
0

尝试 :

  temp.dato= new Integer(((Integer)temp.dato).intValue*2);
于 2010-02-19T23:19:15.797 回答