數(shù)據(jù)結(jié)構(gòu)_內(nèi)存表示

對(duì)象與引用對(duì)象

  • 對(duì)象引用

    對(duì)于一個(gè)簡單的例子:
    Person p=new Person("Jim",18);
    內(nèi)存表示:

    1

    棧內(nèi)存中p并不是一個(gè)對(duì)象本身,而只是一個(gè)指向?qū)ο蟮闹羔?引用).用等號(hào)賦值時(shí),是將右側(cè)堆內(nèi)存中對(duì)象的地址賦予給對(duì)象引用.

  • 引用賦值

    若繼續(xù)進(jìn)行操作的話:

     Person p2=p;
     p2.name="Lucy";
    

    那么p的名字也受影響變成了lucy.

    2

    當(dāng)我們將一個(gè)引用賦值給另一個(gè)引用時(shí),我們實(shí)際上復(fù)制的是對(duì)象的地址。兩個(gè)引用將指向同一對(duì)象.其中一個(gè)引用修改對(duì)象,另一個(gè)引用也看得見.

  • 垃圾回收

    一個(gè)對(duì)象可以有多個(gè)引用,一個(gè)引用不可以有多個(gè)對(duì)象.同時(shí),一個(gè)對(duì)象要是沒有引用,會(huì)被垃圾回收.

    3

  • 參數(shù)傳遞

    java只有值傳遞,java只有值傳遞,java只有值傳遞!
    如果傳遞參數(shù)類型是基本數(shù)據(jù)類型,那么傳過來的就是這個(gè)參數(shù)的一個(gè)副本,也就是這個(gè)原始參數(shù)的值,這個(gè)與c的傳值是一樣的。如果在函數(shù)中改變了副本的 值不會(huì)改變?cè)嫉闹?
    如果傳遞參數(shù)類型是引用類型,那么傳過來的就是這個(gè)引用參數(shù)的副本,這個(gè)副本存放的是參數(shù)的地址。如果在函數(shù)中沒有改變這個(gè)副本的地址,而是改變了地址中的 值,那么在函數(shù)內(nèi)的改變會(huì)影響到傳入的參數(shù)。如果只是改變地址,指針指來指去,而不去改變值,是不會(huì)影響參數(shù)的值。
    引用一段Clara_babybear代碼作為例子:
      public class ParamTest {
     public static void main(String[] args){
           /**
            * Test 1: Methods can't modify numeric parameters
            */
          System.out.println("Testing tripleValue:");
           double percent = 10;
           System.out.println("Before: percent=" + percent);
           tripleValue(percent);
           System.out.println("After: percent=" + percent);
    
           /**
            * Test 2: Methods can change the state of object parameters
            */
           System.out.println("\nTesting tripleSalary:");
           Employee harry = new Employee("Harry", 50000);
           System.out.println("Before: salary=" + harry.getSalary());
           tripleSalary(harry);
           System.out.println("After: salary=" + harry.getSalary());
    
           /**
            * Test 3: Methods can't attach new objects to object parameters
            */
           System.out.println("\nTesting swap:");
           Employee a = new Employee("Alice", 70000);
           Employee b = new Employee("Bob", 60000);
           System.out.println("Before: a=" + a.getName());
           System.out.println("Before: b=" + b.getName());
           swap(a, b);
           System.out.println("After: a=" + a.getName());
           System.out.println("After: b=" + b.getName());
     }
    
     private static void swap(Employee x, Employee y) {
         Employee temp = x;
         x=y;
         y=temp;
         System.out.println("End of method: x=" + x.getName());
         System.out.println("End of method: y=" + y.getName());
     }
    
     private static void tripleSalary(Employee x) {
         x.raiseSalary(200);
         System.out.println("End of method: salary=" + x.getSalary());
     }
    
     private static void tripleValue(double x) {
         x=3*x;
         System.out.println("End of Method X= "+x);
     }
    

}

