Тип литья молча не удалось с динамическим прокси и дженериками Java

StackOverflow https://stackoverflow.com/questions/19849208

Вопрос

Вопрос IMY касается поведения типа литья с динамическим прокси и дженериками Java. Более конкретно, я хочу инструментально предпринять объект Servellet, используя динамический прокси. Для лучшего повторного использования я принял несколько общих шаблонов кода для создания прокси -объектов, как показано ниже.

@SuppressWarnings("unchecked")
public static <T> T instrument(final T aT) {
    T proxy = (T) Proxy.newProxyInstance(aT.getClass().getClassLoader(), new Class[]{MyServelet.class}, new InvocationHandler() {
        @Override
        public Object invoke(Object aProxy, Method aMethod, Object[] aArgs) throws Throwable {
        ..... instrumentation logic goes here
        }
    });
     System.out.println("proxy class " + proxy.getClass());
     System.out.println("input class " + aT.getClass());
     return proxy;
}

Здесь t - мой класс реализации конкретного сервера, который реализует интерфейс MySerVellet. Однако, если я запускаю вышеупомянутый метод, он распечатывает

proxy class class com.sun.proxy.$Proxy0
input class class MyServeletImplementation

Поэтому мне интересно, что случилось с оператором типа кастинга в фрагменте кода. Кажется, что он тихо провалился, так как прокси не был поднят в MyserVeletimplementation, но он также не бросил ClassCastException. Может ли кто -нибудь пролить мне свет на это? Спасибо!

Это было полезно?

Решение

В реальном скомпилированном бай -коде метода не произошло. Тип стирания.

При генерации ByteCode компилятор рассматривает любую переменную типа параметра как имеет тот же тип, что и верхняя граница типа параметра, или Object Если тип неограничен. Так что если T В вашем методе было ограничение <T extends MyServelet>, компилятор обработал бы proxy как переменная типа MyServelet, и вставил актерский состав. Однако как T без ограничения, он рассматривается как переменная типа Object - Таким образом, нет актеров.

Другие советы

Смысл динамического прокси в том, что вас не заботятся о фактическом классе возвращаемого прокси. Вы просто заботитесь о том, что это реализует все желаемые и указанные интерфейсы.

Javadocs для newProxyInstance государство:

Возвращает:

Экземпляр прокси с указанным обработчиком вызова прокси -класса, который определяется указанным загрузчиком класса и реализует указанные интерфейсы

Так, newProxyInstance вернул экземпляр com.sun.proxy.$Proxy0 (Что бы это ни было, нам все равно), но это также удостоверилось, что это MyServelet. Анкет Вы должны быть в состоянии разыграть это MyServelet без ClassCastException, потому что newProxyInstance создал класс для реализации этого интерфейса, и вы указали, что он должен пройти в new Class[]{MyServelet.class}.

Для кастинга типа не удалось, дженерики Java должны были сделать вывод, что T является MyServelet, нет MyServeletImplementation. Анкет Возможно, когда ты позвонил instrument, ты сделал это так:

MyServelet proxy = YourClass.instrument(new MyServeletImplementation());

Так что актерский состав MyServelet что должно быть успешным, а не MyServeletImplementation, который должен потерпеть неудачу.

Причина, по которой вам нужно было добавить @SuppressWarnings("unchecked") потому что компилятор пытался предупредить вас, что вы делаете что -то не так. Добавив подавление, вы сказали компилятору, что вам было все равно, потому что вы знали, что делаете. Может быть, вам не следовало добавлять аннотацию, если бы вы не поняли, почему вы получили предупреждение в первую очередь?

Подсказка: общий актерский состав T proxy = (T) превращается в Object proxy = (Object) компилятором. («Стирание типа», как упомянуто в другом ответе).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top