Java 编译器不同意泛型方法调用的安全性

Java compiler is not agreed with safety of a generic method call

我正在研究表示 SQL 结果集的一些抽象集,并编写了以下方法:

public interface Column<T>{
    //some methods
}

public class SqlRowExtractor{

    public void doExtraction(){
        Collection<Column<?>> cols = getColumns(); //Returns the collection of Column<T>.
                                                   //A particular result set may contain, 
                                                   //for instance 2 Column<Date>, 
                                                   //1 Column<Integer> and so fotrh

        for(Column<?> c : cols){
            put(c, get(c)); //1  <-------------------- HERE
                            //Compile-error  
        }
        //other staff
    }

    public <T> void put(Column<T> c, T o){
       //put the extracted value in another place
    }

    public <T> T get(Column<T> c) throws SQLException{
        //extract the value of the row for the Column<T> c
    }
}

我在 //1 处遇到编译错误,尽管 putget 方法的签名非常清楚,无法放置不适当的值。如何以类型安全的方式修复错误?错误信息:

The method put(Column<T>, T) is not applicable for the arguments 
(Column<capture#3-of ?>, capture#4-of ?)

我不确定你到底想做什么,但对我来说,如果你想让所有类型都安全,那么你需要传入列的类型。确保他们都使用相同的类型。

interface Column<T>{
    //some methods
}

class SqlRowExtractor{

    public <T> Collection<Column<T>> getColumns(Class<T> clss) {
        return null;
    }
    public <T> void doExtraction(Class<T> clss) throws SQLException{
        // Type T needs to be specified before this so compiler 
        // can check it.
        Collection<Column<T>> cols = getColumns(clss); 
        for(Column<T> c : cols){
            put(c, get(c)); 
        }
        //other staff
    }

    public <T> void put(Column<T> c, T o){
       //put the extracted value in another place
    }

    public <T> T get(Column<T> c) throws SQLException{
        //extract the value of the row for the Column<T> c
        return null;
    }
}

您必须重新设计您的代码,因为在那种形式下它无法编译。您的代码对于编译器来说不是类型安全的。你可以写成下面的形式 <pre></p> <pre><code>interface Column<T>{ /** * extracts valu from the column * * @return the value */ T value() throws SQLException; } public class test{ public void doExtraction() throws SQLException { Collection<Column<?>> cols = getColumns(); //Returns the collection of Column<T>. for(Column c : cols){ put(c, c.value()); } } public <T> void put(Column<T> c, T o){ //put the extracted value in another place } }

此代码有效,每列负责提取值

这不会编译,因为编译器不理解 get 调用中使用的通配符类型与 [=] 中使用的通配符类型是同一类型12=] 调用,即使这些方法用于同一对象。

引入一个带类型参数的util方法即可解决。这样,通配符类型只使用一次,方法内部的类型参数会有一个具体的类型,编译器可以理解它是同一个,在多个地方使用。

在每个单独的使用地方分配给通配符类型的具体类型称为通配符类型的捕获,并给出编译器命名为 capture#3-of ?

编译如下:

private <T> void getPut(Column<T> c) throws SQLException {
    // Compiles because the type's capture, which in non-wildcard, has been bound to T
    put(c, get(c));
}

public void doExtraction() throws SQLException {
    Collection<Column<?>> cols = getColumns(); 
    for(Column<?> c : cols) {
        // Compiles because wild-card type of c is only used once
        getPut(c);  
    }
}

example of capturing conversion in the JLS.

中使用了相同的技术