【1】相等比较
基本类型的包装类型和基本类型进行比较时,会自动进行装箱拆箱操作。
== 和 != 比较若类型不同,先偿试转换类型,再作值比较,最后返回值比较结果 。
而 === 和 !== 只有在相同类型下,才会比较其值。
如果是对象类型,==比较引用地址;如果是基本类型,==比较值;
a.equals(b),a必须为对象类型(不能为基本类型)且不能为null,b可以为object。
如果自定义对象如User没有重写equals方法,则继承Object的equals方法。而Object的equals方法则是简单的==比较–引用地址比较。
int a = 10; Integer b=10; a == b;//true b.equals(a);//true "10".eauals(b);//false,请注意! a.equals(10);//不存在该用法。
① ==与===
var num = 1; var str = '1'; var test = 1; test == num //true 相同类型 相同值 test === num //true 相同类型 相同值 test !== num //false test与num类型相同,其值也相同, 非运算肯定是false num == str //true 把str转换为数字,检查其是否相等。 num != str //false == 的 非运算 num === str //false 类型不同,直接返回false num !== str //true num 与 str类型不同 意味着其两者不等 非运算自然是true啦
② == 与equals
当为基本数据类型时,== 是判断值是否相等。
当时对象引用变量时,== 是判断对象引用地址(即,对象存放的内存地址);
如果自定义对象如User没有重写equals方法,则继承Object的equals方法。而Object的equals方法则是简单的==比较–引用地址比较。
Java中的基本类型和引用类型
③ Integer 的equals 与==
示例一
int t1=57; int t2=67; int t3=124; int t4=124; //单纯的值判断 System.out.println(t1==t2);//false System.out.println((t1+t2)==t3);//true System.out.println(t3==t4);//true Integer i1=new Integer(t1); Integer i2=new Integer(t2); Integer i3=new Integer(t3); Integer i4=new Integer(t4); //equals不能用于基本数据类型。只能用于对象类型(封装类型)。对于基本数据类型要用其包装类。 //i1 != i2 故为false System.out.println(i1.equals(i2));//false //i3== i1+i2 故为true System.out.println(i3.equals(i1+i2));//true //i3 == i4 故为true System.out.println(i3.equals(i4));//true
Integer类的equals方法
private final int value; //构造方法 public Integer(int value) { this.value = value; } //intValue 方法 public int intValue() { return value; } //equals 方法!!! public boolean equals(Object obj) { if (obj instanceof Integer) { /*首先转换为Integer类型,然后获取int 类型的 value值。拿着当前对象的value值 与 参数的 value值进行 == 判断!!!*/ return value == ((Integer)obj).intValue(); // 明白了,就是value的== 判断!!! } return false; }
示例二
@Test public void testInteger(){ Integer a1=10; Integer a2 = new Integer(10); int b1 = 10; Integer b2=new Integer(10); System.out.println(a1==a2);//false System.out.println(a1.equals(a2));//true System.out.println(a1==b2);//false System.out.println(a1.equals(b2));//true System.out.println(a1==b1);//true--自动进行拆箱操作 System.out.println(a1.equals(b1));//true }
可以看到,如果是对象类型,==比较引用地址;如果是基本类型,==比较值;a.equals(b),a必须为对象类型且不能为null,b可以为object。equals()比较值!!!
④ String 类的 == 与 equals
String 类的equals 方法:
public String(String original) { this.value = original.value; this.hash = original.hash; } public boolean equals(Object anObject) { //如果引用了同一个对象(引用地址相同),那么返回true if (this == anObject) { return true; } //如果参数为String的实例对象 if (anObject instanceof String) { //类型转换为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; }
测试代码
String st1="wasiker "; String st2="is super man"; String st3="wasiker is super man"; String st4="wasiker is super man"; // == 为判断变量保存的对象引用的内存地址 System.out.println(st1 == st2);//false System.out.println((st1+st2)==st3);//false System.out.println(st3==st4);//true--字符串常量池字符串都是唯一的 // String 重写了 equals 为 字符串中字符的 == 判断 System.out.println(st1.equals(st2));//false System.out.println(st3.equals(st1+st2));//true System.out.println(st3.equals(st4));//true
这里需要注意下面形式:
@Test public void testString11(){ String a1 = "2"; // 存放在常量池 String a2 = new String("2"); //存放在堆内存 String b1 = "2"; String b2 = new String("2"); System.out.println(a1==b1); //字符串常量池,2为唯一字符串a1等于b1 System.out.println(a1.equals(b1)); //如果引用地址想等直接返回true,不等则比较值(这里引用地址相等) System.out.println(a2==b2); //引用变量 == ,判断引用地址,故不等 System.out.println(a2.equals(b2)); //如果引用地址相等直接返回true,不等则比较值 System.out.println(a1==a2); //指向不同的引用:a1指向字符串常量池,a2指向堆 System.out.println(a1.equals(a2)); //引用地址不等,比较值 }
⑤ 普通Java bean
若没有重写equals 方法,则继承了object 类的 equals方法。
object类的equals方法:
public boolean equals(Object obj) { // 一个单纯的 == 判断引用地址!! return (this == obj); }
测试代码
SysUser user = new SysUser(); SysUser user2 = new SysUser(); SysUser user3 = user2; //内存地址不同 System.out.println(user == user2);//false //两个“不同”的对象。 System.out.println(user.equals(user2));//false //对同一个对象的引用 System.out.println(user3.equals(user2));//true //存储的地址为同一个对象的引用 System.out.println(user3==user2);//true
==比较的是值【变量(栈)内存中存放的对象的(堆)内存地址】
equals用于比较两个对象的值是否相同【不是比地址】
【特别注意】Object类中的equals方法和“==”是一样的,没有区别,而String类,Integer类等等一些类,是重写了equals方法,才使得equals和“==不同”。
所以,当自己创建类时,自动继承了Object的equals方法,要想实现不同的等于比较,必须重写equals方法!
⑥ instanceof
博文开头举了几个简单比较例子,其中一个如下:
Integer b= 10; "10".equals(b);//false
"10"这里很显然作为了字符串,String 的equals()源码上面已经说明过了。如果地址引用相同返回true,否则判断是否为string的对象实例,若是类型转换继续判断,不是则返回false。
何为对象实例?也就是instanceof
**instanceof运算符用法 **
运算符是双目运算符,左面的操作元是一个对象,右面是一个类 。当左面的对象是右面的类创建的对象时,该运算符运算的结果是true,否则是false 。instanceof左边操作元显式声明的类型与右边操作元必须是同种类或右边是左边父类的继承关系。
这里也就不难理解为什么"10".equals(b)返回false了。b为Integer类型,同样是一个独立的对象类型与String平级!
【2】值传递与引用传递
首先需要说明的是,Java 中只有值传递。
首先回顾一下在程序设计语言中有关将参数传递给方法(或函数)的一些专业术 语。按值调用(call byvalue)表示方法接收的是调用者提供的值,而按引用调用 (call by reference)表示方法接收的是调用者提供的变量地址。
一个方法可以 修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值。 它用来描述各种程序设计语言(不只是Java)中方法参数传递方式。Java程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的 一个拷贝,也就是说,方法不能修改传递给它的任何参数变量的内容。
当一个对象被当作参数传递到一个方法后,此方法可改变这个对 象的属性,并可返回变化后的结果,那么这里到底是值传递还是 引用传递?
是值传递。Java 语言的方法调用只支持参数的值传递。当一个对象实例作为一 个参数被传递到方法中时,参数的值就是对该对象的引用。对象的属性可以在被 调用过程中被改变,但对对象引用的改变是不会影响到调用者的。
实现一个改变对象参数状态的方法并不是一件 难事。理由很简单,方法得到的是对象引用的拷贝,对象引用及其他的拷贝同时 引用同一个对象。很多程序设计语言(特别是,C++和Pascal)提供了两种参数传递的方式:值调 用和引用调用。有些程序员(甚至本书的作者)认为Java程序设计语言对对象 采用的是引用调用,实际上,这种理解是不对的。
由于这种误解具有一定的普遍 性,所以下面给出一个反例来详细地阐述一下这个问题。
public class Test { public static void main(String[] args) { Student s1 = new Student("小张"); Student s2 = new Student("小李"); Test.swap(s1, s2); System.out.println("s1:" + s1.getName()); System.out.println("s2:" + s2.getName()); } public static void swap(Student x, Student y) { Student temp = x; x = y; y = temp; System.out.println("x:" + x.getName()); System.out.println("y:" + y.getName()); } }
输出结果:
1 x:小李 2 y:小张 3 s1:小张 4 s2:小李
方法并没有改变存储在变量 s1 和 s2 中的 对象引用。swap方法的参数x和y被初始化为两个对象引用的拷贝,这个方法交 换的是这两个拷贝。
值传递和引用传递有什么区别
值传递:指的是在方法调用时,传递的参数是按值的拷贝传递,传递的是值的拷 贝,也就是说传递后就互不相关了。
引用传递:指的是在方法调用时,传递的参数是按引用进行传递,其实传递的引 用的地
址,也就是变量所对应的内存空间的地址。传递的是值的引用,也就是说 传递前和传递后都指向同一个引用(也就是同一个内存空间)。