消除Cast中的中间步骤

时间:2013-05-25 21:07:07

标签: java spring generics casting spring-data

我使用import org.springframework.data.repository.support.Repositories在Quartz Job中获取Spring Data Repository的实例。

Repositories类有一个getRepositoryFor(Class<?> domainClass)方法,它返回相应存储库的实例,但存储库的类型为CrudRepository<Object, Serialiazable>

如果我尝试将返回的CrudRepository向上转换为自定义存储库类型CustomerRepository,Eclipse会通知我无法执行强制转换。

    // Eclipse Error: Cannot cast from CrudRepository<Object,Serializable> 
    // to CustomerRepository
    this.customerRepository =
        (CustomerRepository)super.repositories.getRepositoryFor(Customer.class);

但是,如果我将存储库分配给CrudRepository<Customer, Long> repository类型的字段,那么我可以转换为CustomerRepository

//No Problems here
CrudRepository<Customer, Long> repository = 
    super.repositories.getRepositoryFor(Customer.class);
CustomerRepository repository = (CustomerRepository) repository;
  1. 是否还要避免执行所需的中间步骤 这个演员?

  2. 第一次演员导致问题的原因是什么?

2 个答案:

答案 0 :(得分:2)

问题出在方法定义“getRepositoryFor”中。除非您将其分配给定义了泛型的变量,否则它不会为“T”泛型建立合同。

public <T,S extends Serializable> CrudRepository<T,S> getRepositoryFor(Class<?> domainClass)

我想那个级别的编译器看不到CustomerRepository扩展CrudRepository<Customer, Long>。我想这个例子可以帮助您理解这个问题:

public class TestCast {

    public static class MyMap extends HashMap<String, String> {
    }

    public static <T> Map<T,String> getMap1(Class<?> myClass) {
        return new HashMap<T,String>();
    }

    public static <T> Map<T,String> getMap2(Class<T> myClass) {
        return new HashMap<T,String>();
    }

    public static void main(String[] args) {

        // Works, because it knows T is String as you state it with the variable type Map<STRING,String>
        Map<String,String> map = getMap(String.class); 

        // Compilation error, it doesn't know T is String and cast won't work either
        MyMap myMap = getMap1(String.class); 

        // Works, because it knows T is String as it is getting it in the method parameter, no need to rely on the variable that is getting the value
        MyMap myMap = (MyMap) getMap2(String.class); 
    }

}

这是Java中的一个复杂领域,有一些已知的限制可以降低编译器的复杂性。

答案 1 :(得分:0)

这是关于类型推断。假设我们有方法声明

<T> T foo(){ return null; }

之类的陈述
foo(); 

此处没有足够的信息来推断T

无法编译器使用上下文信息来辅助推理,例如

void bar(String str){ }

bar(foo());  // T must be String, right?

一般来说,不支持;你可以想象一般来说它会变得多么复杂。

然而,在两种特定情况下,类型推断中会考虑目标类型

String s = foo();   // assign it to a type

String baz()
{
    return foo();   // return it to a type
}

从Java5到Java7都是如此。

在Java 8中,类型推断利用了更多的上下文类型信息,您的代码可能会起作用:)