zoukankan      html  css  js  c++  java
  • Java的引用类型的内存分析

    一. jdk的内存:jdk的bin目录常见命令

      1. javac.exe:编译java源代码的,生成java字节码文件(*.class)

      2. java.exe:启动一个jvm,来运行指定class字节码文件

      3. javap.exe:(javap -c  java type.class)反汇编Java字节码成Java源代码。

    二. Jvm的内存

      1. 栈内存:函数的{ }之间定义的变量均在JVM的stack栈内存中存储(在定义其变量的时候,开辟空间,当执行到函数右大括号时,栈内存回收)

      注:简单类型定义的变量直接存储数值,引用类型定义的变量存储的是地址。

        

      2. 堆内存:存储新new的对象(new的时候开辟空间, 闲置时则靠GC(Garbage Collection垃圾回收器)来回收堆内存)

      注:堆里只存储新new的对象

        JVM内存简单示例:

     3. int型

        1. int a=10;

        int b=10;

        //简单类型,变量里存储的是数值

        System.out.println(a==b);

        //因为存储的是数值,所以此处比较的是数值大小。

        //结果:true

       2. Integer b=new Integer(10);

        Integer d=new Integer(10);

        //引用类型,变量里存储的是地址,new的对象(10)在堆里。

        System.out.println(b==d);

        //因为存储的是地址,b,d 地址不相等。/

        /结果:false

        System.out.println(b.equals(d));

        //此处是对b, d 进行调用函数equals(),比较其数值的大小。

        //结果:true

       3. Integer b=new Integer(10);

        Integer e=10;

                  Integer f=10;

        //此处调用Integer.valueOf()函数,相当于

         Integer.valueOf(10)

         if(data>=-128&&data<=127)

          {

           return Integer.cache(data);//返回的是缓存池里的固定地址

          }

         else{

           return new Integer(data);//返回的是新new出来的地址

           }

        //注:用Integer e=?;定义变量时,当变量的值?在-128——//127之间时,e的地址均在常量池里找。

        System.out.println(e==f);

        //因为e,f的变量值均在-128——127之间,所以在常量池中查找,

        //且e ,f 存储的是地址,即结果为true

        System.out.println(e==b);

        //因为b是用Integer e=?;方式定义的,且在-128——127范//围内,所以地址在常量池里查找。而b是新new的地址,所以结果:false。

           装包:Integer e=10;//(将一个数值赋给引用变量,此时就要进行装包,装包的实质就是调用 Integer.valueOf(10);找到在缓存池中的位置,返回地址。)

         Integer.valueOf(10)

         if(data>=-128&&data<=127){

                         return Integer.cache(data);//返回的是缓存池里的固定地址

         }else{

                         return new Integer(data);//返回的是新new出来的地址

                       }

           

           拆包:int b=a;    (当两个变量进行比较,一个为数值,一个为地址时,此时就要对引用地址的变量进行拆包)

                              //a.intValue()

             { 

              return  Value;//返回其数值

             }

        例题分析:

            *在jdk1.5的环境下,有如下4条语句:

            Integer i01=59;   //  要装包

            int i02=59;

            Integer i03= Integer.valueOf(59);

            Integer i04= new Integer (59);

            以下输出结果为false的是( C )

            A. System.out.println(i01== i02);

            //1是装包后,地址在常量池里找的。2存的是数值。所以此时两者进行比较要对i01进行拆包,然后在进行比较。True

            B. System.out.println(i01== i03);

            //1是装包后,地址在常量池里找的。3是1的具体语句,所以3也是装包后,地址在常量池里找。  True

            C. System.out.println(i03== i04);

            //3是装包后,地址在常量池里找的。

             //4是新new的,地址是新开辟的。  False

            D. System.out.println(i02==i04);

           //2存的是数值。4是新new的地址。所以此时进行拆包,两者均拆为数值,然后进行比较。  true

      4.string型

        1.String  str1=new String("hello world");//str1存储的是新new的地址

          String  str2=new String("hello world");  //str2存储的是新new的地址

          String  str3="hello world";                     //str3进行了装包,并且地址是在常量池里查找的

            System.out.println(str1=str2);

          System.out.println(str1=str3);

          System.out.println(str1.equals(str2));

                      

     5.Byte型.Short型.long型.Float型.Double型与Integer型用法一样。

        但Byte型的范围为-128——127,所以Byte data1=Byte.valueOf(59);均在常量池中查找。

    6.例题1

     1 public class liti {
     2     public static void main(String[] args) {
     3         int a=10;
     4         int b=20;
     5         swap(a,b);  //调用swap方法对变量,a b 的值进行交换
     6         System.out.println(a+" "+b);
     7     }
     8     private static void swap(int a,int b)
     9     {
    10         int temp=a;
    11         a=b;
    12         b=a;
    13 
    14     }
    15 }

    代码结果

     分析:

          当程序开始执行时,首先调用了main()方法,所以JVM在栈内存中给main()方法开辟了一块内存,在main()方法内存中

    定义了两个变量 a, b ,并分别给其赋值10,20。接着又调用了swap()方法,于是JVM在栈内存中给swap()方法也开辟了一块

    内存,在swap()方法内存中,定义了一个变量temp,并将a的值赋给temp,然后将 a b 的值进行交换,当出了swap()方法的

    右大括号时,swap内存被回收,因为swap()方法中无任何返回值,所以随着内存被回收,在swap内存中进行的一切运算也

    将归零。而此时main()方法中 a 和 b 变量的值仍为10 和20,这时候打印出来的结果仍为a=10,b=20.

     7.例题二

     1 public class liti {
     2     public static void main(String[] args) {
     3    int[] arr=new int[2];
     4    arr[0]=10;
     5    arr[1]=20;
     6    swap(arr,0,1);  //交换数组元素arr[0],arr[1]的值
     7         System.out.println(arr[0]+" "+arr[1]);
     8         }
     9 
    10     private static void swap(int[] arr, int i, int i1) {
    11         int temp=arr[0];
    12             arr[0]=arr[1];
    13             arr[1]=temp;
    14 
    15     }
    16 }

    运行结果

     分析

         当程序在执行时,首先调用了main()方法,所以Jvm在栈内存中给main()方法开辟了一块内存,在这块内存中

    定义了一个数组变量,其变量中存储的是数组的地址,然后根据地址又在堆内存中给数组元素进行了赋值,接着

    调用swap()方法,所以Jvm在栈内存中给swap()方法开辟了一块内存 ,  在这块内存中定义了一个数组变量,并将

    main()方法中的数组变量arr的值(地址)赋给它,swap()方法根据变量arr中的地址,在堆内存中找到该数组,并将

    数组元素arr[0] 和arr[1]的值进行交换。此时swap()方法执行完毕,swap内存被Jvm回收。因为main()方法和swap()

    方法引用的是一个数组地址,所以此时main()方法中的数组的值也被就改变了,所以在main()方法中打印arr数组元

    素的值,结果为arr[0]=20;arr[1]=10。

    8.例题

     1 import java.util.Arrays;
     2 public class liti {
     3     public static void main(String[] args) {
     4         String str="good";
     5         char[] ch={'a','b','c'};
     6         change(str,ch);
     7         System.out.println(str+" "+ Arrays.toString(ch));
     8     }
     9 
    10     private static void change(String str, char[] ch) {
    11         str="test.ok";
    12         ch[0]='g';
    13     }
    14 }

    代码结果:

     分析:

        当程序在执行时,首先调用了main()方法,所以Jvm在栈内存中给main()方法开辟了一块内存,在这块内存中

    先定义了一个字符类型变量,该变量中存储的是该字符串在堆中的地址,然后定义了一个字符数组变量,

    其变量中存储的是数组的地址,然后根据地址又在堆内存中给字符数组元素进行了赋值。接着调用change()方法,

    所以Jvm在栈内存中给change()方法开辟了一块内存,在change内存中,定义了一个字符串变量,并将main()方法

    中的字符串变量的值(地址)赋给它,还定义了一个字符数组变量,同样的,并将main()方法中的字符数组变量的值

    (地址)赋给它,然后在该方法中又将字符串“good”在堆中(字符串常量池)的地址赋给str,接着又根据ch的地址

    在堆中找到字符串数组,并将堆中的数组元素ch[0]='a';变成ch[0]='g';随着change()方法执行完毕,change()方法

    的内存被回收,而此时main()方法中的str变量仍存储的是“good“的地址,虽然ch也存储的仍是数组在堆中的地址

    但数组内的值却发生了变换。所以打印出来的结果str不变,ch变。

  • 相关阅读:
    uniDAC 8.4.1一个严重的bug
    Delphi Event Bus进阶(三)如何使用通道?
    从delphi 10.3到delphi 10.4的改变实务
    uniDAC 8.4.1 database is locked
    调整Delphi IDE代码的行间距
    Deployment Manager now Open Source
    Delphi 10.4.2 Android 64位发布格式之App Bundle格式aab
    每日日报79
    每日日报78
    团队冲刺博客(四)
  • 原文地址:https://www.cnblogs.com/ljl150/p/11555008.html
Copyright © 2011-2022 走看看