int修改为long的悲剧
来源:互联网 发布:淘宝网店策划书 编辑:程序博客网 时间:2024/04/30 11:56
一.背景
应用app依赖consumer.jar,provider.jar,而consumer.jar依赖provider.jar,并且consumer.jar中的Client.java通过接口User.java调用provider.jar的提供的用户信息查询服务(可以是远程服务或本地服务),如果接口的参数由int变为long,而consumer.jar代码没有重新编译,将会出现java.lang.NoSuchMethodError,如果应用程序只做Exception的捕捉,意味整个请求可能就crash了。
二.问题还原
需求:Client调用User接口,查询用户信息,并打印到控制台
服务消费者:consumer.jar用Client.java模拟,Client.java依赖User.java
服务提供者:provider.jar用User.java和UserImpl.java模拟
1.消费者Client.java
public class Client { public static void main(String[] args) { User user = new UserImpl(); user.find(Integer.valueof("123")); }}
2.提供者接口User.java
public interface User { void find(long userId);}
3.提供者实现UserImpl.java
public class UserImpl implements User { @Override public void find(long userId) { System.out.println("mr.jiang"); }}
如果接口User将参数类型int变成long,并重新编译打包,提供给应用app使用,而consumer.jar没有重新进行编译,会出现java.lang.NoSuchMethodError:错误,具体分析如下
1.未变更前find(int userId)
编译:javac Client.java ,javac UserImpl.java javac User.java
Client字节码:javap -p -v Client
public static void main(java.lang.String[]); Code: Stack=2, Locals=2, Args_size=1 0:new#2; //class UserImpl 3:dup 4:invokespecial#3; //Method UserImpl."<init>":()V 7:astore_1 8:aload_1 9:bipush123 11:invokeinterface#4, 2; //InterfaceMethod User.find:(I)V 这里为I,也就是int(映射关系见最后的截图) 16:return LineNumberTable: line 4: 0 line 5: 8 line 6: 16
User字节码:javap -p -v User
public interface User SourceFile: "User.java" minor version: 0 major version: 50 Constant pool:const #1 = class#7;// Userconst #2 = class#8;// java/lang/Objectconst #3 = Ascizfind;const #4 = Asciz(I)V;const #5 = AscizSourceFile;const #6 = AscizUser.java;const #7 = AscizUser;const #8 = Ascizjava/lang/Object;{public abstract void find(int);}
2.find(int userId)改成find(long userId)
find(int userId)改成find(long userId),然后javac User.java ,javac UserImpl.java,不编译Client.javaClient字节码:javap -p -v Client
public static void main(java.lang.String[]); Code: Stack=2, Locals=2, Args_size=1 0:new#2; //class UserImpl 3:dup 4:invokespecial#3; //Method UserImpl."<init>":()V 7:astore_1 8:aload_1 9:bipush123 11:invokeinterface#4, 2; //InterfaceMethod User.find:(I)V 这里还是I,此时如果运行,则出问题 16:return LineNumberTable: line 4: 0 line 5: 8 line 6: 16
User字节码:javap -p -v User
Compiled from "User.java"public interface User SourceFile: "User.java" minor version: 0 major version: 50 Constant pool:const #1 = class#7;// Userconst #2 = class#8;// java/lang/Objectconst #3 = Ascizfind;const #4 = Asciz(J)V;const #5 = AscizSourceFile;const #6 = AscizUser.java;const #7 = AscizUser;const #8 = Ascizjava/lang/Object;{public abstract void find(long);}
运行 java Client 出现error
Exception in thread "main" java.lang.NoSuchMethodError: User.find(I)Vat Client.main(Client.java:5)
3.重新编译Client.java
编译:javac Client
Client字节码:javap -p -c Client
public static void main(java.lang.String[]); Code: Stack=3, Locals=2, Args_size=1 0:new#2; //class UserImpl 3:dup 4:invokespecial#3; //Method UserImpl."<init>":()V 7:astore_1 8:aload_1 9:ldc2_w#4; //long 123l 12:invokeinterface#6, 3; //InterfaceMethod User.find:(J)V ==>虽然代码中是123,但是这里“隐式”转成了J,就是long,运行正常 17:return LineNumberTable: line 4: 0 line 5: 8 line 6: 17
运行
java Client控制台输出结果:mr.jiang
三.建议
虽说int,long能够进行装箱和拆箱,但是通过jar包依赖场景下,被依赖方的修改,必须通知依赖方进行编译,打包,发布,否则出现问题是error级别的。
附图:
0 0
- int修改为long的悲剧
- int转化为long
- 关于int、short int、long int、long long 的区别
- int ,long , long long类型的范围
- int ,long , long long类型的范围
- int ,long , long long类型的范围
- int ,long , long long类型的范围
- int 、long 、long long 的表示范围
- int ,long , long long类型的范围
- int,long,long long,__int64的范围
- INT ,LONG , LONG LONG类型的范围
- int ,long , long long类型的范围
- int ,long , long long类型的范围
- int ,long,long long 的范围
- int ,long , long long类型的范围
- int、long、long long的范围
- int ,long , long long的最大最小值
- int ,long , long long类型的范围
- 邀请 The Invitation
- eoe:抽像类DatabaseColumn及其实现类
- Oracle_Day2集合运算
- QT图形变换技巧
- 防止jsp数据请求重复提交
- int修改为long的悲剧
- MySQL 加锁处理分析
- lua实现汉诺塔
- wamp的图标是黄色的一种解决方案
- 关于label.opition控件求助
- AES加密解密,Winphone8与Java互通
- 自己写的一段代码-线程以及EVENT
- ‘dict’ object has no attribute 'has_key'解决办法
- CodeIgniter調用jquery的ajax