目录
==和EQUALS的区别?
equals:比较两个引用类型的地址(有重写的特殊情况)
== :比较两个基本数据类型的值,比较两个引用类型的地址
1、基本数据类型
== 比较的是值
2、普通引用类型
没有重写equals方法,自动继承的Object类的方法,比较地址。
== 和 equals比较的都是地址
3、特殊的引用类型
Srting类、Integer类、Date类,java重写了equals()方法,比较的是值。
装箱与拆箱
自动装箱:
装箱:把基本数据类型转换为对应的包装类类型。
基本类型的数据处于需要对象的环境中时,会自动转为“对象”,由自动装箱过程通过调用包装类的valueOf()方法实现的。
Integer i = 5; //代码
Integer i = Integer.valueOf(5);//编译器转换,自动装箱
只需Integer i = 5这样的语句就能实现基本数据类型转换成包装类,这是因为JVM为我们执行了Integer i = Integer.valueOf(5)这样的操作,这就是Java的自动装箱。
注意:对于Integer类的特殊情况
Integer.valueOf(int/String num);源代码如下
“valueOf()会返回一个Integer(整型)对象,当被处理的字符串或数字在-128和127(包含边界)之间时,返回的对象是预先缓存的。”,因此用该方法获得[-128,127]的对象,相同的数值获得是相同的对象。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
public static Integer valueOf(String s) throws NumberFormatException {
return Integer.valueOf(parseInt(s, 10));
}
自动拆箱:
拆箱:把包装类类型转换为对应的基本数据类型。
每当需要一个值时,对象会自动转成基本数据类型,由自动拆箱过程通过调用包装类的如intValue()、doubleValue()等方法实现的。
Integer i = 5;
int j = i; //代码
int j = i.intValue()//编译器转换,自动拆箱
注意:可能导致空指针异常的情况
public class Test1 {
public static void main(String[] args) {
Integer i = null;
int j=i;
//在编译时期是合法的,但是在运行时期会有错误,因为其相当于:
int j = i.intValue();
}
}
null表示i没有指向对象实例,因此编译后使用空引用调用了方法,导致产生了空指针异常。
STRING类型相关
创建字符串
使用new关键字新建一个字符串对象时,JVM首先在字符串常量池中查找有没有"xyz"这个字符串对象,
如果字符串常量池中有,则直接在堆中创建一个"xyz"字符串对象,然后将堆中的这个"xyz"对象的地址返回;
如果字符串常量池中没有,则首先在字符串常量池中创建一个"xyz"字符串对象,然后再在堆中创建一个"xyz"字符串对象,然后将堆中这个"xyz"字符串对象的地址返回。
String s1 = new String("xyz");//创建两个对象,字符串常量池中一个"xyz",堆上一个"xyz"
String s2 = new String("xyz");//堆上创建一个"xyz"
System.out.println(s1==s2);
因此上述代码一共创建了三个字符串对象,new第一个String对象时,字符串常量池中没有"xyz",所以在字符串常量池中创建一个"xyz",堆上在创建一个"xyz",new第二个String对象时,只在堆上创建一个"xyz"。
拼接String字符串
+如何拼接String字符串?
字符串常量在拼接过程中,会先创建一个StringBuilder对象,然后再使用append()方法将需要连接的字符串添加到该对象中,最后使用StringBuilder对象的toString()方法获得一个String字符串。
concat如何拼接字符串?
首先分别获得原字符串和拼接字符串的长度,按照该长度用Arrays.copyOf()获得一个新字符数组,且将原字符串复制到字符数组中,然后用getChars()将拼接字符串复制到字符数组中,再新建一个String字符串返回。
public String concat(String str) {
int otherLen = str.length();//获得拼接部分的长度
if (otherLen == 0) {
return this;
}
int len = value.length;//获得原字符串长度
//获得一个新的字符数组,长度为原字符串长度与拼接字符串长度之和
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);//将字符串内容复制到字符数组后面
return new String(buf, true);//新建一个String字符串并返回
}
创建了几个对象?
String str = "abc" + new String("def");
//等同于
String s = new String("def");
new StringBuilder().append("abc").append(s).toString();
对比等价代码,执行【new String("def");】会在堆和字符串常量池分别创建一个"def"对象,然后在字符串常量池创建一个"abc"对象,由于使用了【+】,先在堆上创建一个StringBuilder对象,然后使用该对象的append()方法将"abc"字符串添加到StringBuilder对象中,最后使用toString()方法获得一个String对象。
因此,字符串常量池中创建了"def"对象、"abc"对象、堆中有StringBuilder对象、"abcdef"对象、"def"对象,一共5个对象字符串。
StringBuilder如何添加新字符
-
value[] : 用来存储StringBuilder对象中的字符,以下称内容数组,其长度可在创建对象时通过构造函数初始化,若未初始化则默认初始长度为16
-
count: 记录StringBuilder对象中所存字符的实际数量,以下称实际内容长度
sb.append(str)的添加流程:
判断count + str.length > char.length?
(1)内容数组容量足够,直接将str复制存入内容数组。
(2)内容数组容量不足够则扩容,即扩大长度为原长度 * 2再加2,即char.length * 2 + 2,此时再次比较是否足够,char.length * 2 + 2 < count + str.length?
i: No 即足够,此时容量足够,将str复制存入内容数组, 此时内容数组长度为char.length*2 + 2。更新实际内容长度 count += len
ii:yes 不足够,则内容数组长度增加至 count + str.length, 并将str复制存入内容数组,此时实际内容长度为:count += len
Array.copyOf(int[] a,int len) 用于复制指定的数组内容以达到扩容的目的。创建一个新的长度为len数组的数组并返回,且将旧数组a的内容复制给新数组。若len长度小于a数组长度,则新数组长度为a数组长度。