Integer类
将基本数据类型包装成类对象
Integer a = new Integer(10);
Integer b = Integer.valueOf(12);
将包装类对象转换成基本数据类型
int c = b.intValue();
double d = b.doubleValue();
将字符串转换成包装类对象
Integer e = new Integer("9999");
Integer f = Integer.parseInt("55555");
将包装类对象转换成字符串
String str=Integer.toString(100);
常见的常量
System.out.println("Integer里最大的常量:"+Integer.MAX_VALUE);
System.out.println("Integer里最小的常量:"+Integer.MIN_VALUE);
自动装箱
Integer a = 100;
相当于编译器自动为你执行下Integer b = Integer.valueOf(100);
自动拆箱
int c = a;
相当于编译器自动执行int c = a.intValue();
关于[-128,127]之间的缓存问题
首先我们来看一段代码,思考一下结果是什么?
Integer int1 = Integer.valueOf(123);
Integer int2 = 123;
System.out.println(int1.equals(int2));
System.out.println(int1 == int2);
int1.equals(int2)结果为true很简单,两者值相等,那么int1 == int2呢?
很多人会以为答案是false,因为int1和int2是两个不同对象,它们在堆中所处空间不一样,但是结果是true。为什么会这样呢?
我们打开Integer的源码,看到valueOf方法里这样一段代码:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
这里的cache是什么呢?我们顺藤摸瓜:
static final int low = -128;
static final int high;
static final Integer cache[];
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;
}
我们对此进行分析,原来Integer一开始创建了一个cache数组,这个数组里有[-128,127]的Integer对象,当我们创建在这个范围的实例时,valueOf方法就会找到相应的实例,所以我们创建两个大小一样的对象其实是指向同一引用。
String类
String 类对象代表不可变的Unicode字符序列,因此我们可以将String对象称为“不可变对象”。
String类常用的方法有:
-
String类的下述方法能创建并返回一个新的String对象: concat()、 replace()、substring()、 toLowerCase()、 toUpperCase()、trim()。
-
提供查找功能的有关方法: endsWith()、 startsWith()、 indexOf()、lastIndexOf()。
-
提供比较功能的方法: equals()、equalsIgnoreCase()、compareTo()。
-
其它方法: charAt() 、length()。
StringBuffer和StringBuilder
StringBuffer和StringBuilder非常类似,均代表可变的字符序列。 这两个类都是抽象类AbstractStringBuilder的子类,方法几乎一模一样。我们打开AbstractStringBuilder的源码:
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char value[];
//以下代码省略
}
显然,内部也是一个字符数组,但这个字符数组没有用final修饰,随时可以修改。因此,StringBuilder和StringBuffer称之为“可变字符序列”。
两者的区别:
-
StringBuffer JDK1.0版本提供的类,线程安全,做线程同步检查, 效率较低。
-
StringBuilder JDK1.5版本提供的类,线程不安全,不做线程同步检查,因此效率较高。 建议采用该类。
一些StringBuffer方法:
StringBuffer str3 = new StringBuffer("abcd");
str3.append("e");//在尾部添加字符串
System.out.println(str3);
str3.reverse();//将字符串逆序
System.out.println(str3);
str3.setCharAt(1, 'B');//将该下标的字符替代
System.out.println(str3);
str3.insert(0,"A").insert(1, "BC");//链式调用,核心就是调用了return this;
System.out.println(str3);
str3.delete(0, 2);//删除[0,2)区间的字符
System.out.println(str3);
结果:
可变字符序列和边看边字符序列的陷阱
/**使用String进行字符串的拼接*/
String str = "";
//本质上使用StringBuilder拼接,但是每次拼接会产生新的字符串对象
long num1 = Runtime.getRuntime().freeMemory();//获取系统剩余内存
long time1 = System.currentTimeMillis();//获取系统当前时间
for(int i=0;i<5000;i++) {
str = str + i;//相当于产生了10000个对象
}
long num2 = Runtime.getRuntime().freeMemory();
long time2 = System.currentTimeMillis();
System.out.println("String占用内存"+(num1-num2));
System.out.println("String占用时间"+(time2-time1));
/**使用StringBuilder进行字符串的拼接*/
StringBuilder str1 = new StringBuilder("");
long num3 = Runtime.getRuntime().freeMemory();
long time3 = System.currentTimeMillis();
for(int i=0;i<5000;i++) {
str1.append(i);//相当于产生了10000个对象
}
long num4 = Runtime.getRuntime().freeMemory();
long time4 = System.currentTimeMillis();
System.out.println("String占用内存"+(num3-num4));
System.out.println("String占用时间"+(time4-time3));
结果:
使用String拼接产生大量对象会耗费很多内存和时间,因此非常不可取,而使用append消耗时间和内存忽略不计。