2014-09-26 2 views
0

У меня есть перечисление в моем классе, который содержит атрибут класса, а так:Получить экземпляр универсального класса из атрибута перечислений в Java

public enum DatEnum { 
    CONSTANT_ONE(ClassOne), 
    CONSTANT_TWO(ClassTwo); 

    private Class<? extends UpperBoundClass> classAttribute; 

    private DatEnum(Class<? extends UpperBoundClass> classAttribute) { 
    this.classAttribute = classAttribute; 
    } 

    public <T extends UpperBoundClass> T getInstance() { 
    UpperBoundClass instance = classAttribute.newInstance(); 
    return instance; 
    } 
} 

Но тогда я получаю предупреждение в первой строке геттер :

Непроверенный актер с захвата # 4-из? расширяет UpperBoundClass до Т

, а также во второй строке геттер:

Неконтролируемый литая из UpperBoundClass до Т

Пока код работает, но я бы очень хотел чтобы избавиться от предупреждения, а также лучше понять, что проблема на самом деле здесь.

+1

У вас нет перечислений констант там. –

+0

Кроме того, вы имеете в виду 'newInstance'? –

+0

Технически, все, что вам нужно, это полуколония над декларацией поля, но это действительно странно, что вы можете сделать что-то подобное. – Makoto

ответ

1
public <T extends UpperBoundClass> T getInstance() { 
    UpperBoundClass instance = classAttribute.newInstance(); 
    return instance; 
} 

Этот код делает не фактически вернуть <T>. Он возвращает экземпляр конкретного Class<? extends UpperBoundClass>, на который ссылается поле classAttribute. Весь компилятор может проверить, что instance назначается (может быть отлит) UpperBoundClass. Однако не существует заявленной взаимосвязи между этим экземпляром и конкретным типом, представленным в методе подписи <T>.

Конечный результат: вы получите предупреждение. Это может быть Слушайте до тех пор, пока каждое место, которое вы используете CONSTANT_ONE или CONSTANT_TWO, уже ожидает того же типа, что и в своих конструкторах, но компилятор не может обеспечить его выполнение или знать.

Если вы изменили метод к следующему, то вы увидите сайты, использование (в коде вызова), которые не являются строго Типобезопасными, поскольку они предполагают определенный подкласс:

public UpperBoundClass getInstance() { 
    return classAttribute.newInstance(); 
} 

Кроме того, вы может обеспечить некоторую связь между вашим <T> и хранимой ссылкой класса:

public <T extends UpperBoundClass> T getInstance(Class<T> type) { 
    UpperBoundClass instance = classAttribute.newInstance(); 
    return type.cast(instance); // verifies type-safety 
} 

Но мало смыслом делать это, потому что абонент может либо вызвать type.newInstance() сам или просто new ClassOne() (в зависимости от варианта использования). Призыв к type.cast(instance) мог выкинуть ClassCastException во время выполнения, но компилятор будет счастлив, потому что он считает это вашей проблемой.

Вы боретесь с тем, что enum представляет единообразного контракт; и хотя вы можете настраивать отдельные константы с полиморфным поведением, вы не можете использовать generics для параметризации базового API enum с чем-то, что варьируется от экземпляра к экземпляру.

Связанные чтения: Why shouldn't Java enum literals be able to have generic type parameters?

+0

Спасибо, Уильям! Я только что изменил getInstance() на то, что вы написали, и сайты использования не были типа-небезопасными. Мне интересно, будет ли getInstance() возвращать экземпляр UpperBoundClass или экземпляр подкласса, указанного в конструкторе? – Dieguito

+0

'Class.newInstance()' всегда возвращает экземпляр типа _exact_, представленный экземпляром 'Class'. В вашем вопросе это 'ClassOne.class' для' CONSTANT_ONE' и 'ClassTwo.class' для' CONSTANT_TWO'. Тем не менее, он появляется в API_, чтобы быть не более конкретным, чем «UpperBoundClass», и вызывающие абоненты не могут зависеть от какого-либо API, который недоступен в верхней границе без downcasting (и потенциально получить «ClassCastException»). Пока ваши абоненты должны использовать только методы на «UpperBoundClass», все будет в порядке. –

0

Прежде всего, ваш enum класс не имеет перечислимую constants.Secondly, я считаю, что ваш Enum объект будет иметь ClassObject как его memeber variables.In большинстве случаев, вы будете иметь один объект для каждого класса (если вы не используете несколько классов классов для загрузки класса), почему бы не использовать простую структуру данных, содержащую только объекты класса.

Как бы то ни было, вы всегда можете использовать Class.newInstance() или Class.getDeclaredConstructors(), чтобы получить Constructor и подать в суд на него, чтобы иметь свой собственный экземпляр.

+0

Я не уверен, что понимаю это правильно, но идея здесь состоит в том, чтобы иметь верхнюю границу переменной 'Class'' Object' для предоставления какой-то гарантии относительно того, что может сделать фактический экземпляр. – Dieguito

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