先写总结:
==对于基本数据类型来说:是比较值
对于非基本数据类型来说:是比较引用
equals只针对引用数据类型,所以比较的是引用,但是
重要
重要
重要
重要的事情标记3遍:
但是 String,Integer等重写了equals方法,把他变成了值比较
另外lombok的@Data注解慎用,因为@Data注解相当于加了这几个注解:
@Getter
@Setter
@ToString
@EqualsAndHashCode
@RequiredArgsConstructor 会生成一个包含常量(final),和标识了@NotNull的变量 的构造方法。
由于会包括@EqualsAndHashCode会重写equals方法所以会导致equals变成值比较。
例如:
public class MyTest {
public static void main(String[] args) {
String s1 = "string";
String s2 = "string";
String s3 = new String("string");
System.out.println(s1 == s2);//值比较true
System.out.println(s1 == s3);//s3是引用类型,引用比较 false
System.out.println(s1.equals(s2));//true equals是引用比较,应该是false的,但是这里String类型重
//写了equals把他变成了值比较,所以是true
System.out.println(s1.equals(s3));//true 解释同上
Cat c1 = new Cat("小花");
Cat c2 = new Cat("小花");
System.out.println(c1 == c2);//引用比较false
System.out.println(c1.equals(c2));//引用比较false,
// 这里注意
// *************
// 如果Cat类加了@Data注解的话,会重写
// equals和HashCode,所以会把equals重写成值比较,变成true
// 所以以后@Data慎用,最好用@Getter和@Setter简化
// *************
}
}
//@Data
class Cat{
public Cat(String name){
this.name = name;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Test
public void test1() {
int i = 2 << 3;//位运算,相当于2*2的3次幂
int m = 16;
System.out.println(i == m);
System.out.println("------------------");
int a = 1;
int b = 1;
System.out.println(a == b);//基本数据类型值比较true
Integer c = new Integer(2);
Integer d = new Integer(2);
System.out.println(c == d);//非基本数据类型,引用比较false
System.out.println(c.equals(d));//Integer重写了equals方法变成了值比较true
Cat cat1 = new Cat("小花");
Cat cat2 = new Cat("小花");
System.out.println(cat1 == cat2);//引用的内存地址比较,肯定是false
System.out.println(cat1.equals(cat2));//equals就是内存地址比较,false,如果Cat类加了@Data注解,相当于加了@EqualsAndHashCode注解重写了equals方法,比较值,则返回true
System.out.println("111111111111111");
String q1 = "这是声明一个常量";
String q2 = "这是声明一个常量";
System.out.println(q1 == q2);//不是基本数据类型,所以比较的是内存地址,但是String这样声明的是一个常量,所以这两个是在一个常量池中q2指向的也是q1的常量地址,所以true
String q3 = new String("这是变量的声明方法");
String q4 = new String("这是变量的声明方法");
System.out.println(q3 == q4);//false
System.out.println(q3.equals(q4));//值比较true
}
扩展:
String,StringBuffer,StingBuilder的区别
String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。
StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。
扩展二
String s2 = "string";//java虚拟机会将其分配到常量池中
String s3 = new String("string");//会被分配到堆内存中
扩展三
String 类的常用方法都有那些?
indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
getBytes():返回字符串的 byte 类型数组。
length():返回字符串长度。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substring():截取字符串。
equals():字符串比较。
扩展四
对于String类型==比较的是内存地址是否一致,因为不是基本数据类型,所以==比较的是内存地址,
equals比较的却是值是否一致,因为String/Integer等都重写了equals方法,变成了值比较。
扩展五
String的常量(不仅String,Integer的常量也是)放在常量池中的,值相同的常量是共享同一块内存地址的,也就是==比较的内存地址是相同的。
重要扩展
/**
由于String的不可变,num = num + "0"会新开辟一个内存空间来存储新的num,之前的num内存空间没有对象引用,就变成了内存碎片,如果像这样循环100次就会产生100个内存碎片,造成内存浪费,这种需要频繁改变String值得情况就需要使用StringBuilder来处理,只针对一个StringBuilder对象来进行累加操作。
*/
String num = "1";
for(int i = 0; i < 100; i++) {
num = num + "0";
}
扩展toString
System.out.println(x);
//这个x即使不是String类型也能打印,这是因为默认调用了toString()方法,这个就是多态的运用。
网友评论