Вопрос по генерикам - приведение типов
От: manenkov  
Дата: 14.06.07 07:56
Оценка:
Добрый день!

Есть такой набор классов:

public abstract class AbstractEntity
{
private int id;

public int getId()
{
return id;
}

public void setId(int id)
{
this.id = id;
}
}



public class Entities extends Hashtable<Integer, AbstractEntity>
{
}



public abstract class AbstractManager<T extends Entities, V extends AbstractEntity>
{
protected T entities;

public V get(int id)
throws NoSuchEntityException
{
V e = (V)entities.get(id);

if (e != null)
return e;
else
throw new NoSuchEntityException();
}
}

IDE показывает unchecked cast в классе AbstractManager в методе get на строке
V e = (V)entities.get(id);
Почему? Ведь явно показано что V есть наследник от AbstractEntity, entities.get(id) возвращает именно AbstractEntity. Если сделать так:
V e = entities.get(id);

то это будет ошибкой приведения типов (требуется V, найден AbstractEntity)

Почему так происходит?

И правильно ли я понимаю, что в рантайме нельзя создавать объект параметрического типа, т.е. мне придется инициализировать поле entities вне класса AbstractManager?

Спасибо.
Re: Вопрос по генерикам - приведение типов
От: Nicht Россия  
Дата: 14.06.07 08:23
Оценка:
Здравствуйте, manenkov, Вы писали:

M>Добрый день!




M>public abstract class AbstractManager<T extends Entities, V extends AbstractEntity>

M>{
M> protected T entities;

M> public V get(int id)

M> throws NoSuchEntityException
M> {
M> V e = (V)entities.get(id);

M> if (e != null)

M> return e;
M> else
M> throw new NoSuchEntityException();
M> }
M>}


M>то это будет ошибкой приведения типов (требуется V, найден AbstractEntity)


M>Почему так происходит?


M>И правильно ли я понимаю, что в рантайме нельзя создавать объект параметрического типа, т.е. мне придется инициализировать поле entities вне класса AbstractManager?


M>Спасибо.


Во первых форматирование!!!

Во вторых не понятно зачем такой огород, если можно написать так.

public abstract class AbstractManager<V extends AbstractEntity> {
        protected Map<Integer, V> entities = new HashMap<Integer, V>();

        public V get(int id) throws NoSuchEntityException {
            V e = (V) entities.get(id);

            if (e != null)
                return e;
            else
                throw new NoSuchEntityException();
        }
    }


На твой вопрос скажу, что нет. В рантайме создавать параметризованный тип нельзя. Их и нет в рантайме. Параметризация сучествует только на уровне компиляции. Почитай про особенности реализации Generics в java. Ключевое слово затирание (erasure).
Re: Вопрос по генерикам - приведение типов
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 14.06.07 08:26
Оценка: 1 (1)
Здравствуйте, manenkov, Вы писали:

Сделайте так:

package ru.rsdn.generics;

import java.util.Hashtable;

public abstract class AbstractManager<T extends Hashtable<Integer, V>, V extends AbstractEntity> {
    protected T entities;

    public V get(int id) throws NoSuchEntityException {
        V e = entities.get(id);
        if (e != null)
            return e;
        else
            throw new NoSuchEntityException();
    }
}

Небольшой рефакторинг и все работает.

M>Почему так происходит?

А вы проведите простой эксперимент:

package ru.rsdn;

public class A {
}

package ru.rsdn;

public class B extends A {
}

package ru.rsdn;

public class Test {
    public static void main(String[] args) {
        B b = new A(); // compile error: can't convert A to B
    }
}

Намек понятен?
В вашем коде аналогично: попытка приведения базового класса к наследнику.

M>И правильно ли я понимаю, что в рантайме нельзя создавать объект параметрического типа, т.е. мне придется инициализировать поле entities вне класса AbstractManager?

Да, экземпляр обобщенного типа Java нельзя создать внутри класса, который по нему параметризован, только извне.
... << RSDN@Home 1.2.0 alpha rev. 679>>
Re[2]: Вопрос по генерикам - приведение типов
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 14.06.07 08:38
Оценка:
А еще лучше вообще так:

package ru.rsdn.generics;

import java.util.Hashtable;

