Tìm nơi lớp java được tải từ


183

Có ai biết làm thế nào để lập trình tìm ra trình tải lớp java thực sự tải lớp từ đâu không?

Tôi thường làm việc trên các dự án lớn trong đó đường dẫn lớp rất dài và tìm kiếm thủ công không thực sự là một lựa chọn. Gần đây tôi có một vấn đề trong đó trình nạp lớp đang tải một phiên bản không chính xác của một lớp vì nó nằm trên đường dẫn lớp ở hai nơi khác nhau.

Vậy làm thế nào tôi có thể yêu cầu trình nạp lớp cho tôi biết tệp trên lớp thực sự đến từ đâu?

Chỉnh sửa: Điều gì sẽ xảy ra nếu trình nạp lớp thực sự không tải được lớp do phiên bản không khớp (hoặc một cái gì đó khác), liệu chúng ta có thể tìm ra tệp nào đang cố đọc trước khi đọc nó không?


4
@JarrodRoberson Tôi không nghĩ rằng điều này nên được coi là một bản sao của stackoverflow.com/questions/11747833/ vì câu hỏi này đã được hỏi vào năm 2008 và câu hỏi đó đã được hỏi vào năm 2012
luke

Câu trả lời:


187

Đây là một ví dụ:

package foo;

public class Test
{
    public static void main(String[] args)
    {
        ClassLoader loader = Test.class.getClassLoader();
        System.out.println(loader.getResource("foo/Test.class"));
    }
}

Điều này in ra:

file:/C:/Users/Jon/Test/foo/Test.class

32
Để cắt giảm việc gõ thừa, người ta cũng có thể sử dụng phiên bản ngắn hơn : Test.class.getResource("Test.class"), không lặp lại tên gói.
meriton

1
Điều gì xảy ra nếu lớp được biên dịch, ví dụ từ tệp .groovy?
Ondra Žižka

35
@meriton: Hoặc, để sống sót tái cấu trúc:Test.class.getResource(Test.class.getSimpleName() + ".class")
leonbloy

1
Đối với BouncyCastleProvidertên gói đầy đủ là cần thiết tuy nhiên.
Pavel Vlasov

3
Nó có thể getClassLoader()trở lại null. Xem ở đây để mở rộng cho phương pháp này để xử lý đó.
OldCurmudgeon

100

Một cách khác để tìm ra nơi một lớp được tải từ (mà không cần thao tác với nguồn) là khởi động Java VM với tùy chọn: -verbose:class


6
điều này hoạt động rất tốt và không gặp vấn đề gì khi xử lý các lớp với null ClassLoader
vựng

2
@ries Nếu một người không cần phải làm điều này theo chương trình, đây chắc chắn là cách để đi và nó đã giải quyết vấn đề của tôi. Tuy nhiên, OP đã hỏi cụ thể cách thực hiện việc này theo chương trình.
SantiBailors 17/2/2017

79
getClass().getProtectionDomain().getCodeSource().getLocation();

4
Yup, mặc dù nó không hoạt động với trình quản lý bảo mật được cài đặt và không có quyền yêu cầu.
Tom Hawtin - tackline

1
FYI, NPE = Ngoại lệ con trỏ Null. HTH!
Evgeni Sergeev

Phương thức này được ưa thích miễn là bạn có một tham chiếu đến một thể hiện, vì bạn có thể tải cùng một lớp từ hai vị trí khác nhau.
Miguel Ping

1
Cũng không hoạt động khi được gọi từ mô-đun Java 9+ (tất nhiên bạn không thể biết vào năm 2008).
Jeff G

28

Đây là những gì chúng tôi sử dụng:

public static String getClassResource(Class<?> klass) {
  return klass.getClassLoader().getResource(
     klass.getName().replace('.', '/') + ".class").toString();
}

Điều này sẽ hoạt động tùy thuộc vào việc triển khai ClassLoader: getClass().getProtectionDomain().getCodeSource().getLocation()


