Class.getResource () ve ClassLoader.getResource () arasındaki fark nedir?


194

Ben fark arasındadır merak Class.getResource()ve ClassLoader.getResource()?

edit: Özellikle herhangi bir önbellek dosya / dizin düzeyinde dahil olup olmadığını bilmek istiyorum. "Dizin listeleri Sınıf sürümünde önbelleğe alınmış mı?"

AFAIK aşağıdakileri esasen aynı şekilde yapmalıdır, ancak değildir:

getClass().getResource() 
getClass().getClassLoader().getResource()

Bunu WEB-INF/classes/, o dizindeki mevcut bir dosyadan yeni bir dosya oluşturan bazı rapor oluşturma kodlarıyla uğraşırken keşfettim . Class'tan yöntemi kullanırken getClass().getResource(), dağıtım sırasında orada bulunan dosyaları bulabilirim , ancak yeni oluşturulan dosyayı almaya çalışırken boş bir nesne aldım. Dizine göz atmak, yeni dosyanın orada olduğunu açıkça gösterir. Dosya adları "/myFile.txt" dosyasında olduğu gibi eğik çizgi ile eklenmiştir.

ClassLoaderSürümü getResource()diğer taraftan oluşturulan dosyayı buldunuz. Bu deneyimden, dizin listesinin önbelleğe alınmasının bir tür olduğu görülmektedir. Haklı mıyım ve eğer öyleyse, bu nerede belgeleniyor?

Gönderen API docs üzerindeClass.getResource()

Belirli bir ada sahip bir kaynak bulur. Belirli bir sınıfla ilişkili kaynakları arama kuralları, sınıfın tanımlayıcı sınıf yükleyicisi tarafından uygulanır. Bu yöntem, bu nesnenin sınıf yükleyicisine yetki verir. Bu nesne bootstrap sınıf yükleyicisi tarafından yüklendiyse, yöntem ClassLoader.getSystemResource (java.lang.String) için temsilci seçer.

Bana göre, bu "Class.getResource gerçekten kendi sınıf yükleyicinin getResource () diyor." Bu da yapmakla aynı olurdu getClass().getClassLoader().getResource(). Ama öyle değil. Birisi bana bu konuda biraz ışık verebilir mi?

Yanıtlar:


6

Herhangi bir önbellekleme olup olmadığı sorusunu cevaplamak için.

GetResourceAsStream ClassLoader yöntemini kullanarak sürekli olarak diskten bir dosya yükleyen tek başına bir Java uygulaması çalıştırarak bu noktayı daha fazla araştırdım. Dosyayı düzenleyebildim ve değişiklikler hemen yansıtıldı, yani dosya önbelleğe alınmadan diskten yeniden yüklendi.

Ancak , birkaç maven modülü ve birbirine bağımlı web projeleri olan bir proje üzerinde çalışıyorum. Web projelerini derlemek ve çalıştırmak için IDE olarak IntelliJ kullanıyorum.

Yukarıdakilerin artık doğru görünmediğini fark ettim, nedeni yüklenmekte olan dosyanın şimdi bir kavanoza pişirilmesi ve bağlı web projesine dağıtılması. Bunu sadece hedef klasörümdeki dosyayı değiştirmeye çalıştıktan sonra boşuna fark ettim. Bu, önbellekleme devam ediyor gibi görünüyordu.


Ben de Maven ve IntelliJ kullandım, bu yüzden bu benimkine en çok benzeyen ve 2. soru için makul bir açıklamaya sahip bir ortamın cevabı.
oligofren

251

Class.getResourcesınıfın paketine göre işlenen bir "göreli" kaynak adı alabilir. Alternatif olarak, eğik çizgi kullanarak bir "mutlak" kaynak adı belirleyebilirsiniz. Sınıf yükleyici kaynak yolları her zaman mutlak olarak kabul edilir.

Yani aşağıdakiler temel olarak eşdeğerdir:

foo.bar.Baz.class.getResource("xyz.txt");
foo.bar.Baz.class.getClassLoader().getResource("foo/bar/xyz.txt");

Ve bunlar da (ama yukarıdakilerden farklı):

foo.bar.Baz.class.getResource("/data/xyz.txt");
foo.bar.Baz.class.getClassLoader().getResource("data/xyz.txt");

Açık örneklerle güzel cevap. Gönderinin aslında iki soruya cevap alması amaçlanmış olsa da, şimdi ikinci soruların bir çeşit gizli olduğunu görüyorum. Ben bunu yansıtmak için yazı güncelleme gerekir / emin oldukça, ama ikinci bilmek istiyorum bu (sonraki yorum):
oligofren

2
Class.getResource () sürümünde bir tür önbellekleme oluyor mu? Bunun bazı jasper raporlarının oluşturulması olduğuna inanmamı sağlayan şey: jasper xml dosyasını almak için getClass (). GetResource ("/ aDocument.jrxml") kullanıyoruz. Daha sonra aynı dizinde bir ikili jasper dosyası üretilir . getClass (). getResource ("/ aDocument.jasper") bulamıyor, ancak aynı düzeydeki belgeleri (giriş dosyası) açıkça bulabiliyor. ClassLoader.getResource () yöntemi, dizin listesinin önbelleğe alınmadığı anlaşıldığı için yardımcı oldu. Ancak bununla ilgili belge bulamıyorum.
oligofren

