2018年4月24日
难忘的一天,因为“装箱和拆箱”基础遗忘了,导致Bug分析出现延误(足足花了一个小时···)特地在此做个总结,坚决避免重蹈覆辙!!
1. 经历:
【1】前端给了个Bug,说我的这个接口没有返回任何的数据;我屁颠屁颠去看现场,果真没数据;确认过现场后,屁颠屁颠回到座位,开始自我剖析。。。
【2】为什么会没有返回值呢?我首先想到了以下3个情况:
1)前端问题:请求超时或者别的情况,导致后端接收不到数据,后面的操作也自然不会进行;
2)后端问题:后端接收到数据,后续的逻辑处理出错;
3)数据库问题:数据库get数据出错,进而接口发送的也会出问题;
后面调试之后,排除了1和3,看来还是代码出了问题啊(我内心千万个草泥马··)
【3】看下原来的代码:
public PublishProto.Builder sendPublishMsg(Integer publishType,GamePlayer gamePlayer) {
System.out.println("** 开始发送公布(活动/广告)!");
PublishProto.Builder publishBuilder = PublishProto.newBuilder(); //输出数据序列化
PublishInfoListProto.Builder builder = PublishInfoListProto.newBuilder();
ArrayList<PublishInfo> publishList = publishRepo.getPublicInfoList().getPublishInfoList();//根据key取出redis数据,转换为可迭代数据结构
ArrayList<PublishInfo> sortList = new ArrayList<PublishInfo>(); //类型一致的数据列表
for(PublishInfo publishInfo : publishList){
if(publishInfo.getType() == publishType){ //这里是重点,因为判断为false,导致发送的数组没有值增添
sortList.add(publishInfo);
}
}
publishBuilder.setPublishType(publishType);
publishBuilder.setPublishInfo(builder);
System.out.println("******** 结束发送公布(活动/广告) *********!");
return publishBuilder;
}
【4】为什么 publishInfo.getType() == publishType 会是false呢??
答:因为两者都是Integer 类型的数据,这是装箱后的对象,而 == 在这里的使用将会比较两个对象在内存的地址,毫无疑问,这是不一样的。所以,导致了false。
2. 深入剖析
【1】什么是装箱?什么是拆箱?
答:1) 装箱:将基本类型转换为包装类型;拆箱:将包装类型转换为基本类型。
2)说道自动装箱和拆箱,首先我们需要知道基本数据类型包装类。
java提供了四类八种基本数据类型,但是有些需求,靠基本数据类型无法满足我们的需求,或者是不方便。例如做一些进制转换,获取int数据类型的取值范围等等。
3)我们知道,类的优点在于,它可以定义成员变量、成员方法,提供丰富便利的功能。因此Java在JDK1.0的时候就设计了基本数据类型的包装类。
【2】基本类型和包装类的联系?
【3】拆箱和装箱的好处是什么?
答:下面有两个例子
例1:将100这个十进制数,分别转换为二进制,八进制,十六进制。
int x = 100; "2进制:"+Integer.toBinaryString(x); //2进制:1100100 "8进制:"+Integer.toOctalString(x); //8进制:144 "16进制:"+Integer.toHexString(x); //16进制:64
例2:判断一个数据是否在int数据范围内
int x = 100000; "int min=" + Integer.MIN_VALUE; //int min=-2147483648 "int max=" + Integer.MAX_VALUE; //int max=2147483647 (x >= Integer.MIN_VALUE && x <= Integer.MAX_VALUE); //true
体会到了基本数据类型包装成对象的好处之后,我们再来看自动装箱和自动拆箱。
【4】自动拆箱和装箱是什么?
答:自动装箱:把基本数据类型转换为包装类类型;自动拆箱:把包装类类型转换为基本数据类型。
【5】实例解释
新建两个java文件:
package test3; public class test2{ public static void main(String str[]){ /** * 关键字 : * new 自动装箱 自动拆箱 * -128~127 * */ String s = "hello"; // 静态区放入 字符串常量对象hello , s 指向 它 String t = "hello"; // 静态区已有hello 则引用类型t 指向 静态区的hello //不管静态区有没有hello 在堆中创建对象 h指向创建的对象 如果静态区有hello 则无需再在静态区中创建对象 String h = new String("hello"); System.out.println("s==t: " + (s==t)); System.out.println("h==t: " + (h==t)); System.out.println("s.equals(t): " + (s.equals(t))); System.out.println("s.equals(h): " + (s.equals(h))); Integer i1 = 12; // 存入缓存 Integer i2 = new Integer(12); // 不管有没有都会创建对象 Integer i3 = 12; // 12 在[-128,127] 直接从缓存中去取 Integer i4 = i2; // 所☞引用相同 Integer i5 = 128; // 128 不再[-128,127]之间 自动装箱成对象 Integer i6 = 128; int i7 = i6; // 自动拆箱成基本数据类型 int i8 = 128; System.out.println("i1==i2: " + (i1==i2)); System.out.println("i1==i3: " + (i1==i3)); System.out.println("i1==i4: " + (i1==i4)); System.out.println("i2==i4: " + (i2==i4)); System.out.println("i3==i2: " + (i3==i2)); System.out.println("i5==i6: " + (i5==i6)); System.out.println("i7==i6: " + (i7==i6)); System.out.println("i8==i6: " + (i8==i6));//自动拆箱 A a = new A(1,3); A b = new A(1,2); A c = a; System.out.println("a.equals(b) " + a.equals(b)); System.out.println("a.equals(c) " + a.equals(c)); System.out.println("b.equals(c) " + b.equals(c)); System.out.println("Object a==b: " + (a==b)); System.out.println("Object a==c: " + (a==c)); System.out.println("Object a==c: " + (b==c)); } }
package test3; class A{ private int a = 0; private int b = 0; public A(int a ,int b) { this.a = a; this.b = b; } public void fun(){ a++; b++; System.out.println(a+" "+b); } }
打印输出:
s==t: true h==t: false s.equals(t): true s.equals(h): true i1==i2: false i1==i3: true i1==i4: false i2==i4: true i3==i2: false i5==i6: false i7==i6: true i8==i6: true a.equals(b) false a.equals(c) true b.equals(c) false Object a==b: false Object a==c: true Object a==c: false