基本数据类型,指的是java
中的八种基本数据结构(byte,short,char,int,long,float,double,boolean
),一般的比较是使用的 ==
,比较的是他们的值。
复合数据类型(类)
==
比较的是两个对象的引用,可以理解为在内存中的地址,除非是同一个new
出来的对象,他们的 ==
为true,否则,都为false
。equal
是object
中的方法。object
中的实现如下,内部还是使用==
实现,也就是说,如果一个类没有重写equal
方法,那么比较还是地址。 public boolean equals(Object obj) {
return (this == obj);
}
3.String,Integer,Date
中重写了object
中的equal
方法。
string中的实现,比较的是字面值。
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
equal
方法必须要重写hashcode
方法?在jdk源码的equal
方法的注释中,是这样描述的
Note that it is generally necessary to override the {@code hashCode} method whenever this method is overridden, so as to maintain the general contract for the {@code hashCode} method, which states that equal objects must have equal hash codes.
重写equals
方法时候重写hashcode
方法的主要目的就是让Hashtable/HashSet/HashMap
等集合正常工作,因为这些集合是基于hashcode
进行地址判断的,如果重写equals而不重写hashcode
,对于HashMap
来说存入2个相同的对象保存一个key,却对应2个值,而取的时候是无法取出值,其它的集合类也是类似,为了不至于混乱出错,所以以上集合类重写equals
时候必须重写hashcode
方法。
不可变对象是指对象的状态在被初始化以后,在整个对象的生命周期内,不可改变。 以确保它们不会在子类中改变语义。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
首先,string的底层存储是基于一个被声明为final的字符数组,其次是string类本身被声明为final
.基于这两点,你不可能写一个类,来继承string类。
Tips one : * 当两个字符串字面值
连接时(相加),得到的新字符串依然是字符串字面值,保存在常量池中*
public static void test1() {
String a = "a1";
//当两个字符串字面值相加,得到的新字符串依然是字符串字面值,保存在常量池中
String b = "a" + 1;
System.out.println(a == b);
System.out.println(a.equals(b));
}
---> true true
Tip two: 当字符串字面值与String类型变量连接时,得到的新字符串不再保存在常量池中,而是在堆中新建一个String对象来存放。注意常量池中要求的存放的是常量,有String类型变量当然不能存在常量池中了。
public static void test2() {
String a = "ab";
String bb = "b";
//这是一个字符串字面值和一个字符串变量 相加,得到的是一个新字符串 ,在堆中创建一个新的变量来保存
String b = "a" + bb;
System.out.println(a == b);
System.out.println(a.equals(b));
}
---> false true
Tips three: 字符串字面值与String类型常量连接,得到的新字符串依然保存在常量池中
public static void test3() {
String a = "ab";
//注意,这个是字符串常量
final String bb = "b";
String b = "a" + bb;
System.out.println(a == b);
System.out.println(a.equals(b));
}
---> true true
Tips four: 并非定义为final的就保存在常量池中。
/**
* 很明显此处bb常量引用的String对象保存在堆中,
* 因为getBB()得到的String已经保存在堆中了,final的String引用并不会改变String已经保存在堆中这个事实。
*/
public static void test4() {
String a = "ab";
//final String bb = getBB();其实与final String bb = new String("b");是一样的。
//也就是说return “b”会在堆中创建一个String对象保存”b”,虽然bb被定义成了final。
final String bb = getBB();
String b = "a" + bb;
System.out.println(a == b);
System.out.println(a.equals(b));
}
private static String getBB() {
return "b";
}
---> false true
Tips five: intern()方法
这个方法是一个native方法,看不到源码,在jdk中有注释。
返回字符串对象的规范化表示形式。
一个初始为空的字符串池,它由类 String 私有地维护。
当调用 intern 方法时,如果字符串常量池已经包含一个等于此 String 对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并返回此 String 对象的引用。它遵循以下规则:对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。
//首先,变量a在栈上,保存的是“ab”的引用,
//“ab”在字符串常量池中,没有在堆上创建对象
private static String a = "ab";
public static void test5() {
String s1 = "a";
String s2 = "b";
//两个字符串变量相加,得到的结果字符串保存在堆中
String s = s1 + s2;
System.out.println(s == a);
System.out.println(s.intern() == a);
System.out.println(s.equals(a));
}
---> false true true
Tips six:
//首先,在字符串常量池中有一个“ab”的字符串,
//然后,当new时,会拷贝一份该字符串存放到堆中,
//于是字符串变量a指向了堆中的那个“ab”字符串
private static String a = new String("ab");
public static void test6() {
String s1 = "a";
String s2 = "b";
//两个字符串变量相加,得到的结果字符串保存在堆中
String s = s1 + s2;
System.out.println(s == a);
System.out.println(s.intern() == a);
System.out.println(s.intern() == a.intern());
System.out.println(s.equals(a));
}
---> false false true true
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/weiyongxuan/article/details/47363357