2
@oligofren: Hmm ... Ben olmaz bekliyoruz ... Class.getResource () orada herhangi bir önbelleği yapmak
Jon Skeet

1
@JonSkeet neden this.getClass().getClassLoader().getResource("/");null döndürüyor? Aynı olmamalıthis.getClass().getClassLoader().getResource(".");
Asif Mushtaq

@UnKnown: Sanırım muhtemelen bu konuda yeni bir soru sormalısın.
Jon Skeet

22

İlk çağrı .classdosyaya göre, ikincisi sınıfyolu köküne göre arama yapar.

Bunun gibi hata ayıklamak için URL'yi yazdırıyorum:

System.out.println( getClass().getResource(getClass().getSimpleName() + ".class") );

3
Ben sadece seçici olmak için "classloader kökü" "sınıf yolu kökü" daha doğru olacağını düşünüyorum.
Jon Skeet

4
Dosya adı "/" ile
başlıyorsa

2
İlginç ... getClass (). GetResource ("/ someAbsPath"), /path/to/mylib.jar!/someAbsPath ve getClass (). GetClassLoafer (). GetCource (). / someAbsPath ") null döndürür ... Yani" classloader'ın kökü "çok iyi tanımlanmış bir kavram gibi görünmüyor ...
Pierre Henry


8
@PierreHenry: getClassLoader().getResource("/...")her zaman geri döner null- classloader öncüyü yoldan kaldırmaz /, bu nedenle arama her zaman başarısız olur. getClass().getResource()Bir başlangıcı yalnızca /sınıfyoluna göre mutlak bir yol olarak işler .
Aaron Digulla

17

Özellikleri bakmak zorunda kaldı:

Sınıfın getResource () - belgeleri farkı belirtir:

Bu yöntem çağrıyı sınıf yükleyicisine devreder, kaynak adında bu değişiklikleri yaptıktan sonra: kaynak adı "/" ile başlıyorsa değişmez; aksi takdirde, paket adı "." dönüştürüldükten sonra kaynak adına eklenir. "/" Bu nesne önyükleme yükleyicisi tarafından yüklendiyse, çağrı ClassLoader.getSystemResource'a devredilir.


2
Dizin listesini de önbelleğe alıp almadığı hakkında herhangi bir bilginiz var mı? Bu, bir girdi dosyasını ilk kez ararken ve ardından aynı dizinde bunu kullanarak bir dosya oluştururken iki yöntem arasındaki temel farktı. Class sürümü bulamadı, ClassLoader sürümü buldu (her ikisi de "/file.txt" kullanarak).
oligofren

11

Buralarda Bütün bu cevaplar yanı sıra cevaplar bu soruya , "/foo/bar.properties" aynı muamele gibi bu yükleme mutlak URL'ler, önermek class.getResourceAsStream(String)ve class.getClassLoader().getResourceAsStream(String). En azından Tomcat yapılandırmamda / versiyonunda (şu anda 7.0.40) durum böyle değil.

MyClass.class.getResourceAsStream("/foo/bar.properties"); // works!  
MyClass.class.getClassLoader().getResourceAsStream("/foo/bar.properties"); // does NOT work!

Üzgünüm, kesinlikle tatmin edici bir açıklamam yok, ama sanırım tomcat kirli yükler ve kara büyüsünü sınıf yükleyicilerle yapıyor ve fark yaratıyor. Her zaman class.getResourceAsStream(String)geçmişte kullandım ve hiç problem yaşamadım.

Not: Bunu da buraya gönderdim


Bu davranış Tomcat'te 8 sürümünde giderilen bir hata gibi görünüyor. Bu soruya
cevabımda

2

Class.getResourcesnesneyi yükleyen classloader tarafından kaynağı alır. Iken ClassLoader.getResourcebelirtilen classloader kullanarak kaynak almak.


0

Ben okumaya çalışıyordu sınıf ile birlikte benim paketlerden biri içinde input1.txt okuma denedim .

Aşağıdaki işler:

String fileName = FileTransferClient.class.getResource("input1.txt").getPath();

System.out.println(fileName);

BufferedReader bufferedTextIn = new BufferedReader(new FileReader(fileName));

En önemli bölüm getPath()Dize biçiminde doğru yol adını istiyorsanız aramak oldu . KULLANMAYINtoString() çünkü dosyaAdını TAMAMEN MESAJLAYACAK bazı ek biçimlendirme metinleri ekleyecektir (deneyebilir ve çıktıyı görebilirsiniz).

Bu hata ayıklama 2 saat geçirdim ... :(



Kaynaklar dosya değildir. JAR veya WAR dosyasından paketi açılmamış olabilirler ve eğer değilse FileReaderveya FileInputStreambunlara erişmek için kullanılamazlar. Cevap doğru değil.
Lorne Marquis
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.