欢迎大家来到IT世界,在知识的湖畔探索吧!
成也习惯,败也习惯
每个人都有自己的习惯,有早起的习惯、有助人为乐的习惯、有勤俭节约的习惯,当然这些习惯在大部分人眼里,我们称之为好习惯。当然还有一些坏习惯,比如爱熬夜、爱写bug、爱痴心妄想的习惯。
从编程这件事上来说,也有好习惯和坏习惯之分,最终产生的效果也是泾渭分明。昨天在博客园发表的文章《号称精通Java的你,是否真的名副其实》中提到了String和StringBuilder的区别的时候,下面就有网友评论到还是使用String的“+”
方便,写StringBuilder比String起码就多写了好几个字母,当然这可能是一句玩笑话,但也可能正是大部分人内心的真实想法。
就拿上面的例子来说,我们看这样一段代码
String result = "abc" + "def" + "g"; StringBuilder sb = new StringBuilder(); sb.append("abc").apped("def").append("g");
欢迎大家来到IT世界,在知识的湖畔探索吧!
从代码可以看出,通过“+”确实方便很多,一行代码就可以搞定,反观下面通过StringBuilder的方式,起码行数就比上面多。但是我要告诉你下面的这种方式在绝大多数的情况下要比上面好,你会怎么选,是仍然选择方便常见的String,还是下面稍显复杂的StringBuilder,如果你还是犹豫不决,请看下面这个例子。
欢迎大家来到IT世界,在知识的湖畔探索吧!public static void testString(){ long start = System.currentTimeMillis(); String resultStr = ""; int i = 0; for (int a = 0; a < 10000; a++) { resultStr += "abc" + "def" + "g" + i++; } System.out.println("using String:" + (System.currentTimeMillis() - start)); } public static void testStringBuilder() { StringBuilder stringBuilder = new StringBuilder(); long start = System.currentTimeMillis(); int i = 0; for (int a = 0; a < 10000; a++) { stringBuilder.append("abc").append("def").append("g").append(i++); } System.out.println("using StringBuilder:" + (System.currentTimeMillis() - start)); }
运行上面的两个方法,我们得到这样的结果
using String:2266 using StringBuilder:3
想必你会大吃一惊,使用String方式耗费的时间是2226毫秒,而StringBuilder方式只有3毫秒。
图省事的习惯可能让你在走向优秀和卓越的路上越走越偏,最终养成的是坏习惯,坏习惯可能让你看不到编程以及语言的美,让你抱怨懊恼,开始痛恨编程,所以就开始对编程更加敷衍了事,从而进入一个恶性循环。所以,成也习惯,败也习惯!
还有网友,在看完上篇《Java封神之路-拿下Byte》之后问我,这些东西都在哪里会用到。我想了想,抛开网友的问题,我觉得看源码有如下一些好处:
-
扫盲 有一些东西,你不看源码,或许就很难知道,比如Byte中的缓存数组,通过阅读代码,我们知道了缓存数组的作用,可以节省空间。
-
消除模棱两可的点 比如parseByte和valueOf到底有什么区别,应该用那种比较好,什么时候用什么方法
-
学习代码规范 看源码,我们可以学习大牛们是如何写出整洁漂亮的代码
除此以外,读源码的好处还有很多,下面我们就来看看阅读Integer的源码又收获了写什么。
Integer
Integer作为我们熟悉到不能再熟悉的包装类,我们来看看它还有那些隐藏属性。因为有些方法在Byte中已经说过,这里就不再强调了。
继承关系
IntegerCache缓存数组
欢迎大家来到IT世界,在知识的湖畔探索吧!private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} }
相比较Byte简单的从-128~127,这里的代码稍稍复杂点,复杂就在于这里缓存的上限是可以设置的,默认还是从-128到127。
关于这个缓存数据,有一点需要注意,看如下代码
Integer s1=100,s2=100; Integer c1=1000,c2=1000; System.out.println(s1==s2);//true System.out.println(c1==c2);//false
是的,你没看错,第一个返回为true,第二个为false。
按照道理来说,这两个应该都返回为false才对,因为使用了“==”
表示不仅仅要值相等,引用地址也要相等。解这个谜底的关键恰恰就是这个缓存数组,因为Integer会缓存-128~127之间的数值,也就是专门开辟一段空间存储这一范围的值,所以例子中的s1和s2都使用的缓存数组中的值,也就是同一引用地址,故而他们不仅值相等,引用地址也相等,所以返回为true。
Integer构造方法
我们熟知的Integer构造方法应该是这样的Integer val = new Integer(5);
,如果想要将一个String类型的数值转为Integer,我们可能会这样做
Integer val = 0; val = Integer.parseInt("5");
其实我们大可使用Integer val = new Integer("5")
这种方式一步到位。当然了,该构造函数内部也是使用了parseInt方法。
public Integer(String s) throws NumberFormatException { this.value = parseInt(s, 10); }
compare的三元表达式写法
因为Integer实现了Comparable接口,所以可以使用compareTo方法,我们看到Integer中的compareTo如下
public int compareTo(Integer anotherInteger) { return compare(this.value, anotherInteger.value); }
调用的compare方法如下
public static int compare(int x, int y) { return (x < y) ? -1 : ((x == y) ? 0 : 1); }
这是一个嵌套的三元表达式,是不是很简洁,这一行代码就相当于
int result = 0; if(x < y) { result = -1; } else if(x == y) { result = 0; } else { result = 1; }
toBinaryString toHexString toOctalString
我们有时候会用到将一个10进制的数值转为2进制、8进制或16进制,实际上Integer就为我们提供了这样的方法。
-
toBinaryString 以二进制(基数 2)无符号整数形式返回一个整数参数的字符串表示形式。
-
toOctalString 以八进制(基数 8)无符号整数形式返回一个整数参数的字符串表示形式。
-
toHexString 以十六进制的无符号整数形式返回一个整数参数的字符串表示形式。
巧用这些静态方法,可以让我们少些很多代码。
rotateLeft和rotateRight
这两个方法相当于是左位移和右位移的位运算。rotateLeft代码如下
public static int rotateLeft(int i, int distance) { return (i << distance) | (i >>> -distance); }
该方法的效果与“<<”是一样的。
下面通过举例看看各个方式的实现效果
private static void testInteger() { Integer val1 = new Integer("123"); System.out.println(val1); System.out.println("decode:" + Integer.decode("-123")); Integer val2 = new Integer(10); System.out.println("rotateLeft: " + Integer.rotateLeft(val2, 1)); System.out.println("<<: " + (val2 << 1)); System.out.println("rotateRight: " + Integer.rotateRight(val2, 1)); System.out.println(">>: " + (val2 >> 1)); System.out.println("toBinaryString: " + Integer.toBinaryString(val2)); System.out.println("toHexString: " + Integer.toHexString(val2)); System.out.println("toOctalString: " + Integer.toOctalString(val2)); System.out.println("valueOf" + Integer.valueOf(val2)); }
运行结果如下
123 decode:-123 rotateLeft: 20 <<: 20 rotateRight: 5 >>: 5 toBinaryString: 1010 toHexString: a toOctalString: 12 valueOf: 10
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/31569.html