輸出結(jié)果  
```java
 Testing tripleValue:
 Before: percent=10.0
 End of Method X= 30.0
 After: percent=10.0

 Testing tripleSalary:
 Before: salary=50000.0
 End of method: salary=150000.0
 After: salary=150000.0

 Testing swap:
 Before: a=Alice
 Before: b=Bob
 End of method: x=Bob  //可見引用的副本進(jìn)行了交換
 End of method: y=Alice
 After: a=Alice  //引用本身沒有交換
 After: b=Bob

對(duì)象內(nèi)存表示

  • 對(duì)象內(nèi)存基礎(chǔ)

    java中內(nèi)存主要包含4塊,即heap(堆內(nèi)存)、stack(棧內(nèi)存)、data segment(靜態(tài)變量或是常量存放區(qū))、codesegment(方法區(qū)).
    堆內(nèi)存: 存放的是new出的對(duì)象,new出的對(duì)象只包含成員變量.
    棧內(nèi)存: 存放的是局部成員變量。對(duì)于基本的數(shù)據(jù)類型存放的是基本變量的值,而對(duì)于對(duì)象變量,存放的是堆內(nèi)存的地址。
    靜態(tài),常量區(qū): 存放的是靜態(tài)變量(類變量)或是常量(字符串常量和基本類型常量(public static final))。
    方法區(qū): 存放的是對(duì)象的方法。因此即使new出多個(gè)對(duì)象也是只存在一個(gè)方法。
    對(duì)于一段簡單的代碼:
 class Student{
   private String name;
   private int id;
   private Class class;
   public void study(){};
 }
 class Class{
   private String name;
   private int id;
   public void exam(){};
 }
 public class MainClass(){
     public static void main(String[] args){
       Student s=new Student();
       s.name="Jim";
       s.id=001;
       s.study();
       Student s2=new Student();
       s2.name="Lucy"
       Class c=new Class();
       c.name="三班";
       c.id=03;
       s.class=c;
       c.exam();
     }
 }

關(guān)于該段內(nèi)存表示:

4

考慮一些復(fù)雜的情況:

 class Student{
   private String name;
   private int id;
   private Class class;
   public Student(String iname,int iid){
     name=iname;
     id=iid;
   }
   public void study(int i){
     id=i;
     class.exam();
   };
 }
 class Class{
   private String name;
   private int id;
   public void exam(){};
 }
 public class MainClass(){
     public static void main(String[] args){
       Student s=new Student("Jim",001);
       Class c=new Class();
       c.name="三班";
       c.id=03;
       s.class=c;
       s.study(010);
     }
 }

內(nèi)存表示:

5

形參,局部變量基本類型的值都是在棧內(nèi)存中

  • 關(guān)于繼承與多態(tài)內(nèi)存表示

一個(gè)簡單的例子:

 class Animal(){
   private String name;
   public void eat(){}
   public void run(){
     eat();
   }
 }
 class Birds extends Animal(){
   private Wing wing;
   public void eat(){}
 }
 public MainClass(){
    public static void main(String[] args){
    Animal a=new Birds();
    a.eat();
    a.run();
    }
 }
6

分析方法調(diào)用過程:
創(chuàng)建的對(duì)象a指向Birds類,this層為Birds類那層.
a.eat()方法從this層調(diào)起,調(diào)用Bird類的eat()方法.
a.run()方法從this層調(diào)起,沒有則去調(diào)Animal的run()方法.這時(shí)候run()方法要調(diào)用eat()方法,同樣從this層調(diào)起,調(diào)用Birds類的eat()方法.

  • 串的內(nèi)存表示

    String是一個(gè)特殊的包裝類數(shù)據(jù)。可以用String str = new String("abc");String str = "abc"; 兩種的形式來創(chuàng)建.
    第一種用new創(chuàng)建的對(duì)象會(huì)放在堆中,每調(diào)用一次會(huì)創(chuàng)建一個(gè)新的對(duì)象.
    第二種先在棧中創(chuàng)建一個(gè)對(duì) String類的對(duì)象引用變量str,然后通過符號(hào)引用去字符串常量池 里找有沒有"abc",如果沒有,則將"abc"存放進(jìn)字符串常量池 ,并令str指向”abc”,如果已經(jīng)有”abc” 則直接令str指向“abc”。
    值得一提的是:

    1. new String()和new String("")都是申明一個(gè)新的空字符串,是空串不是null;
    2. "fredal"=="fre"+"dal";
      "fredal"!="fre"+new Stirng("dal");
      String s="a";String s2="b";"ab"!=s+s2
    3. equals對(duì)于String簡單來說就是比較兩字符串的Unicode序列是否相當(dāng);而==是比較兩字符串的地址是否相同,也就是是否是同一個(gè)字符串的引用。
    4. String是不可變的,所有會(huì)產(chǎn)生很多臨時(shí)變量,可以采用StringBuffer,StringBuilder.
    5. 關(guān)于final,例如final String ia="a",由于對(duì)于final修飾的變量,它在編譯時(shí)被解析為常量值的一個(gè)本地拷貝存儲(chǔ)到自己的常量池中或嵌入到它的字節(jié)碼流中,用的時(shí)候ia和"a"沒啥區(qū)別.2的第三個(gè)加了final就是相等的.
  • 數(shù)組內(nèi)存表示

    首先數(shù)組的初始化有靜態(tài)初始化和動(dòng)態(tài)初始化,前者類似于String[] names = { "Jim", "Lili", "Lucy" }這種,后者則是String[] names = new String[4];這種.
    根據(jù)數(shù)組的存儲(chǔ)對(duì)象的類型呢也有兩種,一種存基本數(shù)據(jù)類型,一種引用數(shù)據(jù)類型.
    當(dāng)然還有一維數(shù)組和多維數(shù)組的區(qū)別.
    一股腦舉個(gè)例子:

      String[] names={"Jim", "Lili", "Lucy"};
     
     int [] number=new int[3];
     for(int i=1;i<=3;i++){number[i-1]=i}
     
     Animal[] animal = new Animal[2];
     Animal cat = new Animal("cat", 1);
     Animal dog = new Animal("dog", 2);
     animal[0] = dog;
     animal[1] = cat;
     
     int[][] number2=new int[2][];
     number2[0]=new int[2];
     number2[1]=new int[3];
    
    7

    更多文章與相關(guān)下載請(qǐng)看擴(kuò)展閱讀

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容