Почему стирание java-типа изменяет неуниверсальный тип целевой коллекции? - PullRequest
1 голос
/ 25 сентября 2019

Прежде всего, я пришел из C #, но я знаю о стирании типов в Java.Но я не понимаю следующий пример кода ...

Когда я определяю целевую коллекцию с конкретным типом, я ожидаю, что эта коллекция сохранит этот тип.Даже если фактическая коллекция является результатом универсального метода.Поэтому я ожидаю ClassCastException, если назначена неподходящая коллекция.Но исключений не возникает, но внутренний тип целевой коллекции изменяется во время выполнения ... Позже я выполняю итерацию коллекции, получаю во время итерации ClassCastExceptions ... Я что-то не так делаю?Или это странное поведение правильно?

//There are 2 classes. Both implementing the same interface.
class CA implements IA
class CB implements IA



public void method1()
{
    //This is the target-collection. The Type is set to CA(!)
    //In Java, I expect an exception here! Why does Java change the type of
    //collection? This is very dangerous ... because I have defined a 
    //specific type. So I expect to get what I have defined.
    Collection<CA> result = getInstances();

    //Some Code...

    //Time to iterate the instances
    for(CA instance : result)
    {
        //ClassCastException at second instance...
    }
}

public <T extends IA> Collection<T> getInstances()
{
    //Resulting collection
    Collection<T> instances = new LinkedList<T>();


    for(int i = 0; i < 2; i++)
    {
        //In C#, an exception would occure exactly here.
        //That would be sooo fine... :(
        //I already wrote a solution for this. I use Class<T> to cast at
        //this point. So thats not my question. I just want to understand
        //why java is allowing to change the inner type of collection
        T instance = (T)getInstance(i);

        //Add the instance
        instances.add(instance);
    }

    //At this point, the collection will containing CA and(!) CB instances...
    return instances;
}

//Non-generic method!
public IA getInstance(int i)
{
    if(i == 0)
         return new CA();
    else
         return new CB();
}


Ответы [ 2 ]

3 голосов
/ 25 сентября 2019

Вы выполняете непроверенное приведение на

T instance = (T)getInstance(i);

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

В этом случае вы «не знаете, что делаете», т.е.Вы говорите: «Черт возьми систему типов!».Тогда все ставки отменены, и во время компиляции невозможно убедиться, что вы делаете правильные вещи.Во время выполнения вы можете получить исключения.

GhostCat упоминал о проверенных типах коллекциях.Вам не нужно реализовывать свои собственные классы для них, поскольку служебный класс Collections содержит методы для создания проверенных коллекций checkedList, checkedSet и т. Д. Они содержат дополнительный аргумент Class, который используется для проверки того, что содержимоеправильного типа.Используя их, вы получите исключение времени выполнения раньше, когда помещаете элементы в коллекцию, а не извлекаете их.

2 голосов
/ 25 сентября 2019

Когда я определяю целевую коллекцию с конкретным типом, я ожидаю, что эта коллекция сохранит этот тип

Неправильное ожидание.Обобщения в Java являются (почти) релевантными «только во время компиляции».

Существует только один класс ArrayList, который работает с аргументами типа Object.Ошибки, которые вы получаете от компилятора при добавлении «неправильного типа», таковы: только время компиляции.

Конечно, вы можете создать свою собственную реализацию списка , для которой создается конкретный экземпляр Class, а затем выполнить соответствующую проверку во время выполнения.И update : вы можете использовать один из вспомогательных методов класса Collection, например, checkedCollection () , чтобы создать коллекцию / список / набор / ..., которая делает именно это.

Помимо этого:

for(CA instance : result)
{
    //ClassCastException at second instance...

Здесь у вас есть явное приведение, вы заявляете: все объекты в списке результатов будут CA объектами, но, очевидно, не все таковыми являются.

...