Java: Проверьте, является ли универсальный тип int - PullRequest
2 голосов
/ 04 мая 2011
public class Hashing<Key, Elem>

Я хочу проверить, является ли Key целым, поэтому я помещаю следующие строки в конструктор:

Key key = null;
if (!(key instanceof Integer)) {
    throw new TypeOfKeyStillNotSupportedException();
}

Тем не менее, я создаю один таким образом:

tHash = new Hashing<Integer, Movie>(max);

И чертовски TypeOfKeyStillNotSupportedException () появляется. Почему это происходит и как я могу сделать это правильно?

Заранее спасибо.

Редактировать: Уже обнаружено, что проблема в том, что ключу присвоено значение NULL. Вопрос сейчас: как сделать чек?

Ответы [ 6 ]

3 голосов
/ 04 мая 2011

null - это не instanceof ничего. Из-за удаления типа невозможно проверить тип Key непосредственно во время выполнения. Один из вариантов - заставить пользователя передать Class<Key> в конструктор, чтобы вы могли проверить, что:

public Hashing(Class<Key> keyType, ...) {
  if (keyType != Integer.class) {
    throw new TypeOfKeyStillNotSupportedException();
  }
  ...
}

...

Hashing<Integer, Foo> hashing = new Hashing<Integer, Foo>(Integer.class, ...);

Чтобы избавить себя от необходимости повторять аргументы типа, вы можете создать статический фабричный метод:

public static <K, E> Hashing<K, E> create(Class<K> keyType, ...) {
  return new Hashing<K, E>(keyType, ...);
}

...

Hashing<Integer, Foo> hashing = Hashing.create(Integer.class, ...);
2 голосов
/ 04 мая 2011

Обобщения Java реализованы с использованием стирания типа : обобщенная информация отбрасывается компилятором после использования для проверки типов, поэтому во время выполнения ваш класс просто равен Hashing<Object, Object>. Вот почему вы не можете выполнять проверки во время выполнения на основе универсального типа.

Вы можете добавить аргумент типа Class<Key> в конструктор, и вызывающая сторона должна будет передать правильный объект класса для типа, используемого в качестве ключа. Например, в Hashing<Integer, String> в качестве значения этого аргумента будет приниматься только Integer.class, и вы можете использовать его для проверки типов во время выполнения. Однако требование передать объект класса ключа в качестве параметра делает вызов конструктора немного неловким.

2 голосов
/ 04 мая 2011

Если ваш код имеет «ключ = ноль;»прямо перед проверкой instanceof, исключение обязательно будет выдано.

Причина в том, что оператор instancof проверяет ссылку на тип объекта, на который указывает объект, а не на то, как он объявлен.

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

public static void main(String[] args) {
    //Object obj = new Integer(9);
    Object obj = null;

    if (!(obj instanceof Integer))
        System.out.println("Not Integer.");
    else
        System.out.println("Is Integer");
}

Также вы можете узнать более подробную информацию здесь:

http://download.oracle.com/javase/tutorial/java/nutsandbolts/op2.html

Надеюсь, это поможет:)


Полноценный пример Java Generics:

class GenTest<Key extends Integer, Value>{
    Key key;
    Value val;

    GenTest(Key key, Value val){
        this.key = key;
        this.val = val;

        System.out.println("Key: " + key + " Value: " + val);
    }
}

public class GenericRecap {
    public static void main(String[] args) {
        //Object obj = new Integer(9);
        Object obj = null;

        if (!(obj instanceof Integer))
            System.out.println("Not Integer.");
        else
            System.out.println("Is Integer");

        new GenTest<Integer, String>(9, "nine");
    //new GenTest<String, String>("funny", "nine");  // In-Error
    }
}

Также обратите внимание, что при наличии «Key extends Integer» во время выполнения будет выдано исключение, если вы передадите значение, не являющееся подклассом Integer.Более того, если вы используете и IDE, которая проверяет это, он будет помечен как «Тип не в пределах» класса GenTest.

Floats и Integer все наследуются от Number.Таким образом, вы можете «расширить Number», а затем проверить «instanceof Integer» или «instanceof Float» в зависимости от того, как вы хотите использовать его в своем коде.

Надеюсь, это поможет :) Cheers!

0 голосов
/ 04 мая 2011

Вам необходим метод isInstance , который является динамическим эквивалентом оператора instanceof.

Например,

Integer.class.isInstance(1); //return true
Integer.class.isInstance(null); //return false

Редактировать :
Если вы хотите проверить другой тип класса, напишите вспомогательный метод, подобный этому:

static <T> boolean isInstance(Class<T> type, Object obj) {
    return type.isInstance(obj);
}

Например,

Hashing.<String>isInstance(String.class, "hi"); // return true
0 голосов
/ 04 мая 2011

Способ справиться с этим - явно проверить на ноль; например,

Key key = null;
if (key == null) {
    throw new KeyIsNullException();
} else if (!(key instanceof Integer)) {
    throw new TypeOfKeyStillNotSupportedException();
}

// ... or (for the literal minded) ...

if (key != null && !(key instanceof Integer)) {
    throw new TypeOfKeyStillNotSupportedException();
}

Для справки, те люди, которые ответили, что это было связано с стиранием типов, находятся вне базы. Вы бы получили точно такое же поведение, если бы Key был определенным классом или интерфейсом.

(С другой стороны, если бы код сказал someObj instanceof Key ..., это было бы ошибкой компиляции из-за проблемы стирания типа.)

0 голосов
/ 04 мая 2011

Учитывая следующее из вашего примера:

public class Hashing<K, E>

Это не имеет смысла: потому что K - это Type, который может быть установлен на что угодно, когда класс специализирован. Я изменил имя с Key на K, чтобы убрать путаницу из-за того, что Key не представляет Type. Общим стандартом для имен Type является использование одиночных символов в большинстве случаев.

K key = null;
if (!(key instanceof Integer)) 
{
    throw new TypeOfKeyStillNotSupportedException();
}

если вы измените его на

K key = null;
if (!(key instanceof K)) 
{
    throw new TypeOfKeyStillNotSupportedException();
}

это было бы более Generic решение, но это также не имеет смысла, потому что key будет всегда быть типом K

key не может быть null, поскольку null не имеет значения Type

Не имея большего контекста с тем, что окружает проверку instanceof, я не знаю, каково ваше намерение.

Проверка Type для Generic с instanceof - это запах кода, и, вероятно, неправильный подход, независимо от того.

Посмотрите, как реализация java.util.HashMap решает эту проблему.

Есть только два места, где они используют instanceof, и это оба устаревших метода, которые принимают только Object и не безопасны для типов.

...