Java Generics: сравнение класса Object o с <E>

Скажем, у меня есть следующий класс:

public class Test<E> {
    public boolean sameClassAs(Object o) {
        // TODO help!
    }
}

Как бы проверить, что o - это тот же класс, что и E?

Test<String> test = new Test<String>();
test.sameClassAs("a string"); // returns true;
test.sameClassAs(4); // returns false;

Я не могу изменить подпись метода из (Object o), поскольку я переопределяю суперкласс и поэтому не могу выбрать свою подпись метода.

Я также предпочел бы не идти по пути попытки броска, а затем поймать полученное исключение, если оно не получится.

Ответ 1

У экземпляра Test нет информации о том, что E находится во время выполнения. Итак, вам нужно передать Class<E> конструктору Test.

public class Test<E> {
    private final Class<E> clazz;
    public Test(Class<E> clazz) {
        if (clazz == null) {
            throw new NullPointerException();
        }
        this.clazz = clazz;
    }
    // To make things easier on clients:
    public static <T> Test<T> create(Class<T> clazz) {
        return new Test<T>(clazz);
    }
    public boolean sameClassAs(Object o) {
        return o != null && o.getClass() == clazz;
    }
}

Если вам нужна связь "instanceof", используйте Class.isAssignableFrom вместо сравнения Class. Примечание. E должен быть неэквивалентным типом, по той же причине Test нужен объект Class.

Примеры в API Java см. в java.util.Collections.checkedSet и т.д.

Ответ 2

Метод, который я всегда использовал, приведен ниже. Это боль и немного уродливая, но я не нашел лучшего. Вы должны передать тип класса через конструкцию, как при компиляции данных класса Generics.

public class Test<E> {
    private Class<E> clazz;
    public Test(Class<E> clazz) {
       this.clazz = clazz;
    }
    public boolean sameClassAs(Object o) {
        return this.clazz.isInstance(o);
    }
}

Ответ 3

Я мог только заставить это работать следующим образом:

public class Test<E> {  

    private E e;  

    public void setE(E e) {  
        this.e = e;  
    }

    public boolean sameClassAs(Object o) {  

        return (o.getClass().equals(e.getClass()));  
    }

    public boolean sameClassAs2(Object o) {  
        return e.getClass().isInstance(o);  
    }
}

Ответ 4

Я просто пытался сделать то же самое, и один простой трюк, который я только что понял, - это то, что вы можете попробовать попробовать, и если приведение не выполнено, ClassCastException будет выброшено. Вы можете это поймать и сделать что угодно.

поэтому ваш метод sameClassAs должен выглядеть так:

public boolean sameClassAs(Object o) {
    boolean same = false;
    try {
        E t = (E)o;
        same = true;
    } catch (ClassCastException e) {
        // same is false, nothing else to do
    } finally {
        return same;
    }
}