2010-05-03 27 views
7

Java tạo một lớp proxy cho một giao diện cụ thể và cung cấp cá thể của lớp proxy. Nhưng khi chúng ta gõ đối tượng proxy vào Object cụ thể của chúng ta, java xử lý nội bộ như thế nào? Đây có phải là trường hợp đặc biệt không?Trong Java, cách thể hiện kiểu và kiểu truyền (nghĩa là (ClassName)) hoạt động trên đối tượng proxy?

Ví dụ tôi có lớp OriginalClass và nó thực hiện OriginalInterface, khi tôi tạo đối tượng proxy bằng cách thông qua giao diện OriginalInterface Java tạo Proxy lớp ProxyClass sử dụng các phương pháp trong giao diện cung cấp và cung cấp đối tượng của lớp này (nghĩa là. ProxyClass). Nếu hiểu biết của tôi là đúng thì bạn có thể xin vui lòng trả lời các truy vấn

  1. Khi tôi gõ đúc tượng của ProxyClass đến lớp học của tôi OriginalClass làm việc này, nhưng làm thế nào Java được cho phép này sau đây? Tương tự trong trường hợp instace của?
  2. Theo kiến ​​thức của tôi, Java chỉ tạo một lớp proxy với các phương thức, nhưng điều gì xảy ra khi tôi cố gắng truy cập các thuộc tính trên đối tượng này?
  3. Chỉ các phương thức giao diện mới được triển khai trong proxy, nhưng điều gì sẽ xảy ra khi tôi cố truy cập một phương thức không có trong giao diện và chỉ được đề cập trong lớp?

Cảm ơn, Student

+1

Bạn có chắc chắn rằng việc truyền proxy của mình tới OriginalClass hoạt động không? Theo hiểu biết của tôi nếu bạn đã tạo proxy cho OriginalInterface, bạn không thể truyền tới OriginalClass –

Trả lời

11

Java không cho phép đúc từ một proxy để một lớp bê tông. Các proxy JDK (java.lang.reflect.Proxy) chỉ là proxy của một giao diện. Proxy kết quả là loại ProxyX (X là số) và nếu bạn cố gắng truyền tới bất kỳ lớp nào, bạn sẽ nhận được ClassCastException

Do đó câu hỏi thứ 2 và thứ 3 của bạn không có liên quan - proxy không được hỗ trợ bởi một lớp bê tông. Để đạt được điều này, bạn có thể sử dụng các cơ chế proxy khác - CGLIB hoặc javassist. Họ sử dụng phân lớp ynamic, và vì vậy tất cả các trường và phương thức protected (và ở trên) có thể truy cập được vào lớp con (proxy).

+0

Cảm ơn rất nhiều vì đã trả lời nhanh chóng của bạn. Java không cho phép truyền tới lớp bê tông. – learner

7

Từ javadocs API cho java.lang.reflect.InvocationHandler:

InvocationHandler là giao diện được thực hiện bởi bộ xử lý gọi của một trường hợp proxy.

Proxy động triển khai giao diện, nhưng sử dụng trình xử lý (OriginalClass) để cung cấp triển khai cơ sở của phương pháp.

Để trả lời câu hỏi của bạn:

  1. Trình biên dịch sẽ cho phép bạn chọn vào vai miễn là nó không có đủ thông tin để chắc chắn rằng các diễn viên không thể thành công. Các hành vi thời gian chạy của đúc và instanceof thử nghiệm cho proxy động được mô tả trong javadoc cho java.lang.reflect.Proxy. Các test và instanceof sẽ thành công nếu được sử dụng với các giao diện, nhưng không thành công nếu được sử dụng với các lớp.
  2. Bạn không thể truy cập bất kỳ thuộc tính nào bằng proxy động vì nó thực hiện giao diện, nó không mở rộng lớp trình xử lý.
  3. Bạn không thể truy cập bất kỳ phương thức nào không được khai báo trong giao diện bằng proxy động bởi vì nó triển khai giao diện, nó không mở rộng lớp trình xử lý.

Bên trong việc triển khai proxy động (ví dụ: khi triển khai lệnh gọi (...)) bạn có thể truy cập các thành viên của trình xử lý bằng cách sử dụng sự phản chiếu.

Dưới đây là một số mã kiểm tra mà tôi sử dụng để kiểm tra câu trả lời của tôi:

// 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; 
    } 
} 

article này có rất nhiều thông tin hữu ích và mã ví dụ.

+0

Cảm ơn rất nhiều. Thông tin của bạn rất hữu ích. – learner

Các vấn đề liên quan