17

Phiên bản của Jon không thành công khi đối tượng ClassLoaderđược đăng ký vì nulldường như ngụ ý rằng nó đã được Boot tải ClassLoader.

Phương pháp này giải quyết vấn đề đó:

public static String whereFrom(Object o) {
  if ( o == null ) {
    return null;
  }
  Class<?> c = o.getClass();
  ClassLoader loader = c.getClassLoader();
  if ( loader == null ) {
    // Try the bootstrap classloader - obtained from the ultimate parent of the System Class Loader.
    loader = ClassLoader.getSystemClassLoader();
    while ( loader != null && loader.getParent() != null ) {
      loader = loader.getParent();
    }
  }
  if (loader != null) {
    String name = c.getCanonicalName();
    URL resource = loader.getResource(name.replace(".", "/") + ".class");
    if ( resource != null ) {
      return resource.toString();
    }
  }
  return "Unknown";
}

5

Chỉnh sửa chỉ dòng 1 :. MainClass

Class<?> c = Main.class;
String path = c.getResource(c.getSimpleName() + ".class").getPath().replace(c.getSimpleName() + ".class", "");

System.out.println(path);

Đầu ra:

/C:/Users/Test/bin/

Có thể phong cách xấu nhưng hoạt động tốt!


3

Thông thường, chúng tôi không sử dụng mã hóa gì. Chúng ta có thể lấy className trước, sau đó sử dụng ClassLoader để lấy URL lớp.

        String className = MyClass.class.getName().replace(".", "/")+".class";
        URL classUrl  = MyClass.class.getClassLoader().getResource(className);
        String fullPath = classUrl==null ? null : classUrl.getPath();

Cần phải là: URL classUrl = MyClass. Class.getClassLoader (). GetResource ("/" + className);
Andrew Coates

MyClass. Class là phần quan trọng - getClass () có thể trả về Proxy! Sau đó, bạn có thể nhận được tên như MyClass $$ EnhancerBySpringCGLIB $$ a98db882. Class và null URL.
jalmasi


1

Cách đơn giản:

System.out.println (java.lang.String. Class.getResource (String. Class.getSimpleName () + ". Class"));

Ví dụ:

jar: file: / D: /Java/jdk1.8/jre/lib/rt.jar! /java/lang/String. class

Hoặc là

Chuỗi obj = "kiểm tra đơn giản"; System.out.println (obj.getClass (). GetResource (obj.getClass (). GetSimpleName () + ". Class"));

Ví dụ:

jar: file: / D: /Java/jdk1.8/jre/lib/rt.jar! /java/lang/String. class


0

Cách tiếp cận này hoạt động cho cả tệp và lọ:

Class clazz = Class.forName(nameOfClassYouWant);

URL resourceUrl = clazz.getResource("/" + clazz.getCanonicalName().replace(".", "/") + ".class");
InputStream classStream = resourceUrl.openStream(); // load the bytecode, if you wish

-1

Giả sử rằng bạn đang làm việc với một lớp có tên MyClass, những điều sau đây sẽ hoạt động:

MyClass.class.getClassLoader();

Việc bạn có thể lấy vị trí trên đĩa của tệp. Class hay không phụ thuộc vào chính trình nạp lớp. Ví dụ: nếu bạn đang sử dụng một cái gì đó như BCEL, một lớp nhất định thậm chí có thể không có biểu diễn trên đĩa.


Cái này trả về ClassLoader được sử dụng để tải lớp, phải không? Nó không tìm thấy tập tin. Class ở đâu?
Koray Tugay

1
Không, nó không có. Trình nạp lớp thực sự có thể giới thiệu đến đường dẫn lớp hoàn toàn khác - có nghĩa là nó sẽ hoàn toàn không thể quay lại vị trí lớp thực tế.
Tomáš Zato - Phục hồi Monica
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.