我有一个最初为Java1.4编写的项目,但我的Mac上只有Java 6,无法安装Java1.4。
通常,我会使用这样的行来编译:
javac -source=1.4 -target=1.4 MyClass.java但是,MyClass.java实现了java.sql.ResultSet接口,它在Java6中添加了几个新方法,因此我得到了如下编译错误:
MyClass is not abstract and does not override abstract method
updateNClob(java.lang.String,java.io.Reader) in java.sql.ResultSet我不能简单地实现缺少的方法,因为许多方法使用泛型,这些泛型在Java1.4中是不可用的。
似乎有一种解决方案是在Java1.4JAR上获取和编译。所以,我有几个问题:
谢谢!
发布于 2011-09-05 12:48:47
你的情况似乎是人为的。我会尽量简化事情。首先,我要忽略你关于Maven的问题。
首先让我陈述一些事实:
-source=1.4的意思是:亲爱的编译器,请只接受JDK1.4的javac提供的语言结构--而不是库特性。
-target=1.4的意思是:亲爱的编译器,请用与JRE1.4兼容的二进制文件格式编写类文件。
我认为您对JDK1.4的加载时间兼容性感兴趣,也就是说,您希望JDK1.4可以加载安装过程中生成的类文件。是那么回事吗?
您还想支持源代码兼容性吗?也就是说,您想让其他人在JDK1.4上编译您的代码吗?
如果对最后一个问题的回答是肯定的,我将尝试在OS上安装JDK1.4。它支持多个已安装的JDK。所以我很确定这是可能的。如果没有选择,请使用:
-source=1.4 -target=1.4 -bootclasspath=[path/to/1.4.jar]注意,不要使用-Xbootclasspath。这会改变执行javac的jvm的引导类路径。
如果上述问题的答案是否定的话。您可以释放-source=1.4,允许您在代码中使用泛型和其他Java5增强。但是,您仍然必须通过以下方法提供二进制兼容性:
-target=1.4 -bootclasspath=[path/to/1.4.jar]另一种选择是使用回纬器。
在重新阅读您的问题之后,我想补充一句,您必须掌握jdbc类文件的JDK1.4变体。否则,您将遇到您在问题中显示的编译器错误。
发布于 2011-09-05 12:22:42
除非您是JDBC供应商,否则像这样实现接口是不明智的。
考虑使用代理来维护跨JVM版本的兼容性。
迁移到代理的过程如下所示。考虑一下这个ResultSet实现:
public class ResultSetFoo implements ResultSet {
public String getString(int columnIndex) throws SQLException {
return "foobar";
}
// other Java 1.4 methods这将被更改,因此没有类实现ResultSet。
public class ResultBar {
public String getString(int columnIndex) throws SQLException {
return "foobar";
}
// other method signatures matching the 1.4 ResultSet, as before然后,您需要在运行时在这两种类型之间构建方法的映射(一种鸭子类型的原始形式:)
private static final Map RESULT_SET_DUCK = initResultSet();
private static Map initResultSet() {
Map map = new HashMap();
Method[] methods = ResultSet.class.getMethods();
for (int i = 0; i < methods.length; i++) {
try {
Method match =
ResultBar.class.getMethod(methods[i].getName(),
methods[i].getParameterTypes());
map.put(methods[i], match);
} catch (SecurityException e) {
throw new IllegalStateException(e);
} catch (NoSuchMethodException e) {
// OK; not supported in 1.4
}
}
return map;
}这允许您通过代理调用ResultBar类型:
/** Create a java.sql.ResultSet proxy */
public static ResultSet proxy(final ResultBar duck) {
class Handler implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Method proxiedMethod = (Method) RESULT_SET_DUCK.get(method);
if (proxiedMethod == null) {
throw new UnsupportedOperationException("TODO: method detail");
} else {
return invoke(proxiedMethod, duck, args);
}
}
private Object invoke(Method m, Object target, Object[] args)
throws Throwable {
try {
return m.invoke(target, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
}
return (ResultSet) Proxy.newProxyInstance(null, RSET, new Handler());
}这样的实现应该允许在将来的JVM中使用编译在一个JVM中的代码,即使添加了新的方法。现有的方法签名不太可能改变,因为让数据库供应商做一些工作是一回事,也是让所有API使用者改变的事情。
您可能需要更改类实例的创建方式。不能再直接使用构造函数:
ResultSet nonPortable = new ResultSetFoo();
//becomes...
ResultSet portable = proxy(new ResultBar());如果您已经雇用了工厂/生成器/等等模式,这一点很容易。
虽然反射在最新的JVM中相对便宜,但在旧版本中就不那么便宜了;这可能会对性能产生不利影响。
发布于 2011-09-05 12:38:18
如何向我的Java1.6javac指定我希望使用1.4 JAR而不是Java 6 JAR?
在胜利中。& *nix将通过指定bootclasspath选项来实现。有关更多详细信息,请参阅javac:交叉编译选项。
https://stackoverflow.com/questions/7307905
复制相似问题