2016-10-16 2 views
1

Я пытаюсь загрузить классы из динамически загружаемого файла jar. В настоящее время я могу загрузить класс, который не распространяется на класс, отличный от объекта класса root, но я не могу загрузить класс, который расширяет пользовательский класс. Подробное описание моей проблемы заключается в следующем.Загрузить класс Java с суперклассом из динамически загружаемого файла jar

В проекте А, существует класс А, как:

class A { 
} 

В проекте B есть класс B1 и класс В2, как:

class B1 { 
} 

class B2 extends A { 
} 

Я экспортировал проект от А до a.jar, а проект B - b.jar. Код тестирования:

File f = new File("Z:\\Jars\\b.jar"); 
URLClassLoader urlClassLoader = new URLClassLoader(new URL[] { f.toURL() }, 
     System.class.getClassLoader()); 

Class<?> classB1 = (Class<?>) urlClassLoader.loadClass("b.B1"); 
System.out.println("B1 is loaded"); 

Class<?> classB2 = (Class<?>) urlClassLoader.loadClass("b.B2"); 
System.out.println("B2 is loaded"); 

класс В1 успешно загружен, но класс В2 не загружается из-за класса a.A не найдено исключение:

java -cp a.jar;b.jar; a.Main 
B1 is loaded 
Exception in thread "main" java.lang.NoClassDefFoundError: a/A 
Caused by: java.lang.ClassNotFoundException: a.A 
     at java.net.URLClassLoader.findClass(Unknown Source) 
     at java.lang.ClassLoader.loadClass(Unknown Source) 
     at java.lang.ClassLoader.loadClass(Unknown Source) 
     ... 12 more 

Как я могу решить эту проблему? Спасибо.

PS. С включением a.jar, класс В2 может быть загружен, но не следующий тест:

Class<A> classB2 = (Class<A>) urlClassLoader.loadClass("b.B2"); 
A ab2 = classB2.newInstance(); 

Первая строка это хорошо, но вторая строка срабатывает следующее исключение:

Exception in thread "main" java.lang.ClassCastException: b.B2 cannot be cast to a.A 
    at a.Main.main(Main.java:22) 

В2 должен быть экземпляр А, любая идея, почему это произошло?

+0

Как вы построите jar b.jar без включения класса A? Вы вручную удаляете A.class из b.jar? – Mahesh

+0

Я использовал Eclipse, я задал проект B, чтобы он зависел от проекта A, поэтому проект B может быть построен и иметь возможность экспортировать файл jar. Для примера выше, моя проблема была решена путем включения a.jar, класс B2 может быть загружен и может быть передан A. – DeepParticle

+1

Первый ответ в http://stackoverflow.com/questions/2591779/cast-across-classloader сказал что классы для одного и того же класса, загружаемые разными загрузчиками классов, не могут быть переброшены друг в друга. – DeepParticle

ответ

0

У вас есть два класса с именем a.A, загруженный загрузчиком класса по умолчанию вашего потока, а другой загружается вашим пользовательским загрузчиком классов.

Это сообщение путается, потому что у вас есть два класса, которые печатают a.A, но из разных загрузчиков классов вы не можете обменять один на другой. Что вам нужно сделать, это

Class classB2 = urlClassLoader.loadClass("b.B2") 
Object ab2 = classB2.newInstance(); 

Это происходит потому, что a.A который ваш поток будет загружаться от класса по умолчанию загрузчик и вы не можете использовать это, даже если это происходит, чтобы иметь такое же имя.

Другой способ обойти это только один загрузчик классов загрузите a.A с

File f = new File("Z:\\Jars\\b.jar"); 
URLClassLoader urlClassLoader = new URLClassLoader(new URL[] { f.toURL() }); 

Это будет использовать ClassLoader.getSystemClassLoader() для загрузки a.A поэтому есть только один класс с этим именем.

+0

спасибо за ваше четкое объяснение.Предложенный вами контекстный загрузчик классов - это новая концепция для меня, я увижу, смогу ли я заставить ее работать. – DeepParticle

+0

@DeepParticle - это тот, который использует текущий поток для загрузки классов. –

+1

было бы лучше просто получить загрузчик классов A, чем использовать загрузчик классов классов – the8472

Смежные вопросы