简短的回答:不,不是(从 JavaFX 2.x 和 8.0 开始)。它可能在未来的版本中(JFX >8)
长答案:
FXMLLoader 目前并未设计为反复实例化相同项目的模板提供程序。相反,它旨在成为大型 GUI 的一次性加载器(或序列化它们)。
性能很差,因为取决于 FXML 文件,在每次调用 时load()
,FXMLLoader 必须通过反射查找类及其属性。这意味着:
- 对于每个 import 语句,尝试加载每个类,直到可以成功加载该类。
- 对于每个类,创建一个 BeanAdapter 来查找该类具有的所有属性,并尝试将给定的参数应用于属性。
- 再次通过反射将参数应用于属性。
目前load()
在代码中对同一 FXML 文件的后续调用也没有任何改进。这意味着:没有缓存找到的类,没有缓存 BeanAdapter 等等。
但是,通过将自定义类加载器设置为 FXMLLoader 实例,可以解决第 1 步的性能问题:
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
public class MyClassLoader extends ClassLoader{
private final Map<String, Class> classes = new HashMap<String, Class>();
private final ClassLoader parent;
public MyClassLoader(ClassLoader parent) {
this.parent = parent;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
Class<?> c = findClass(name);
if ( c == null ) {
throw new ClassNotFoundException( name );
}
return c;
}
@Override
protected Class<?> findClass( String className ) throws ClassNotFoundException {
// System.out.print("try to load " + className);
if (classes.containsKey(className)) {
Class<?> result = classes.get(className);
return result;
} else {
try {
Class<?> result = parent.loadClass(className);
// System.out.println(" -> success!");
classes.put(className, result);
return result;
} catch (ClassNotFoundException ignore) {
// System.out.println();
classes.put(className, null);
return null;
}
}
}
// ========= delegating methods =============
@Override
public URL getResource( String name ) {
return parent.getResource(name);
}
@Override
public Enumeration<URL> getResources( String name ) throws IOException {
return parent.getResources(name);
}
@Override
public String toString() {
return parent.toString();
}
@Override
public void setDefaultAssertionStatus(boolean enabled) {
parent.setDefaultAssertionStatus(enabled);
}
@Override
public void setPackageAssertionStatus(String packageName, boolean enabled) {
parent.setPackageAssertionStatus(packageName, enabled);
}
@Override
public void setClassAssertionStatus(String className, boolean enabled) {
parent.setClassAssertionStatus(className, enabled);
}
@Override
public void clearAssertionStatus() {
parent.clearAssertionStatus();
}
}
用法:
public static ClassLoader cachingClassLoader = new MyClassLoader(FXMLLoader.getDefaultClassLoader());
FXMLLoader loader = new FXMLLoader(resource);
loader.setClassLoader(cachingClassLoader);
这显着提高了性能。但是,第 2 步没有解决方法,因此这可能仍然是一个问题。
但是,官方 JavaFX jira 中已经有针对此的功能请求。如果你能支持这个请求,那就太好了。
链接: