对于我的Swing项目,我需要同时支持 Java 5 和 Java 6 。
我已经定义了一个自定义JComponent
(称之为Picture
),并且在将其嵌入JScrollPane
之后,我将其放入使用DesignGridLayout管理器的JPanel
中。
DesignGridLayout支持基线对齐,这要归功于 swing-layout 开源库(实现对Java 5的基线支持,并提供与新Java 6基线支持的兼容性)。
我的Picture
类会覆盖 public int getBaseline(int width, int height)
,以便我可以为其定义正确的基线。请注意,“ override ”并不完全正确:它会覆盖Java6上的方法,但在Java5中定义它。
当我在Java5上运行我的示例应用时,一切都很好:我已正确使用我定义的Picture
基线。
但是,当我使用Java6 时,我的Picture#getBaseline()
方法无法被调用!当然我的图片的基线对齐很糟糕(居中)。
在检查Java6源代码后,我已经看到,在BasicScrollPaneUI
中,getBaseline()
在视口组件(我的getBaselineResizeBehavior()
实例)上首先调用Picture
。
仅当getBaseline()
返回getBaselineResizeBehavior()
时,它才会调用Component.BaselineResizeBehavior.CONSTANT_ASCENT
。
现在我的问题是getBaselineResizeBehavior()
是JComponent
的Java6方法,我无法在Java5中实现,因为它返回了Java5中不存在的枚举Component.BaselineResizeBehavior
。
所以我的问题(最后)是:我如何实现(或模拟?)getBaselineResizeBehavior()
以便我的类仍然可以在Java5环境中编译和运行?
答案 0 :(得分:2)
我该如何实现(或模拟?) getBaselineResizeBehavior()让我的 class仍然可以编译并在a中运行 Java5环境?
您无法使用Java 5库编译此方法声明,因为类型Component.BaselineResizeBehaviour不存在:
public Component.BaselineResizeBehavior getBaselineResizeBehavior()
您必须使用Java 6进行编译。如果您编译为1.5目标,您的类仍然可以在Java 5上运行,但您必须注意它们正常处理缺少的类型/方法。遇到这些情况时,请为这些情况添加测试。确保开发人员在签入之前尝试在Java 5上运行他们的代码。
例如,这个班级......
public class MyPanel extends javax.swing.JPanel {
public java.awt.Component.BaselineResizeBehavior getBaselineResizeBehavior() {
return java.awt.Component.BaselineResizeBehavior.OTHER;
}
public static void main(String[] args) {
new MyPanel();
System.out.println("OK");
}
}
...可以使用javac JDK编译器编译和运行如下:
X:\fallback>javac -version
javac 1.6.0_05
X:\fallback>javac -target 1.5 MyPanel.java
X:\fallback>"C:\Program Files\Java\jre1.5.0_10\bin\java.exe" -cp . MyPanel
OK
所有流行的IDE都提供了生成旧版本的选项。当您需要对代码路径做出决策时,可以使用反射在运行时测试方法/类型的存在。
未能设置目标将导致如下错误:
Exception in thread "main" java.lang.UnsupportedClassVersionError: Bad version n
umber in .class file
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$100(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClassInternal(Unknown Source)
答案 1 :(得分:2)
我会创建一个Picture的子类,也许叫做PictureJava6,它实现了getBaselineResizeBehaviour(),在创建Picture的实例时,执行:
public Component pictureFactory() {
if(javaVersion > "1.6") {
return new PictureJava6();
} else {
return new Picture();
}
}
答案 2 :(得分:0)
您可以使用反射尝试按名称获取CONSTANT_ASCENT返回值。如果无法反映,则为J5,否则为J6。这侧面显式依赖,允许编译到J5。
FOLL。是对话模态执行此操作的示例:
try {
Field fld=Class.forName("java.awt.Dialog$ModalExclusionType").getField("TOOLKIT_EXCLUDE");
Method mth=getClass().getMethod("setModalExclusionType",new Class[]{fld.getType()});
mth.invoke(this,new Object[]{fld.get(null)});
}
catch(Throwable thr) {
log.errorln("Unable to configure window to be unaffected by modal dialogs - dialogs may need to be closed to operate help.");
log.errorln("Use Java 6 or later to avoid modal dialogs conflicting with the help system.");
log.errorln("Exception: "+thr);
}
更新:我最初发布了J5代码注释掉的代码;我已经改变了,因为我意识到它混淆了这个问题,暗示J5代码在J6中不起作用 - 确实如此。
答案 3 :(得分:0)
我认为在解决虚函数和重载时,返回类型不被视为方法签名的一部分;可能是你可以定义你的“覆盖”方法来返回Object,并反映出我的第一个答案的返回枚举。由于您在J5中编译它不会是编译时冲突,但JVM仍应选择您的方法来覆盖...它可能或它可能会引发运行时异常。不过,值得一试。
例如:
public Object getBaselineResizeBehavior() {
Object ret;
// reflect out the return value
return ret;
}
任何错误处理都可以是System.out,纯粹用于调试,因为除非你是J6,否则不会调用它,因此正确编码的反射应该在调用时始终有效。
当然,我会评论这种方法,以便清楚地说明发生了什么。