Java易錯點1

這是我參與更文挑戰的第8天,活動詳情查看: 更文挑戰java

Java易錯點1

若有理解錯誤的話,懇請你們指正!!!程序員

內存

Java自動管理棧和堆,程序員不能直接地設置棧或堆。數組

  • 棧內存:
    • 一些基本類型的變量(int, short, long, byte, float, double, boolean, char)和對象的引用變量(對象句柄)。
    • 定義變量時,就在棧中分配內存空間,當超過變量的做用域後,會自動釋放掉爲該變量所分配的內存空間,該內存空間能夠當即被另做他用。
    • 存取速度比堆要快,僅次於寄存器
    • 數據能夠共享
    • 存在棧中的數據大小與生存期必須是肯定的,缺少靈活性
  • 堆內存
    • 存放由new建立的對象和數組。
    • 由Java虛擬機的自動垃圾回收器來管理。
    • 建立一個數組或對象後,還能夠在棧中定義一個特殊的變量,這個變量的取值等於數組或對象在堆內存中的首地址,這個變量就成了數組或對象的引用變量。 使用棧中的引用變量來訪問堆中的數組或對象。在沒有引用變量指向它的時候,才變成垃圾,不能再被使用,可是仍然佔着內存,在隨後的一個不肯定的時間被垃圾回收器釋放掉。 棧中的變量指向堆內存中的變量,這就是 Java 中的指針!
    • 運行時數據區,類的(對象)從中分配空間。這些對象經過new、newarray、anewarray和multianewarray等指令創建
    • 動態地分配內存大小,生存期也沒必要事先告訴編譯器
    • 因爲要在運行時動態分配內存,存取速度較慢。

示例代碼

people對象

package com.wangscaler;

public class People {
    private int age;
    private String name;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "People{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
複製代碼

main函數

package com.wangscaler;

public class Main {

    public static void main(String[] args) {
        // write your code here
        int a = 10;
        int b = 20;
        String c = "wang";
        Integer d = 30;
        System.out.println("c的值爲" + c + ",內存地址爲" + System.identityHashCode(c));
        System.out.println("d的值爲" + d + ",內存地址爲" + System.identityHashCode(d));
        System.out.println("a的值爲" + a);
        System.out.println("b的值爲" + b);
        chage(a, b);
        System.out.println("a的值爲" + a);
        System.out.println("b的值爲" + b);
        People people = new People();
        people.setAge(30);
        people.setName("wang");
        System.out.println("people的值爲" + people + ",內存地址爲" + System.identityHashCode(people));
        System.out.println("people.name的值爲" + people.getName() + ",內存地址爲" + System.identityHashCode(people.getName()));
        System.out.println("people.age的值爲" + people.getAge() + ",內存地址爲" + System.identityHashCode(people.getAge()));
        People people1 = new People();
        people1.setName("scaler");
        people1.setAge(40);
        System.out.println("people1的值爲" + people1 + ",內存地址爲" + System.identityHashCode(people1));
        chagePeople(people, people1);
        System.out.println("交換後people的值" + people + ",內存地址爲" + System.identityHashCode(people));
        System.out.println("交換後people1的值" + people1 + ",內存地址爲" + System.identityHashCode(people1));

    }

    public static void chage(int a1, int b1) {
        int c1 = a1;
        a1 = b1;
        b1 = c1;
        System.out.println("c1的值爲" + c1);
        System.out.println("a1的值爲" + a1);
        System.out.println("b1的值爲" + b1);
    }

    public static void chagePeople(People people2, People people3) {
        People people4 = people2;
        people2 = people3;
        people3 = people4;
        System.out.println("people4的值爲" + people4 + ",內存地址爲" + System.identityHashCode(people4));
        System.out.println("people3的值爲" + people3 + ",內存地址爲" + System.identityHashCode(people3));
        System.out.println("people2的值爲" + people2 + ",內存地址爲" + System.identityHashCode(people2));
    }
}

複製代碼

執行結果

c的值爲wang,內存地址爲356573597
d的值爲30,內存地址爲1735600054
a的值爲10
b的值爲20
c1的值爲10
a1的值爲20
b1的值爲10
a的值爲10
b的值爲20
people的值爲People{age=30, name='wang'},內存地址爲21685669
people.name的值爲wang,內存地址爲356573597
people.age的值爲30,內存地址爲1735600054
people1的值爲People{age=40, name='scaler'},內存地址爲2133927002
people4的值爲People{age=30, name='wang'},內存地址爲21685669
people3的值爲People{age=30, name='wang'},內存地址爲21685669
people2的值爲People{age=40, name='scaler'},內存地址爲2133927002
交換後people的值People{age=30, name='wang'},內存地址爲21685669
交換後people1的值People{age=40, name='scaler'},內存地址爲2133927002

Process finished with exit code 0

複製代碼

原理

  • 前14行markdown

image-20210608144647495.png

a和b都是基本類型,因此只在棧內存申請內存空間,而String和Integer(Integer是int的包裝類,Integer實際是對象的引用)是在棧內存只是定義一個特殊的變量,而這個變量指定了堆內存的首地址。ide

  • 15-17行、34-41行函數

java2.png

change執行後,只是把a和b的值傳遞給a1和b1,對a和b並沒有任何影響。post

java3.png

此時執行change方法,交換的只是a1和b1的值,當change執行完畢,a1和b1就結束了他的生命週期,固棧內存中空間會被釋放掉。this

java4.png

  • 18-27spa

    當建立People對象的時候,就會在堆內存申請空間,同時在棧中定義一個特殊的變量,該變量指向堆內存的首地址,當給對象賦值時,就會指向值的地址,因此此時c和people.name指向的都是同一個堆內存地址。3d

java5.png

建立people1的過程同上

java6.png

  • 剩餘代碼

    進行交換時,由於是值傳遞,因此傳遞的是堆內存的地址。因此同a1,b1,c1同樣,他們的交換,與people、people1無關。

java7.png

數組

示例代碼

package com.wangscaler;

public class TestArray {
    public static void main(String[] args) {
        int[] data = new int[3];
        int[] temp = new int[3];
        System.out.println("data的值爲" + data + ",內存地址爲" + System.identityHashCode(data));
        System.out.println("data的值爲" + temp + ",內存地址爲" + System.identityHashCode(temp));
        data[0] = 99;
        data[1] = 20;
        data[1] = 30;
        data = temp;
        temp[0] = 100;
        System.out.println("data[0]的值爲" + data[0] + ",內存地址爲" + System.identityHashCode(data));
        System.out.println("temp[0]的值爲" + temp[0] + ",內存地址爲" + System.identityHashCode(temp));
        System.out.println("data的值爲" + data + ",內存地址爲" + System.identityHashCode(data));
        System.out.println("temp的值爲" + temp + ",內存地址爲" + System.identityHashCode(temp));

    }
}

複製代碼

執行結果

data的值爲[I@1540e19d,內存地址爲356573597
data的值爲[I@677327b6,內存地址爲1735600054
data[0]的值爲100,內存地址爲1735600054
temp[0]的值爲100,內存地址爲1735600054
data的值爲[I@677327b6,內存地址爲1735600054
temp的值爲[I@677327b6,內存地址爲1735600054
複製代碼

data和temp指向了同一個堆內存地址,因此輸出的推地址是同樣的,都是[I@677327b6。此時若是修改任意一個數組的數據,另外一個跟着變化。

浮點數不可做爲循環變量

由於浮點數精度問題,在程序運行的時候會損失精度,若是程序中使用浮點數做爲循環變量,每每不能達到預期的效果

示例代碼

public class TestFloat {
    public static void main(String[] args) {
        float data = 2000000010f;
        for (float i = 2000000000f; i <= data; i++) {
            System.out.println(i);
        }
    }

}
複製代碼

運行結果

2.0E9
2.0E9
2.0E9
2.0E9
2.0E9
....
//無限循環
//將i <= data改成i <data無任何輸出
複製代碼

原理

一、這裏的2000000000f轉換成二進制表示爲1110111001101011001010000000000, 在計算機存儲中,須要使用二進制的科學計數法表示,計算機不認識十進制數。

二、即1110111001101011001010000000000=1.110111001101011001010000000000*2^30

三、指數爲30+127(IEEE754約定的單精度偏移量)=157,轉換成二進制爲10011101

四、尾數部分截取小數點後的23位(IEEE754約定的單精度尾數長度)

四、因此2000000000f就變成0(符號位1位,0表明正,1表明爲負 )10011101(指數位8位)11011100110101100101000(尾數部分23位)即在內存中存儲的二進制爲01001110111011100110101100101000

五、同理20000000010f---->1110111001101011001010000001010--->1.110111001101011001010000001010*2^30--->指數爲相同

六、20000000010f在內存的表示爲0100111011101110011010110010100

七、對比發現2000000000f和20000000010f在內存中的二進制表示方式是同樣的。因此在這裏2000000000f和2000000010f對程序而言是相等的,因此沒法達到咱們預想的效果(打印十次)。

相關文章
相關標籤/搜索