您的位置 首页 java

Java封神之路-Integer还有哪些你不知道的隐藏属性

成也习惯,败也习惯

每个人都有自己的习惯,有早起的习惯、有助人为乐的习惯、有勤俭节约的习惯,当然这些习惯在大部分人眼里,我们称之为好习惯。当然还有一些坏习惯,比如爱熬夜、爱写bug、爱痴心妄想的习惯。

从编程这件事上来说,也有好习惯和坏习惯之分,最终产生的效果也是泾渭分明。昨天在博客园发表的文章《号称精通 Java 的你,是否真的名副其实》中提到了String和StringBuilder的区别的时候,下面就有网友评论到还是使用String的“+”
方便,写StringBuilder比String起码就多写了好几个字母,当然这可能是一句玩笑话,但也可能正是大部分人内心的真实想法。
就拿上面的例子来说,我们看这样一段代码

String result = "abc" + "def" + "g";

StringBuilder sb = new StringBuilder();
sb. append ("abc").apped("def").append("g"); 

从代码可以看出,通过“+”确实方便很多,一行代码就可以搞定,反观下面通过StringBuilder的方式,起码行数就比上面多。但是我要告诉你下面的这种方式在绝大多数的情况下要比上面好,你会怎么选,是仍然选择方便常见的String,还是下面稍显复杂的StringBuilder,如果你还是犹豫不决,请看下面这个例子。

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缓存数组

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 

文章来源:智云一二三科技

文章标题:Java封神之路-Integer还有哪些你不知道的隐藏属性

文章地址:https://www.zhihuclub.com/191834.shtml

关于作者: 智云科技

热门文章

网站地图