Temukan dari mana kelas java diambil


184

Apakah ada yang tahu bagaimana cara pemrograman menemukan di mana java classloader sebenarnya memuat kelas dari?

Saya sering mengerjakan proyek besar di mana classpath menjadi sangat panjang dan pencarian manual bukan pilihan. Saya baru-baru ini memiliki masalah di mana classloader memuat versi kelas yang tidak benar karena ada di classpath di dua tempat yang berbeda.

Jadi bagaimana saya bisa mendapatkan classloader untuk memberi tahu saya di mana pada disk file kelas yang sebenarnya berasal?

Sunting: Bagaimana jika classloader benar-benar gagal memuat kelas karena ketidakcocokan versi (atau sesuatu yang lain), adakah di sana kita bisa mengetahui file apa yang coba dibaca sebelum membacanya?


4
@JarrodRoberson Saya tidak berpikir ini harus dianggap duplikat dari stackoverflow.com/questions/11747833/… karena pertanyaan ini ditanyakan pada tahun 2008 dan pertanyaan itu ditanyakan pada tahun 2012
Lukas

Jawaban:


189

Ini sebuah contoh:

package foo;

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

Ini dicetak:

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

32
Untuk mengurangi pengetikan yang berlebihan, kita juga bisa menggunakan versi yang lebih pendek:, Test.class.getResource("Test.class")yang tidak mengulangi nama paket.
meriton

1
Bagaimana jika kelas dikompilasi, misalnya dari file .groovy?
Ondra Žižka

35
@meriton: Atau, untuk bertahan hidup refactorinsgs:Test.class.getResource(Test.class.getSimpleName() + ".class")
leonbloy

1
Namun untuk BouncyCastleProvidernama paket lengkap diperlukan.
Pavel Vlasov

3
Dimungkinkan untuk getClassLoader()kembali null. Lihat di sini untuk ekstensi ke metode ini untuk mengatasinya.
OldCurmudgeon

100

Cara lain untuk mengetahui dari mana kelas diambil (tanpa memanipulasi sumber) adalah memulai Java VM dengan opsi: -verbose:class


6
ini bekerja sangat baik, dan tidak memiliki masalah berurusan dengan kelas-kelas dengan null ClassLoader
lexicalscope

2
@ries Jika seseorang tidak perlu melakukan ini secara terprogram, ini jelas merupakan cara untuk pergi, dan itu memang memecahkan masalah saya. Namun, OP telah bertanya secara spesifik bagaimana melakukan ini secara terprogram.
SantiBailors

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

4
Yup, meskipun itu tidak bekerja dengan manajer keamanan diinstal dan tanpa izin yang diperlukan.
Tom Hawtin - tackline

1
FYI, NPE = Null Pointer Exception. HTH!
Evgeni Sergeev

Metode ini lebih disukai selama Anda memiliki referensi ke sebuah instance, karena Anda dapat memuat kelas yang sama dari dua lokasi yang berbeda.
Miguel Ping

1
Juga tidak berfungsi ketika dipanggil dari modul Java 9+ (yang tentu saja Anda tidak tahu pada 2008).
Jeff G

28

Inilah yang kami gunakan:

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

Ini akan bekerja tergantung pada implementasi ClassLoader: getClass().getProtectionDomain().getCodeSource().getLocation()


17

Versi Jon gagal ketika objek ClassLoaderterdaftar sebagai nullyang tampaknya menyiratkan bahwa itu dimuat oleh Boot ClassLoader.

Metode ini berkaitan dengan masalah itu:

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

Sunting hanya baris pertama: Main.class

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

System.out.println(path);

Keluaran:

/C:/Users/Test/bin/

Mungkin gaya yang buruk tetapi bekerja dengan baik!


3

Biasanya, kami tidak menggunakan hardcoding. Kita bisa mendapatkan className terlebih dahulu, dan kemudian menggunakan ClassLoader untuk mendapatkan URL kelas.

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

Perlu: URL classUrl = MyClass.class.getClassLoader (). GetResource ("/" + className);
Andrew Coates

MyClass.class adalah bagian penting - getClass () dapat mengembalikan Proxy! Maka Anda bisa mendapatkan nama seperti MyClass $$ EnhancerBySpringCGLIB $$ a98db882.class, dan null URL.
jalmasi


1

Cara sederhana:

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

Contoh Keluar:

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

Atau

String obj = "tes sederhana"; System.out.println (obj.getClass (). GetResource (obj.getClass (). GetSimpleName () + ". Class"));

Contoh Keluar:

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


0

Pendekatan ini berfungsi untuk file dan guci:

Class clazz = Class.forName(nameOfClassYouWant);

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

-1

Dengan asumsi bahwa Anda bekerja dengan kelas bernama MyClass, berikut ini harus berfungsi:

MyClass.class.getClassLoader();

Apakah Anda bisa mendapatkan lokasi di-disk dari file .class tergantung pada classloader itu sendiri. Misalnya, jika Anda menggunakan sesuatu seperti BCEL, kelas tertentu bahkan mungkin tidak memiliki representasi di-disk.


Ini mengembalikan ClassLoader yang digunakan untuk memuat kelas, bukan? Tidak menemukan di mana file .class berada?
Koray Tugay

1
Tidak, tidak. Classloader sebenarnya dapat merujuk ke jalur kelas yang sama sekali berbeda - artinya itu akan sama sekali tidak dapat mengubah lokasi kelas yang sebenarnya.
Tomáš Zato - Pasang kembali Monica
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.