2012-04-17 32 views
5

Tôi có một số lớp A:Java ClassLoader thay đổi

public class A { 
    public A(String str) { 
     System.out.println("Create A instance: " + str); 
    } 

    public void methodA() { 
     System.out.println("#methodA1()"); 
    } 
} 

Và thực hiện lớp loader của tôi:

public class MyClassLoader extends ClassLoader { 
    public MyClassLoader() {  
     super(); 
    } 

    @Override 
    public synchronized Class<?> loadClass(String name) 
      throws ClassNotFoundException { 

     System.out.println("Load: " + name); 

     return super.loadClass(name); 
    } 
} 

Và bây giờ tôi cố gắng thay đổi default class loader trong chủ đề hiện tại:

import java.util.ArrayList; 
import java.util.List; 

public class ChangeLoaderTest { 
    public static void main(String[] args) { 
     // Save class loader so that we can restore later. 
     ClassLoader oldLoader = Thread.currentThread().getContextClassLoader(); 

     MyClassLoader newLoader = new MyClassLoader(); 
     try { 
      // Set new classloader. 
      Thread.currentThread().setContextClassLoader(newLoader); 

      // My class. 
      A a = new A("1"); 
      a.methodA(); 

      // Standard Java class. 
      List<Integer> list = new ArrayList<Integer>(); 
      list.add(2); 
      list.add(3); 
     } finally { 
      // Restore. 
      Thread.currentThread().setContextClassLoader(oldLoader); 
     } 
    } 
} 

ChangeLoaderTest đầu ra:

Create A instance: 1 
#methodA1() 

Không ai

Load: ... 

Tại sao? Làm thế nào tôi có thể thay đổi ClassLoader thành một số chủ đề?

+0

* "Tôi có một số loại A:" * Tôi đã chán. Không, điều đó không đúng, nhưng tôi sẽ không tiếp tục đọc. Trong khi một số người nghĩ tốt hơn là 'trừu tượng một vấn đề' đến mức bạn có thể diễn tả nó như những biểu tượng khó hiểu, tôi thích một số ngữ cảnh giúp giải thích những gì trong lớp 'A' khiến bạn muốn tải nó một cách năng động. I E. lớp 'A' có thể là' UserDefinedPlugIn' - cái sau cung cấp một số ngữ cảnh, cái cũ thì không. –

+0

Ok, tôi có thể giải thích ngữ cảnh của câu hỏi này. Tôi có lớp đọc hình ảnh vào 'BufferedImage'. Đôi khi nó là 'ImageIO.read (file)', đôi khi nó là 'Sanselan.getBufferedImage (file)'.Tôi có lớp của riêng mình để lưu hình ảnh và tôi nên tạo 'BuffredImage' từ tệp, sau đó sao chép dữ liệu từ' BufferedImage' vào đối tượng của tôi. Tôi muốn sử dụng một số lớp proxy để bắt tất cả các phương thức '#get (...)' gọi để lưu thông tin trong đối tượng của tôi. – dzav

Trả lời

4

Vì Marko Topolnik chỉ ra số context classloader is for use by frameworks. Để tự mình sử dụng trình nạp lớp, bạn phải gọi loadClass("somepackage.A") và sau đó sử dụng API phản chiếu để tạo một phiên bản mới của A (Class.newInstance()).

Bạn sẽ không thể sử dụng A hoặc các phương thức của nó trong nguồn của bạn trực tiếp vì mã gọi không biết A - nó sử dụng trình nạp lớp khác. Một giao diện hoặc baseclass của A có thể được nạp bởi trình nạp lớp thông thường có thể được sử dụng để tránh sự phản chiếu.

interface AIF{ 
     void someMethod(); 
} 
class A implements AIF{ 
     public void someMethod(){} 
} 


public void test(){ 
    MyLoader loader = new MyLoader(); 
    Class cla = loader.loadClass("A"); 
    AIF a = (AIF) cla.newInstance(); 
    a.someMethod(); 

} 
+0

Thật không may, bạn không thể xác định một constructor không mặc định trong một giao diện (bất kỳ constructor nào cho vấn đề đó) theo cách mà vanveber có nó. Vì vậy, entre phản ánh ... – mazaneicha

+0

@ mazaneicha bạn có thể bỏ qua điều đó bằng cách tạo ra lớp nhà máy và một giao diện nhà máy (chỉ khi bạn thực sự ghét sự phản chiếu). – josefx

0

Tôi nghĩ rằng điều xảy ra là trình nạp lớp của ứng dụng của bạn cũng là "cha mẹ" của trình nạp lớp của bạn có thể định vị A và tải nó. Do đó, trình tải lớp của bạn sẽ không được tìm kiếm hoặc sử dụng để tải A. Thành thật mà nói, tôi không có nhiều kinh nghiệm với các trình nạp lớp nhưng nếu bạn phân lớp một lớp sử dụng URL cho đường dẫn của lớp (để nó có thể định vị tệp lớp) và trình nạp lớp cha không thể tải nó (không phải là một phần của classpath), tùy chỉnh của bạn sẽ được sử dụng.

3

Cơ chế contextClassLoaderkhông phải được sử dụng bởi các thao tác Java cơ bản như new. Nó chỉ ở đó vì vậy các khung công tác khác nhau có thể truy cập trình nạp lớp ngữ cảnh phụ trách và tải các tài nguyên, các lớp, vv Java sẽ luôn sử dụng trình nạp lớp nạp mã đang thực thi. Đó là tài khoản bạn truy cập qua số ChangeLoaderTest.class.getClassLoader() - và bạn không thể làm gì với vấn đề này.

0

new A("1") sẽ không cắt. Bạn sẽ phải làm một cái gì đó như thế này để nạp lớp học của bạn trong bối cảnh của một lớp nạp mới:

{ 
    Class classA = newLoader.loadClass("A"); 
    Constructor classAConstructor = myClass.getConstructor(String.class); 
    Method methodA = classA.getMethod("methodA",null); 
    Object objectA = classAConstructor.newInstance("A"); 
    Object result = methodA.invoke(objectA,null); 
} 

Nếu không, như đã đề cập ở trên bởi user384706, hầu hết các "cao cấp" class loader sẽ được sử dụng để xác định vị trí và tải lớp A.

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