java对象赋值引起的问题

在java赋值的时候,有种情况是把一个对象赋值给另一个对象,这时会引起别名的问题。所以在写代码的时候一定要尽量避免这个问题。要知道为什么会引起这个问题首先要知道什么是引用(reference)。

 

//创建了一个引用s,引用是用来操纵对象的。引用不能被直接使用,必须让它指向一个实际的对象
String s;
//new String ("abc") 是实际的对象,引用s指向这个对象。java中创建对象通常用new关键字
s = new String ("abc");

我们来拿基本数据类型赋值和java对象赋值来做个对比:

基本数据类型存储的时候实际上存储的是一个实际的值,而并非对象的引用。所以把一个变量赋值给另一个变量的时候,是直接将一个地方的内容复制到另一个地方。

对象的存储分两部分,分别是引用和new的实际对象。引用存在堆栈中。java在调用new实例一个对象的时,在堆中分配一块内存给这个对象。通过 “=” 使引用指向实际分配内存的对象。java中把一个对象赋值给另一个对象实际上赋值的是引用,而不是对象。

/**
* 
*/
public class Test {
    public static void main(String[] args) {
        //基本数据类型赋值
        int a = 12;
        int b = 40;
        System.out.println("1: a: " + a + ", b: " + b);//1: a: 12, b: 40
     //把b等于40复制给a,所以a也等于40
        a = b;
        System.out.println("2: a: " + a + ", b: " + b);//2: a: 40, b: 40
     //修改了a的值,而b根本就不会受这种修改的影响
        a = 15;
        System.out.println("3: a: " + a + ", b: " + b);//3: a: 15, b: 40

        //对象赋值
        Bean b1 = new Bean();
        Bean b2 = new Bean();
        b1.num = 12;
        b2.num = 40;
        System.out.println("1: b1.num: " + b1.num + ", b2.num: " + b2.num);//1: b1.num: 12, b2.num: 40
        //b2的引用赋值给了b1,b1原来的引用被覆盖了,b1和b2现在是相同的引用,所以b1和b2都指向了原本只有b2指向的那个对象,所以值都是40
        b1 = b2;
        System.out.println("2: b1.num: " + b1.num + ", b2.num: " + b2.num);//2: b1.num: 40, b2.num: 40
     //对b1的修改其实也是在修改b2,因为它俩指向的是同一个对象,所以都是15
        b1.num = 15;
        System.out.println("3: b1.num: " + b1.num + ", b2.num: " + b2.num);//3: b1.num: 15, b2.num: 15
      //这样直接把一个对象赋值给了另外一个对象,引起来别名问题,如果想使b1数据的值修改成和b2一样,不会引起问题的方式应该是b1.num = b2.num
    }
}

class Bean {
    int num;
}

 自动递增和递减的两种方式的区别

/**
* java中自动递增和自动递减分前缀式和后缀式。以变量 i 为例,前缀式:++i、--i ,后缀式:i++、i--
* 对于前缀式,我们是在执行完运算后才得到值,对于后缀式,则是在运算执行之前就得到值
*/
public class Test{
    public static void main(String[] args) {
        int i = 1;
        System.out.println(i);//1
     //++i 是在 i 执行完 ++ 操作,才得到值,输出为2
        System.out.println(++i);//2
        //i=2,i++ 是先得到值是2,然后再++,所以输出是2
        System.out.println(i++);//2
     //在上面i执行了++操作,所以输出是3
        System.out.println(i);//3
        System.out.println(--i);//2
        System.out.println(i--);//2
        System.out.println(i);//1
    }
}

"==" 和 equals()

public class Test {
    public static void main(String[] args) {
        // 基本数据类型
        int a = 12;
        int b = 12;
        //基本数据类型直接比较数值
        System.out.println(a == b);//true

       //对象
        Integer x = new Integer(1);
        Integer y = new Integer(1);
        //x==y比较的实际是引用,虽然x和y的内容相同,但是引用不同所以是false
        System.out.println(x == y);//false
        //equals()方法默认比较的也是引用,但是java类库大多数都重写了该方法直接比较内容,所以x.equals(y)是相等的
        System.out.println(x.equals(y));//true
        
        Bean b1 = new Bean();
        Bean b2 = new Bean();
        b1.num = 12;
        b2.num = 12;
        //equals()对象比较的是引用,所以是false。如果想b1.equals(b2)等于true,需要重写Bean类中的equals()方法,让其比较对象中的内容
        System.out.println(b1.equals(b2));//false
    }
}

class Bean {
    int num;
}

短路现象

/**
* 其实&& 和 ||是逻辑操作符,& 和 | 是按位操作符,& 和 | 在操作的是布尔值时与逻辑操作符 && 和 ||有相同的效果,所以才放在一起比较,
* 两者的区别是:逻辑操作符有短路现象,按位操作符没有短路现象。
* 短路现象:逻辑表达式中一旦能够明确的无误的确定整个表达试的值,就不需要计算余下的部分了。
* 如果逻辑表达式都有一部分不必计算,那将获得潜在的性能提升,所以写代码尽量要用有短路现象的表达式&& 和 ||
*/
public class Test {
    public static void main(String[] args) {
        System.out.println("&& ----------");
        boolean a = test1(1) && test2(2) && test3(7);
//因为&&具有短路现象,test1(1)值为ture,所以继续执行test2(2),单test2(2)位false,可以断定 a 的值为false,所以不执行test3(7)
        System.out.println("result: " + a);
        
        System.out.println("& ----------");
        boolean b = test1(1) & test2(2) & test3(7);
     //因为&不具有短路现象,所以test1(1)、 test2(2)、 test3(7)都执行
        System.out.println("result: " + b);
    }
    
    static boolean test1(int val){
        System.out.println("test1");
        return val > 0;
    }
    
    static boolean test2(int val){
        System.out.println("test2");
        return val > 2;
    }
    
    static boolean test3(int val){
        System.out.println("test3");
        return val > 5;
    }
}

输出结果:

&& ----------
test1
test2
result: false
& ----------
test1
test2
test3
result: false