Java sınıfının nereden yüklendiğini bulun


184

Java sınıf yükleyicinin sınıfı nereden yüklediğini programatik olarak nasıl bilen var mı?

Genellikle sınıf yolunun çok uzadığı ve manuel aramanın gerçekten bir seçenek olmadığı büyük projeler üzerinde çalışıyorum. Geçenlerde classloader bir sınıfın yanlış bir sürümünü yüklerken bir sorun vardı çünkü iki farklı yerde sınıfyolunda idi.

Peki, classloader'ı gerçek sınıf dosyasının nereden geldiğini bana nasıl söyleyebilirim?

Düzenleme: Sınıf yükleyici aslında bir sürüm uyumsuzluğu (veya başka bir şey) nedeniyle sınıfı yüklemek başarısız olursa, yine de biz onu okumadan önce hangi dosyayı okumaya çalışıyorum bulabiliriz?


4
@JarrodRoberson Bu soru 2008'de sorulduğundan ve bu soru 2012'de sorulduğundan beri stackoverflow.com/questions/11747833/… 'nin bir kopyası olarak düşünüleceğini düşünmüyorum
luke

Yanıtlar:


189

İşte bir örnek:

package foo;

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

Bu çıktı:

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

32
Gereksiz yazmayı azaltmak için Test.class.getResource("Test.class"), paket adını tekrarlamayan daha kısa sürüm: de kullanılabilir .
meriton

1
Sınıf, örneğin bir .groovy dosyasından derlenmişse ne olur?
Ondra Žižka

35
@meriton: Ya da refactorinsgs hayatta kalmak için:Test.class.getResource(Test.class.getSimpleName() + ".class")
leonbloy

1
İçin BouncyCastleProvidertam paket adına ancak gereklidir.
Pavel Vlasov

3
Geri getClassLoader()dönmek mümkündür null. Bunu ele almak için bu yöntemin bir uzantısı için buraya bakın .
OldCurmudgeon

100

Bir sınıfın nereden yüklendiğini bulmanın başka bir yolu (kaynağı değiştirmeden) Java VM'yi şu seçenekle başlatmaktır: -verbose:class


6
bu çok iyi çalıştı ve null ClassLoader ile sınıflarla uğraşma sorunu yok
lexicalscope

2
@ries Eğer bunu programlı bir şekilde yapmanız gerekmiyorsa, bu kesinlikle gitmenin yoludur ve sorunumu çözdü. Ancak, OP özellikle bunu programlı olarak nasıl yapacağını sormuştu.
SantiBailors

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

4
Evet, yüklü bir güvenlik yöneticisi ile ve gerekli izinler olmadan çalışmasa da.
Tom Hawtin - tackline

1
FYI, NPE = Boş İşaretçi İstisnası. HTH!
Evgeni Sergeev

Aynı sınıfı iki farklı konumdan yükleyebileceğiniz için, bir örneğe başvurunuz olduğu sürece bu yöntem tercih edilir.
Miguel Ping

1
Ayrıca bir Java 9+ modülünden çağrıldığında da işe yaramaz (tabii ki 2008'de bilemezdiniz).
Jeff G

28

Kullandığımız bu:

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

Bu, ClassLoader uygulamasına bağlı olarak çalışacaktır: getClass().getProtectionDomain().getCodeSource().getLocation()


17

Nesnenin , Önyükleme tarafından yüklendiğini ima ettiği gibi ClassLoaderkaydedildiğinde Jon'un sürümü başarısız olur .nullClassLoader

Bu yöntem bu sorunla ilgilenir:

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

Yalnızca 1. satırı Maindüzenleyin : .class

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

System.out.println(path);

Çıktı:

/C:/Users/Test/bin/

Belki kötü tarzı ama iyi çalışıyor!


3

Tipik olarak, sabit kodlamanın ne kullanılacağını bilmiyoruz. Önce className'i alabiliriz ve sonra sınıf URL'sini almak için ClassLoader'ı kullanabiliriz.

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

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

MyClass.class önemlidir - getClass (), Proxy'yi döndürebilir! Ardından MyClass $$ EnhancerBySpringCGLIB $$ a98db882.class ve null URL gibi bir ad alabilirsiniz.
jalmasi


1

Basit yol:

System.out.println (java.lang.String.class.getResource (String.class.getSimpleName () + "sınıfı."));

Örnek:

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

Veya

String obj = "basit test"; System.out.println (obj.getClass () getResource (obj.getClass () getSimpleName () +).. "Sınıfı.");

Örnek:

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


0

Bu yaklaşım hem dosyalar hem de kavanozlar için geçerlidir:

Class clazz = Class.forName(nameOfClassYouWant);

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

-1

Adlı bir sınıfla çalıştığınızı varsayarsak MyClass, aşağıdakilerin çalışması gerekir:

MyClass.class.getClassLoader();

.Class dosyasının diskteki konumunu alıp alamayacağınız classloader'ın kendisine bağlıdır. Örneğin, BCEL gibi bir şey kullanıyorsanız, belirli bir sınıfın disk üzerinde gösterimi bile olmayabilir.


Bu, sınıfı yüklemek için kullanılan ClassLoader öğesini döndürür, değil mi? .Class dosyasının nerede olduğunu bulamıyor mu?
Koray Tugay

1
Hayır değil. Sınıf yükleyici aslında tamamen farklı sınıf yoluna başvurabilir - bu, gerçek sınıf konumunu tamamen elde edemeyeceği anlamına gelir.
Tomáš Zato - Monica'yı iade et
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.