В Java, как экземпляр и бросок типа (т.е. (Имя класса)) работают над объектом прокси?

Java генерирует прокси-класс для данного интерфейса и обеспечивает экземпляр прокси-класса. Но когда мы вводим, бросает объект прокси к нашему конкретному объекту, как Java обрабатывает это внутренне? Это рассматривают как специальный сценарий?

Например, у меня есть класс OriginalClass и это реализует OriginalInterface, когда я создаю объект прокси путем передачи OriginalInterface интерфейс Java создал прокси-класс ProxyClass использование методов в обеспеченном интерфейсе и обеспечивает объект этого класса (т.е. ProxyClass). Если мое понимание корректно, затем может Вы отвечать на следующие запросы

  1. Когда я ввожу объект броска ProxyClass к моему классу OriginalClass это работает, но как Java позволяет это? То же в случае instace?
  2. Поскольку мой Java знаний создает прокси-класс только с методами, но что происходит, когда я пытаюсь получить доступ к атрибутам на этом объекте?
  3. Только методы интерфейса становятся реализованными в прокси, но что происходит, когда я пытаюсь получить доступ к методу, который не в интерфейсе и только упомянул в классе?

Спасибо, студент

8
задан Joachim Sauer 3 May 2010 в 11:00
поделиться

2 ответа

Java не позволяет приводить от прокси к конкретному классу. Прокси в JDK (java.lang.reflect.Proxy) являются только прокси интерфейса. Полученный прокси имеет тип ProxyX (X - число), и если вы попытаетесь привести его к любому классу, то получите ClassCastException

Поэтому ваши 2-й и 3-й вопросы не актуальны - прокси не подкреплен конкретным классом. Для этого можно использовать другие механизмы проксирования - CGLIB или javassist. Они используют динамический подкласс, и поэтому все защищенные (и выше) поля и методы доступны подклассу (прокси).

11
ответ дан 5 December 2019 в 08:51
поделиться

Из документации javadocs API для java.lang.reflect. InvocationHandler:

InvocationHandler - это интерфейс, реализованный обработчиком вызова экземпляра прокси.

Динамический прокси реализует интерфейс, но использует обработчик (OriginalClass) для предоставления базовых реализаций методов.

Чтобы ответить на ваши вопросы:

  1. Компилятор позволит вам выполнить приведение, если у него недостаточно информации, чтобы быть уверенным, что приведение не может быть успешным. Поведение тестов приведения и instanceof для динамических прокси-серверов во время выполнения описано в документации javadoc для java.lang.reflect.Proxy. Приведение и тесты instanceof будут успешными, если они используются с интерфейсами, но не с классами.
  2. Вы не можете получить доступ к каким-либо атрибутам с помощью динамического прокси, потому что он реализует интерфейс, а не расширяет класс обработчика.
  3. Вы не можете получить доступ к каким-либо методам, не объявленным в интерфейсе, с помощью динамического прокси, потому что он реализует интерфейс, а не расширяет класс обработчика.

Внутри реализации динамического прокси (например, в реализации метода invoke (...)) вы можете получить доступ к членам обработчика, используя отражение.

Вот тестовый код, который я использовал для проверки своего ответа:

// package ...;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import junit.framework.Assert;

import org.junit.Test;

public class TestDynamicProxy
{
    @Test
    public void testCast() throws Exception {
        Foo foo = (Foo) TestProxy.newInstance(new FooImpl());
        foo.bar(null);

        System.out.println("Class: " + foo.getClass());
        System.out.println("Interfaces: " + foo.getClass().getInterfaces());

        Assert.assertNotNull(foo);
        Assert.assertTrue(foo instanceof Foo);
        Assert.assertFalse(foo instanceof FooImpl);
    }
}

interface Foo
{
    Object bar(Object obj) throws Exception;
}

class FooImpl implements Foo
{
    public Object bar(Object obj) throws Exception {
        return null;
    }
}

class TestProxy implements java.lang.reflect.InvocationHandler
{
    private final Object obj;

    public static Object newInstance(Object obj) {
        return java.lang.reflect.Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new TestProxy(obj));
    }

    private TestProxy(Object obj) {
        this.obj = obj;
    }

    public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
        Object result;

        try {
            result = m.invoke(obj, args);
        }
        catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
        catch (Exception e) {
            throw new RuntimeException("unexpected invocation exception: " + e.getMessage());
        }

        return result;
    }
}

Эта статья содержит много полезной информации и примеров кода.

8
ответ дан 5 December 2019 в 08:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: