更改构造函数参数类型会破坏另一个 jar 中的类
我在公共 jar 中有以下类:
public class Common
{
public Common(List list)
{
...
}
}
然后,我将构造函数参数从 List
更改为 Collection
,如下所示:
public class Common
{
public Common(Collection collection)
{
...
}
}
重建公共 jar 并运行系统会导致 < code>NoSuchMethodError 在任何依赖类中调用构造函数时,直到我重新编译该类。
我对导致此问题的原因有一些想法,比如构造函数如何绑定在依赖类的字节码中,但我不是 100% 确定。
请有人能解释一下这里发生的事情吗?
更新
我随后进行了快速测试并查看了字节码:
Compiled from "Client.java"
public class Client extends java.lang.Object{
public Client();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #2; //class ArrayList
3: dup
4: invokespecial #3; //Method java/util/ArrayList."<init>":()V
7: astore_1
8: new #4; //class Common
11: dup
12: aload_1
13: invokespecial #5; //Method Common."<init>":(Ljava/util/List;)V
16: pop
17: return
}
就像 Tom 所说,正如您在第 13 行中看到的那样,确切的构造函数是在编译时绑定的。
你每天学习新的东西 :-)
I have the following class in a common jar:
public class Common
{
public Common(List list)
{
...
}
}
I then change the constructor parameter from a List
to a Collection
as follows:
public class Common
{
public Common(Collection collection)
{
...
}
}
Rebuilding the common jar and running the system causes a NoSuchMethodError
in any dependent class when it invokes the constructor until I recompile that class.
I've got a few ideas what's causing this, along the lines of how the constructor is bound in the bytecode of the dependent class, but I'm not 100% sure.
Please can somebody shed some light onto what's going on here?
Update
I've subsequently done a quick test and taken a look at the bytecode:
Compiled from "Client.java"
public class Client extends java.lang.Object{
public Client();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #2; //class ArrayList
3: dup
4: invokespecial #3; //Method java/util/ArrayList."<init>":()V
7: astore_1
8: new #4; //class Common
11: dup
12: aload_1
13: invokespecial #5; //Method Common."<init>":(Ljava/util/List;)V
16: pop
17: return
}
Like Tom said, and as you can see on line 13, the exact constructor is bound at compile time.
You learn something new every day :-)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
javac 准确解析在编译时调用哪个方法或构造函数。 这不会在链接时发生。 由于构造函数签名已更改,链接步骤无法找到请求的方法,因此会引发错误。 您可以通过向构造函数提供来修复错误 - 一个构造函数采用
Collection
,另一个采用List
。 稍后可以添加采用Iterable
的构造函数。请注意,泛型类型不构成签名的一部分,因此可以更改这些类型,同时仍保持二进制兼容性。 参数和返回类型都构成方法签名的一部分(协变返回会导致创建合成桥方法)。
JLS中有一个不错的大节定义到底什么构成了二进制兼容的更改。
javac resolves exactly which method or constructor to call at compile time. This does not occur at link time. As the constructor signature has changed, the linking step cannot find the requested method and therefore throws an error. You can fix the error by providing to constructors - one which takes an
Collection
the otherList
. Later a constructor taking anIterable
could be added.Note, generic types do not form part of the signature, so those can be changed whilst still keeping binary compatibility. Both parameter and return types form part of the signature for methods (covariant returns cause synthetic bridge methods to be created).
There is a nice big section in the JLS defining exactly what constitutes binary compatible changes.
您是否导入了正确的 List 和 Collection 类? 即java.util.List和java.util.Collection?
Are you importing the correct List and Collection classes? i.e.
java.util.List
andjava.util.Collection
?我认为这可能是库版本的问题。 您确定在同一上下文中的其他地方没有另一个版本的公共库吗?
I think it could be a problem with the library version. Are you sure that there is not another version of the commons library somewhere else in the same context ?