2015-12-21 3 views
0

У меня возникли проблемы с пониманием того, почему жалобное затмение жалуется. У меня есть два интерфейса:Общий класс, понять общие параметры

@Preload 
public interface KBaseAo extends FAQ 
{ 
    public static final String ID = "BASE_KEY"; 
} 

public interface FAQ extends Entity { 
    @Unique 
    @NotNull 
    String getBaseKey(); 
    void setBaseKey(String baseKey); 

    @NotNull 
    String getExcerpt(); 
    void setExcerpt(String excerpt); 
} 

где интерфейс Entity:

public interface Entity extends RawEntity<Integer> { 
    @AutoIncrement 
    @NotNull 
    @PrimaryKey("ID") 
    public int getID(); 
} 

Конкретный класс выглядит следующим образом:

public class FAQServiceImpl<T extends FAQ> {  
    private void save(Class<T> clazz, String ID_FIELD, String key, String excerpt) { 
     T entity = (T) aoManager.create(clazz, new DBParam(ID_FIELD, key), 
       new DBParam("EXCERPT", excerpt)); 
     entity.save(); 
    } 

    private <T extends FAQ> void save2(Class<T> clazz, String ID_FIELD, String key, String excerpt) { 
     T entity = (T) aoManager.create(clazz, new DBParam(ID_FIELD, key),new DBParam("EXCERPT", excerpt)); 
      entity.save(); 
    } 
    public Map<String, String> fetchExcerptsFor(Set<String> bodies) { 
     //call save2 or save here 
    } 
} 

Я пытаюсь вызвать сохранить как

save(KBaseAo.class, "SomeID", "SomeStr", "SomeStr"); 

, который дает ошибку компиляции

The method save(Class<T>, String, String, String) in the type FAQServiceImpl<T> is not applicable for the arguments (Class<KBaseAo>, String, String, String) 

Вызов save2 точно так же

save2(KBaseAo.class, "SomeID", "SomeStr", "SomeStr"); 

компилируется отлично, но переписывает тип T.

Что мне не хватает и не могу заставить save() работать?

Edit: Добавлен код вызова из двух сохраняет

+0

Где вы вызываете 'save' (или' save2') с 4 параметрами? Похоже, вы делаете это в методе экземпляра 'FAQServiceImpl ', поэтому 'T' не обязательно' KBaseAo'. –

+0

Как объект, на который вы ссылаетесь, объявляете эти методы? –

ответ

2

Ваш метод save использует тип класса уровня переменной T. При этом вы просите компилятор убедиться, что этот метод вызывается только с экземпляром класса, тип которого точно соответствует типичному типу экземпляра.

Например:

FAQServiceImpl<FooFAQ> instance = new FAQServiceImpl<>(); 
instance.save(FooFAQ.class, "", "", "", ""); // Fine. 

Вы не можете ссылаться на это с каким-то произвольным классом, который также бывает реализовать FAQ, потому что она не соответствует типу instance:

FAQServiceImpl<FooFAQ> instance = new FAQServiceImpl<>(); 
instance.save(BarFAQ.class, "", "", "", ""); // Compiler error. 

Но это то, что вы сейчас делаете в своем коде: вы говорите, что FAQServiceImpl имеет общий тип T, но вы хотите вызвать метод определенного типа KBaseAo:

FAQServiceImpl<T> instance = new FAQServiceImpl<>(); 
instance.save(KBaseAo.class, "", "", "", ""); // Compiler error. 

(даже если это продолжается внутри методов экземпляра в классе).

Однако save2 определяет новую переменную типа, которая просто происходит, чтобы иметь то же имя T. Между этой новой переменной типа и переменной уровня класса T нет никакой связи.

Таким образом, декларация save2 не требует классов, чтобы соответствовать: это просто необходимо некоторые класс, который реализует FAQ.

+0

Я понимаю, почему (мое) второе спасение работает, а первое нет. Мне все еще неясно, почему мне нужно вызвать instance.save (FooFAQ.class .....), поскольку экземпляр уже создан с помощью FooFAQ. Моя конечная цель состояла в том, чтобы избежать передачи ссылок класса с одного объекта на другой –

0

Существует существенная разница между этим методом ...

public void save(Class<T> clazz, String ID_FIELD, String key, String excerpt) 

... и это один ...

public <T extends FAQ> void save2(Class<T> clazz, String ID_FIELD, String key, String excerpt) 

. Первый является обычным методом общего класса класса, тогда как последний представляет собой общий метод , который может принадлежать либо универсальному классу, либо обычным. В частности, во втором методе T является объявленным как <T extends FAQ> в сигнатуре метода и не имеет никакого отношения к любому параметру типа T, который может быть объявлен хост-классом.

Таким образом, T в первом способе, является явным или выводом T из декларации объекта, на котором вызывается метод, в то время как T во втором методе является явным или Inferred один из вызова из метод. Ничто не требует от них какой-либо взаимосвязи между ними, и поэтому было бы яснее использовать в последнем случае другой параметр типа (который также имел бы результат не затенения параметра типа класса с тем же именем).

Кроме того, вы должны знать, что независимо от каких-либо отношений между двумя типами T и U, типами Klass<T> и Klass<U> не присвоения совместимы в любом направлении. Вот почему, например, вы не можете назначить List<String> переменной типа List<Object>.

Если вы вызываете один из ваших методов из одного из методов другого класса, то компилятор не знает, какое значение имеет параметр типа класса T. Указанный save() вызов, который вы представляете, действителен только тогда, когда T равен KBaseAo, но компилятор не видит, что T будет иметь это значение. С другой стороны, вызов save2() не имеет значения, какое значение имеет параметр типа класса. Значение параметра собственного типа этого метода с тем же именем может быть выведено из аргументов метода - в частности, из первого.

Смежные вопросы