简体   繁体   English

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

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

I'm working on some set of abstractions representing an SQL result set and have written this methods: 我正在研究代表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
    }
}

I got compile-error at //1 , although it's perfectly clear by the signature of put and get methods that there is no way to put inaproppriate value. 我在//1遇到了编译错误,尽管通过putget方法的签名可以很清楚地看出,没有办法放置不适当的值。 How can I fix the error in a type-safe way? 如何以类型安全的方式修复错误? The error message: 错误信息:

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

I am not sure exactly what your trying to do but to me if you want to make everything type safe then you need to pass in the type of column. 我不确定您要做什么,但是如果您想确保所有内容的类型都是安全的,那么请交给我,然后您需要传入列的类型。 To make sure they are all using the same type. 确保它们都使用相同的类型。

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;
    }
}

you have to redesign your code because in that form it cannot compile. 您必须重新设计代码,因为它不能以这种形式编译。 Your code is not type safe for the compiler. 您的代码对于编译器而言不是类型安全的。 You can write it in the following form 您可以按以下格式编写

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
    }

}

this code works and each column is responsible for the value extraction 该代码有效,每一列负责值的提取

This does not compile because the compiler does not understand that the use of the wild-card type for the get call is the same type as the use of a wild-card type in for the set call, even if the methods are used with the same object. 这不会编译,因为编译器无法理解get调用使用通配符类型与set调用使用通配符类型相同,即使这些方法与同一对象。

You can solve it by introducing a util method with a type parameter. 您可以通过引入带有类型参数的util方法来解决此问题。 In that way, the wild-card type is used only once, and inside the method the type parameters will have a concrete type, which the compiler can understand that it is the same one that is used in multiple places. 这样,通配符类型仅使用一次,并且在方法内部,类型参数将具有具体的类型,编译器可以理解为在多个地方使用的相同类型。

The concrete type which is assigned to a wild-card type in each separate place where it is used is called the capture of the wild-card type, and it is given a name like capture#3-of ? 在使用它的每个单独位置中分配给通配符类型的具体类型称为通配符类型的捕获 ,并为其指定一个名称,如capture#3-of ? by the compiler. 由编译器。

The following compiles: 编译如下:

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);  
    }
}

The same technique is used in an example of capturing conversion in the JLS . 在JLS中捕获转换示例中使用了相同的技术。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM