#java
Вопрос:
Два класса с одинаковым именем, но загруженные разными загрузчиками классов, будут считаться разными. Тогда метод использует такой тип параметра, может ли этот метод использовать только экземпляр, загруженный загрузчиком классов A, но экземпляр, загруженный загрузчиком классов B, не может?
Следующая моя простая попытка
// src/main/java/com/example/Main.java
// src/main/java/com/example/classloader/Foo.java
public class Main {
public static void main(final String[] args)
throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException,
NoSuchMethodException, InvocationTargetException {
final String path = Main.class.getClassLoader().getResource("").getPath();
final CustomerClassLoader customerClassLoader = new CustomerClassLoader(path);
final Class<?> customFooClass = customerClassLoader.loadClass("com.example.classloader.Foo");
final Object foo1 = customFooClass.newInstance();
try (final ByteArrayOutputStream memory = new ByteArrayOutputStream()) {
try (final ObjectOutputStream de = new ObjectOutputStream(memory)) {
de.writeObject(foo1);
}
try (final ByteArrayInputStream in = new ByteArrayInputStream(memory.toByteArray())) {
try (final ObjectInputStream se = new ObjectInputStream(in)) {
final Foo foo2 = ((Foo) se.readObject());
Main.class.getMethod("from", Foo.class).invoke(new Main(), foo2);
final Class<?> customMainClass = customerClassLoader.loadClass("com.example.Main");
customMainClass
.getMethod("from", customFooClass)
.invoke(customMainClass.newInstance(), foo1);
}
}
}
}
public void from(final Foo foo) {
System.out.println(foo.getClass().getClassLoader());
}
}
/**
package com.example.classloader;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
public class CustomerClassLoader extends ClassLoader {
private final String rootDirPath;
public CustomerClassLoader(String rootDirPath) {
this.rootDirPath = rootDirPath;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.toLowerCase().contains("foo")) {
return this.findClass(name);
}
return super.loadClass(name);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
File javaFile = new File(rootDirPath name.replace('.', File.separatorChar) ".class");
if (javaFile != null amp;amp; javaFile.exists()) {
System.out.println(javaFile);
try {
byte[] javaClassBytes = FileUtils.readFileToByteArray(javaFile);
return defineClass(name, javaClassBytes, 0, javaClassBytes.length);
} catch (IOException e) {
e.printStackTrace();
}
}
throw new ClassNotFoundException(javaFile.getPath());
}
}
**/
на экране появится ошибка .getMethod("from", customFooClass)
Exception in thread "main" java.lang.NoSuchMethodException: com.example.Main.from(com.example.classloader.Foo)
Что я должен сделать Main#from(Foo)
, чтобы получить экземпляр Foo, созданный CustomerClassLoader
?
Большое спасибо.
Спасибо @user207421, после исправления nameToLowerCase.contains("foo")
в nameToLowerCase.contains("foo") || nameToLowerCase.contains("main")
,
customMainClass
.getMethod("from", customFooClass)
.invoke(customMainClass.newInstance(), foo1);
работает хорошо.
Поэтому я предполагаю, что загрузчик классов типа параметра должен совпадать с загрузчиком классов его класса.
Комментарии:
1. Было бы хорошо иметь больше контекста, поскольку это, по-видимому, проблема дизайна. Вам следует избегать загрузки того же типа в другой загрузчик классов.
2. Вместо
Foo.class
буквального цитирования загрузите класс из своего загрузчика классов.3. @user207421
customFooClass
загружается моим загрузчиком классов вgetMethod("from", customFooClass)
4. Но у вас есть
Foo.class
место, где вы получаете методMain.class.getMethod("from", Foo.class)
.5. Вы можете найти документацию ObjectInputStream.resolveClass информативной.