`
qing_gee
  • 浏览: 118098 次
  • 性别: Icon_minigender_1
  • 来自: 河南
社区版块
存档分类
最新评论

从《Java特种兵》中感知老A的世界

阅读更多

前言:偶然间,从微信平台的博文视点中读到了一篇“练武不练功,到老一场空--一个string,见证下功底”的文章,细细致致的阅读完一个string的比较程序后,瞬间让我有些自惭形秽,本文好好得给我上了一课,后来发现本文摘自《Java特种兵·上册》,于是抓紧时间来ITeye上拜读一下试读章节。

 

一、一个扎马,让我打回原形    

private static void test1() {
String a = "a" + "b" + 1;
String b = "ab1";
System.out.println(a == b);
}

       看似简单的一个string字符串比较,我似乎都没有多想,从以前读书的“断章取义”的经验中,String是地址引用类型,通过“==”进行比较的时候就是false,如果要进行两个字符串的比较,就要用“equals”。我甚至还用Eclipse敲了一下这串代码,代码输出true,这时才意识到,自己对于这些概念都是一知半解,很多东西自己都是“一瓶子不满,半瓶子晃荡”,没有很认真的去研究,都只是停留在万恶的“差不多”上。

       接着看完胖哥依次讲解的hashCode、StringBuilder,感觉自己就是孙悟空棒下的小妖,原形毕露,看来自己真的需要好好去钻一些东西了,而不是只是停留在这些空头上的、甚至完全没有自己体系的印象上。

        在一次项目开发中,通过socket对json转换的对象字符串进行两个服务器之间的传递,然而不明所以,A服务器不断向B服务器write字节的时候,虽然都已经写完,但是在B服务器端经常发现迟钝的现象,经过很长时间调查,发现代码中在对一串字符串处理上使用了+进行连接,这个花费了大量的内存,因为这个字符串很庞大,虽然当时就知道要使用StringBuilder进行处理,因为使用+连接的话,会不断创建新的字符串对象,而StringBuilder是不会的。经过胖哥对StringBuilder和String的讲解后,让我对两者之间的利害更加清晰明了,不是说append就一定比+操作好,而是使用+操作string,其实在编译时也会在内部转换为StringBuilder的append操作,如果这个+操作太过频繁的话,就会导致大量的GC。如果直接使用StringBuilder来进行append操作时,在每次append时,只会进行两倍的扩容,而不再像+操作在每次执行时都将申请一个更大内存的StringBuilder对象来进行操作。如果我在修改我提到的那个bug之前看到胖哥的这样明了的讲解,我当时该有多幸福。

 

二、简单的数字游戏,让我明白原来long这么大

       以前在做程序的时候,虽然明白number类型的数据,能用小的类型就不要使用大的数据类型,因为会浪费很多存储空间,但是却并不知道,原来long是这么大的,按照胖哥所说的long“如果存放毫秒值,则可以存放2.92 亿年,微妙值可以存放29.2 万年,纳秒值可以存放292 年的数据。换句话说,一个表的ID,即使加上跳跃每秒有10E9 个ID 自动增长,也可以增加292 年的数据不重复”。

 

三、简单的功底补充,让我恍然大悟

        在没有看到胖哥这段代码

public static void main(String []args) {
Integer a = 1;
Integer b = 1;
Integer c = 200;
Integer d = 200;
System.out.println(a == b);
System.out.println(c == d);
}

 时,我始终没有明白为什么不能直接使用一个Integer对象和int值进行==比较操作,这次,胖哥告诉了我真理,而我也知道了,虽然在编译阶段,如果将一个int类型赋值给一个Integer对象时,会使用valueOf方法,如果将一个Integer对象赋值给一个int类型时,会使用intValue方法,但是我并不知道

源代码 写道
public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}

 Java底部在处理0-127的valueOf时,会从IntegerCache的下标中获取,而128以上的数,则会返回一个新的Integer对象。

       在以前,我的项目中出现了这样一个bug,是拿了一个int和Integer对象进行==比较,不明白为什么1、2、3、4进行比较的时候就返回true,为啥240进行比较的时候就返回了false呢,当时并没有去深究看看valueOf的源码程序,而就是简单的改成了两个Integer类型的compare比较,或者进行==比较的时候,用Integer的intValue进行比较。

 

四、面对技术,如何成为一名老A

       胖哥在试读章节的最后一部分,苦口婆心的说了一些如何成为技术老A要面对的做法,这些都对我有着深深的感悟,我以前总认为自己已经正式开发Java 4年了,虽然中间很长一段时间在做flex,但是语言是相通的,我应该已经具备了坚实的Java开发基础,但是看完本章节后,我离一名老A的差距远不止那么一点点。像胖哥所说的,我面对逆境、迎难而上,多看、多练、多思考、多总结,积累自己在Java开发领域的经验,在未来成为王牌。

 

总结:读完胖哥的试读章节,让我醍醐灌顶,虽然不能说看完章节后自己自卑了,但是至少自己还有很多知识需要学习,需要进步,不积跬步,无以成千里,正视自己,为成为一个Java的老A而奋斗!

4
2
分享到:
评论
9 楼 qing_gee 2014-10-08  
xieyuNL 写道
qing_gee 写道
xieyuNL 写道
多谢兄台的认可(我是作者本人),希望本书能够给予你一些帮助!有些内容也不仅仅局限于本书之中,更加希望大家探究问题的习惯与方法。就如1楼提到的这个问题,其实也是一个不错的案例,因为案例举证不完,所以我才这样写。

至于1楼大侠的题目,主要是“try、catch、finally”在编译时Java的对本地变量的处理机制上,通过第3章提到的虚指令中可以看出这些板块会针对方法分配的frame中,对同一个本地变量,如果出现catch、finally会产生一个单独slot区,或者说是本地变量在栈空间的一份拷贝,与本书中提到的i++的例子类似,也是编译时的一种机制,因此拷贝空间的引用改变是不会影响原空间的内容,但拷贝的引用对象内容发生改变肯定是会影响的,答案我就不再提及了,因为这个问题的答案只是帮助我们参透一些Java内在机制的兴趣点,利用我们所学会的基本方法,就可以让自己所编写的代码逐步清晰起来,尤其是在编写一些比较复杂的中间层或基础组件的时候,这些尤为重要。

至于String拼接的那个例子,第一章的后面几个例子中有类似的,当中的解释也是一致的,答案也是也是一致的,还有更诡异的结果的也有,我在这里不再多说了。

另外,StringBuilder你也应该看出它有浪费空间之处,因为扩容的时候,原先的char[]空间是被当做垃圾了,其实有很多时候,如果我们仅仅是append最后来toString,其实可以有更加节约空间的方法,当然这个是小兴趣点,你未必用得到,有人曾经在这个上面做过改造。总之我们只是在探究问题的方法,进而让我们自己对自己所编写的代码很清楚它在计算机中如何运行,第1章只是一个浅显小有趣的开始,后续会有相对深入的探讨,要说和别人的区别,可能最大的就是基于点带思考和理论的方法。

xieyuNL 写道
qing_gee 写道
xieyuNL 写道
多谢兄台的认可(我是作者本人),希望本书能够给予你一些帮助!有些内容也不仅仅局限于本书之中,更加希望大家探究问题的习惯与方法。就如1楼提到的这个问题,其实也是一个不错的案例,因为案例举证不完,所以我才这样写。

至于1楼大侠的题目,主要是“try、catch、finally”在编译时Java的对本地变量的处理机制上,通过第3章提到的虚指令中可以看出这些板块会针对方法分配的frame中,对同一个本地变量,如果出现catch、finally会产生一个单独slot区,或者说是本地变量在栈空间的一份拷贝,与本书中提到的i++的例子类似,也是编译时的一种机制,因此拷贝空间的引用改变是不会影响原空间的内容,但拷贝的引用对象内容发生改变肯定是会影响的,答案我就不再提及了,因为这个问题的答案只是帮助我们参透一些Java内在机制的兴趣点,利用我们所学会的基本方法,就可以让自己所编写的代码逐步清晰起来,尤其是在编写一些比较复杂的中间层或基础组件的时候,这些尤为重要。

至于String拼接的那个例子,第一章的后面几个例子中有类似的,当中的解释也是一致的,答案也是也是一致的,还有更诡异的结果的也有,我在这里不再多说了。

另外,StringBuilder你也应该看出它有浪费空间之处,因为扩容的时候,原先的char[]空间是被当做垃圾了,其实有很多时候,如果我们仅仅是append最后来toString,其实可以有更加节约空间的方法,当然这个是小兴趣点,你未必用得到,有人曾经在这个上面做过改造。总之我们只是在探究问题的方法,进而让我们自己对自己所编写的代码很清楚它在计算机中如何运行,第1章只是一个浅显小有趣的开始,后续会有相对深入的探讨,要说和别人的区别,可能最大的就是基于点带思考和理论的方法。


非常感谢!我认认真真看完你花那么长时间去回复别人的问题的时候,都觉得敬意油然而生。同时又好好的请教了一次领导,也在此记录好好记录一下:
1.对于System.out.println(getA());编译器在编译的时候getA()方法会创建4个空间,分别是"1""2""3""形参",当执行到return a时,返回给形参getA()的地址引用为1的地址,当执行完final的时候,a的地址引用变成了3,但是不影响形参的值。

2.对于System.out.println(getStudent().name);执行时,getStudent方法依然返回的是a对象的地址引用,但是final执行完时,会把a对象的属性name的地址引用更新为3,所以会输出3

不知道是否表达清楚了,但是觉得兄台的书籍中列出的不论string还是stringbuilder真的让我非常受教,希望以后多多指导。



恩,差不多是那个意思的,Java里面听“形参”这个概念比较少,我也不是很确定是否严谨,一般我们说本地变量,通俗点讲就是方法内的局部变量。

它在方法调用时被分配,因为编译阶段就能够决定这个方法需要用多大的本地变量区域(当然对于对象本地变量中只有引用而已),这个在书的后面有提到,这个问题可通过后续第3章中所提到的javap指令去验证(书中主要是在第三章专门讲解JVM的时候回顾第一章,然后验证结论,因为第一章讲解的时候是因为结论所有有另一个结论,第三章是更往里面挖了一层),我之所以提到不要纠结结论就是如此,因为这个是编译器的一个机制,如果编译器改变了处理方式,可能会得出不同的结果,但我们懂得了一种方法去挖掘它的本质。

就这个问题本身而言,通过验证后可以看到某个版本的JDK,它编译后内存的slot值是如何拷贝的一个过程,进而保证一些东西。如i++,如果运算中它有一个栈顶的拷贝,和本地变量的拷贝还有点区别,但道理都差不多,就是为了保证一些东西而存在的。



非常感谢!我认认真真看完你花那么长时间去回复别人的问题的时候,都觉得敬意油然而生。同时又好好的请教了一次领导,也在此记录好好记录一下:
1.对于System.out.println(getA());编译器在编译的时候getA()方法会创建4个空间,分别是"1""2""3""形参",当执行到return a时,返回给形参getA()的地址引用为1的地址,当执行完final的时候,a的地址引用变成了3,但是不影响形参的值。

2.对于System.out.println(getStudent().name);执行时,getStudent方法依然返回的是a对象的地址引用,但是final执行完时,会把a对象的属性name的地址引用更新为3,所以会输出3

不知道是否表达清楚了,但是觉得兄台的书籍中列出的不论string还是stringbuilder真的让我非常受教,希望以后多多指导。



恩,差不多是那个意思的,Java里面听“形参”这个概念比较少,我也不是很确定是否严谨,一般我们说本地变量,通俗点讲就是方法内的局部变量。

它在方法调用时被分配,因为编译阶段就能够决定这个方法需要用多大的本地变量区域(当然对于对象本地变量中只有引用而已),这个在书的后面有提到,这个问题可通过后续第3章中所提到的javap指令去验证(书中主要是在第三章专门讲解JVM的时候回顾第一章,然后验证结论,因为第一章讲解的时候是因为结论所有有另一个结论,第三章是更往里面挖了一层),我之所以提到不要纠结结论就是如此,因为这个是编译器的一个机制,如果编译器改变了处理方式,可能会得出不同的结果,但我们懂得了一种方法去挖掘它的本质。

就这个问题本身而言,通过验证后可以看到某个版本的JDK,它编译后内存的slot值是如何拷贝的一个过程,进而保证一些东西。如i++,如果运算中它有一个栈顶的拷贝,和本地变量的拷贝还有点区别,但道理都差不多,就是为了保证一些东西而存在的。
是,这些虽然是看似简单的问题,让我有了很多提高!希望以后有能力和你成为好的朋友,加油
8 楼 xieyuNL 2014-10-08  
qing_gee 写道
xieyuNL 写道
多谢兄台的认可(我是作者本人),希望本书能够给予你一些帮助!有些内容也不仅仅局限于本书之中,更加希望大家探究问题的习惯与方法。就如1楼提到的这个问题,其实也是一个不错的案例,因为案例举证不完,所以我才这样写。

至于1楼大侠的题目,主要是“try、catch、finally”在编译时Java的对本地变量的处理机制上,通过第3章提到的虚指令中可以看出这些板块会针对方法分配的frame中,对同一个本地变量,如果出现catch、finally会产生一个单独slot区,或者说是本地变量在栈空间的一份拷贝,与本书中提到的i++的例子类似,也是编译时的一种机制,因此拷贝空间的引用改变是不会影响原空间的内容,但拷贝的引用对象内容发生改变肯定是会影响的,答案我就不再提及了,因为这个问题的答案只是帮助我们参透一些Java内在机制的兴趣点,利用我们所学会的基本方法,就可以让自己所编写的代码逐步清晰起来,尤其是在编写一些比较复杂的中间层或基础组件的时候,这些尤为重要。

至于String拼接的那个例子,第一章的后面几个例子中有类似的,当中的解释也是一致的,答案也是也是一致的,还有更诡异的结果的也有,我在这里不再多说了。

另外,StringBuilder你也应该看出它有浪费空间之处,因为扩容的时候,原先的char[]空间是被当做垃圾了,其实有很多时候,如果我们仅仅是append最后来toString,其实可以有更加节约空间的方法,当然这个是小兴趣点,你未必用得到,有人曾经在这个上面做过改造。总之我们只是在探究问题的方法,进而让我们自己对自己所编写的代码很清楚它在计算机中如何运行,第1章只是一个浅显小有趣的开始,后续会有相对深入的探讨,要说和别人的区别,可能最大的就是基于点带思考和理论的方法。


非常感谢!我认认真真看完你花那么长时间去回复别人的问题的时候,都觉得敬意油然而生。同时又好好的请教了一次领导,也在此记录好好记录一下:
1.对于System.out.println(getA());编译器在编译的时候getA()方法会创建4个空间,分别是"1""2""3""形参",当执行到return a时,返回给形参getA()的地址引用为1的地址,当执行完final的时候,a的地址引用变成了3,但是不影响形参的值。

2.对于System.out.println(getStudent().name);执行时,getStudent方法依然返回的是a对象的地址引用,但是final执行完时,会把a对象的属性name的地址引用更新为3,所以会输出3

不知道是否表达清楚了,但是觉得兄台的书籍中列出的不论string还是stringbuilder真的让我非常受教,希望以后多多指导。



恩,差不多是那个意思的,Java里面听“形参”这个概念比较少,我也不是很确定是否严谨,一般我们说本地变量,通俗点讲就是方法内的局部变量。

它在方法调用时被分配,因为编译阶段就能够决定这个方法需要用多大的本地变量区域(当然对于对象本地变量中只有引用而已),这个在书的后面有提到,这个问题可通过后续第3章中所提到的javap指令去验证(书中主要是在第三章专门讲解JVM的时候回顾第一章,然后验证结论,因为第一章讲解的时候是因为结论所有有另一个结论,第三章是更往里面挖了一层),我之所以提到不要纠结结论就是如此,因为这个是编译器的一个机制,如果编译器改变了处理方式,可能会得出不同的结果,但我们懂得了一种方法去挖掘它的本质。

就这个问题本身而言,通过验证后可以看到某个版本的JDK,它编译后内存的slot值是如何拷贝的一个过程,进而保证一些东西。如i++,如果运算中它有一个栈顶的拷贝,和本地变量的拷贝还有点区别,但道理都差不多,就是为了保证一些东西而存在的。
7 楼 qing_gee 2014-10-08  
xieyuNL 写道
多谢兄台的认可(我是作者本人),希望本书能够给予你一些帮助!有些内容也不仅仅局限于本书之中,更加希望大家探究问题的习惯与方法。就如1楼提到的这个问题,其实也是一个不错的案例,因为案例举证不完,所以我才这样写。

至于1楼大侠的题目,主要是“try、catch、finally”在编译时Java的对本地变量的处理机制上,通过第3章提到的虚指令中可以看出这些板块会针对方法分配的frame中,对同一个本地变量,如果出现catch、finally会产生一个单独slot区,或者说是本地变量在栈空间的一份拷贝,与本书中提到的i++的例子类似,也是编译时的一种机制,因此拷贝空间的引用改变是不会影响原空间的内容,但拷贝的引用对象内容发生改变肯定是会影响的,答案我就不再提及了,因为这个问题的答案只是帮助我们参透一些Java内在机制的兴趣点,利用我们所学会的基本方法,就可以让自己所编写的代码逐步清晰起来,尤其是在编写一些比较复杂的中间层或基础组件的时候,这些尤为重要。

至于String拼接的那个例子,第一章的后面几个例子中有类似的,当中的解释也是一致的,答案也是也是一致的,还有更诡异的结果的也有,我在这里不再多说了。

另外,StringBuilder你也应该看出它有浪费空间之处,因为扩容的时候,原先的char[]空间是被当做垃圾了,其实有很多时候,如果我们仅仅是append最后来toString,其实可以有更加节约空间的方法,当然这个是小兴趣点,你未必用得到,有人曾经在这个上面做过改造。总之我们只是在探究问题的方法,进而让我们自己对自己所编写的代码很清楚它在计算机中如何运行,第1章只是一个浅显小有趣的开始,后续会有相对深入的探讨,要说和别人的区别,可能最大的就是基于点带思考和理论的方法。


非常感谢!我认认真真看完你花那么长时间去回复别人的问题的时候,都觉得敬意油然而生。同时又好好的请教了一次领导,也在此记录好好记录一下:
1.对于System.out.println(getA());编译器在编译的时候getA()方法会创建4个空间,分别是"1""2""3""形参",当执行到return a时,返回给形参getA()的地址引用为1的地址,当执行完final的时候,a的地址引用变成了3,但是不影响形参的值。

2.对于System.out.println(getStudent().name);执行时,getStudent方法依然返回的是a对象的地址引用,但是final执行完时,会把a对象的属性name的地址引用更新为3,所以会输出3

不知道是否表达清楚了,但是觉得兄台的书籍中列出的不论string还是stringbuilder真的让我非常受教,希望以后多多指导。
6 楼 xieyuNL 2014-10-08  
多谢兄台的认可(我是作者本人),希望本书能够给予你一些帮助!有些内容也不仅仅局限于本书之中,更加希望大家探究问题的习惯与方法。就如1楼提到的这个问题,其实也是一个不错的案例,因为案例举证不完,所以我才这样写。

至于1楼大侠的题目,主要是“try、catch、finally”在编译时Java的对本地变量的处理机制上,通过第3章提到的虚指令中可以看出这些板块会针对方法分配的frame中,对同一个本地变量,如果出现catch、finally会产生一个单独slot区,或者说是本地变量在栈空间的一份拷贝,与本书中提到的i++的例子类似,也是编译时的一种机制,因此拷贝空间的引用改变是不会影响原空间的内容,但拷贝的引用对象内容发生改变肯定是会影响的,答案我就不再提及了,因为这个问题的答案只是帮助我们参透一些Java内在机制的兴趣点,利用我们所学会的基本方法,就可以让自己所编写的代码逐步清晰起来,尤其是在编写一些比较复杂的中间层或基础组件的时候,这些尤为重要。

至于String拼接的那个例子,第一章的后面几个例子中有类似的,当中的解释也是一致的,答案也是也是一致的,还有更诡异的结果的也有,我在这里不再多说了。

另外,StringBuilder你也应该看出它有浪费空间之处,因为扩容的时候,原先的char[]空间是被当做垃圾了,其实有很多时候,如果我们仅仅是append最后来toString,其实可以有更加节约空间的方法,当然这个是小兴趣点,你未必用得到,有人曾经在这个上面做过改造。总之我们只是在探究问题的方法,进而让我们自己对自己所编写的代码很清楚它在计算机中如何运行,第1章只是一个浅显小有趣的开始,后续会有相对深入的探讨,要说和别人的区别,可能最大的就是基于点带思考和理论的方法。
5 楼 qing_gee 2014-10-08  
rrsy23 写道
static Integer getB() {

Integer a = new Integer(1);
try {
return a;
} catch (Exception e) {
a =  new Integer(2);
return a;
} finally {
System.out.println("hi");
a =  new Integer(3);

}

}

如果加上这个 估计 更值得思考了



朋友的题出得好,我解答不出来为什么,还望朋友能够指点明白。
4 楼 qing_gee 2014-10-08  
haohao-xuexi02 写道
扎实的基本功多么重要……

是啊
3 楼 haohao-xuexi02 2014-10-07  
扎实的基本功多么重要……
2 楼 rrsy23 2014-10-06  
static Integer getB() {

Integer a = new Integer(1);
try {
return a;
} catch (Exception e) {
a =  new Integer(2);
return a;
} finally {
System.out.println("hi");
a =  new Integer(3);

}

}

如果加上这个 估计 更值得思考了
1 楼 rrsy23 2014-10-06  
String b="abc";
String c=b+b;
String d="abcabc";
System.out.println(c==d);

又如何?

相信老A你就又幼稚

看看 Java规范  JVM等 你就 豁然阚浪

大学的 计算机原理  os  编译器 联系起来java 你才 是小A

个人认为 java世界没有 老A 只有思考者  API使用者


下面代码有如何??
package com.bobo;

public class Test {

/**
* QQ:15221860
* @param args
*/
public static void main(String[] args) {

System.out.println(getA());

System.out.println(getStudent().name);

}

static String getA() {

String a = "1";
try {
return a;
} catch (Exception e) {
a = "2";
return a;
} finally {
System.out.println("hi");
a = "3";
}

}

static Student getStudent() {

Student a = new Student();
a.name = "1";
try {
return a;
} catch (Exception e) {
a.name = "2";
return a;
} finally {
System.out.println("hi");
a.name = "3";

}

}

static class Student {
String name = "";

}

}


这些只是我8年轻的思考与联系


希望大家学会思考 不是想象谁

书只是参考也许也有错

自我设疑 实验  寻找答案

相关推荐

Global site tag (gtag.js) - Google Analytics