public abstract class AbstractManager<T extends Hashtable<Integer, V>, V extends AbstractEntity> {
    protected T entities;

    public V get(int id) throws NoSuchEntityException {
        if (entities.containsKey(id))
            return entities.get(id);
        throw new NoSuchEntityException();
    }
}
... << RSDN@Home 1.2.0 alpha rev. 679>>
Re[2]: Вопрос по генерикам - приведение типов
От: manenkov  
Дата: 14.06.07 08:39
Оценка:
Здравствуйте, Nicht, Вы писали:

Да, так намного проще...занялся генериками только 3 дня назад, пока собираю грабли.

кстати, приведение типа к V можно опустить:



V e = entities.get(id);



ведь у нас уже мапа типов V.

Спасибо за помощь!

И еще один вопрос:

что не так с синтаксисом объявления класса


public class Entities extends Hashtable<Integer, T extends AbstractEntity>



?

вот так все нормально:

public class Entities extends Hashtable<Integer, AbstractEntity>



Смысл который я хотел вложить в первое описание — хеш с ключем integer и параметром — любым наследником от AbstractEntity.
Re[3]: Вопрос по генерикам - приведение типов
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 14.06.07 08:50
Оценка: +1
Здравствуйте, manenkov, Вы писали:

M>что не так с синтаксисом объявления класса

Параметризацию проводят в объявлении, а вы пытаетесь сделать в подстановке — и не совсем понятно зачем. Наверно хотели что-то вроде этого:
public class Entities<T extends AbstractEntity> extends Hashtable<Integer, T>
... << RSDN@Home 1.2.0 alpha rev. 679>>
Re[3]: Вопрос по генерикам - приведение типов
От: Stormblast http://www.myspace.com/stormblastblack
Дата: 14.06.07 08:51
Оценка: +1
Здравствуйте, manenkov, Вы писали:

M>И еще один вопрос:


M>что не так с синтаксисом объявления класса


M>

M>public class Entities extends Hashtable<Integer, T extends AbstractEntity>
M>



M>?


public class Entities<T extends AbstractEntity> extends Hashtable<Integer, T>
Re: Вопрос по генерикам - приведение типов
От: stenkil  
Дата: 14.06.07 09:03
Оценка:
Здравствуйте всем

JDeveloper объявления приведенные автором кушает спокойно и даже просит убрать (V) в
  V e = (V)entities.get(id);

а JBuilder 2007 действительно не пропускает, разрешает только
public abstract class AbstaractManager<T extends Entities<V>, V extends AbstractEntity>{


Похоже придется учитывать и IDE
Re[2]: Вопрос по генерикам - приведение типов
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 14.06.07 09:19
Оценка:
Здравствуйте, stenkil, Вы писали:

S>Похоже придется учитывать и IDE

Скорее всего просто настройки компилятора в IDE — предупреждения попросту можно отключить.
... << RSDN@Home 1.2.0 alpha rev. 679>>
Re[3]: Вопрос по генерикам - приведение типов
От: stenkil  
Дата: 14.06.07 09:25
Оценка:
Здравствуйте, rsn81, Вы писали:

R>Скорее всего просто настройки компилятора в IDE — предупреждения попросту можно отключить.


Предупреждения подключены
Re[3]: Вопрос по генерикам - приведение типов
От: LeonidV Ниоткуда http://vygovskiy.com
Дата: 14.06.07 11:34
Оценка:
Здравствуйте, rsn81, Вы писали:

R>Здравствуйте, stenkil, Вы писали:


S>>Похоже придется учитывать и IDE

R>Скорее всего просто настройки компилятора в IDE — предупреждения попросту можно отключить.
Но, наверное, все-таки не нужно. Можно использовать @SuppressWarnings
http://jvmmemory.com — простой способ настройки JVM
Re[4]: Вопрос по генерикам - приведение типов
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 14.06.07 12:46
Оценка:
Здравствуйте, LeonidV, Вы писали:

LV>Но, наверное, все-таки не нужно.

А разве предлагал? Просто предположил, что в JDeveloper-е умолчальные настройки компилятора такие.

LV> Можно использовать @SuppressWarnings

Каюсь, использую, стараюсь пореже.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.