基础类型与引用类型引申

 

.基本类型与引用类型的值

        在计算机高级语言变量中包含两种不同数据类型:基本类型与引用类型.基本类型指那些保存在栈内存中的简单数据段,也就是说这些变量的值完全保存在栈内存中,而引用类型值指那些保存在堆中的对象,这就是说,引用类型变量在栈中保存的只是一个指向堆中指定对象的 指针而已,为什么要这么做呢,因为对象大小不能固定,而基础类型大小是固定的,int型就占4个字节(不同语言,平台有所差异),我们可以将固定大小的放在一个数据结构中,如果是基础类型直接取值,如果是引用类型首先从栈中读取内存地址,然后顺藤摸瓜,根据地址找到在堆中的值,这样可以提高我们的查询速度,

        JAVA中的基础类型有int,char,byte,long,short,boolean,特别注意String不是基础数据类型,但在javascriptECMAScript放弃这一传统,String作为基础数据类型.栈堆关系如下图,一目了然:


.复制变量值

   除了保存方式不同外,基础数据类型与引用同数据类型在复制变量时也不一样,如下例所示程序:

        int num1 = 5;

        int num2 = num1;

        num2 = 10;

        System.out.println(num1);   //5

        System.out.println(num2);   //10

        初始变量num1的值等于5当将变量num1的值赋于变量num2,num2也保存了5的值,但这两个5的值是完全独立的,num2中的5只是num1中的5的一个副本而已,相信这点大家很容易理解,下面配合图标将这次赋值过程展现出来:

 


 


        对于引用变量的复制,实质上,我们复制的是栈内存中的指针,也就是复制变量的指针的副本,复制后两个变量指向同一个对象,相信这一点也不难理解,惯例图表展现:

       Person p1 = new Person();

       p1.setName("复制前所赋值");

       Person p2 = p1;

       p2.setName("复制后所赋值");

       System.out.println(p2.getName());// 复制后所赋值      

 


 

.参数传递

    与变量复制一样,参数传递基础类型与引用类型也存在差异,java这门计算机语言中,非常多的书籍都会写到基础数据类型是值传递,而引用类型是引用传递,其实我赞同前半句,不过对后半句有异议,后面再谈,首先先来看看基础类型的值传递.

        在向参数传递基本类型的值的时候,被传递的变量的值会复制给函数的一个局部变量,局部变量所对应的内存中会参数被传递变量值的副本,所以当我们修改局部变量时被传递变量不会发生改变:

    public static int addNum(int num) {

           num += 100;

           return num;

    }

    int num = 10;

    int result = addNum(num);

    System.out.println("操作后的num :" + num); // 10

    System.out.println("结果result :" + result); // 110

       函数addNum()有一个参数num当我们使用变量num传入时,实际上是在addNum函数作用域内产生一个num局部变量,该局部变量的值是被传入参数值的副本,当我们修改局部变量时,外层变量不会发生改变,所以我们最后打印的时候外层变量仍然为10并没有受到函数参数自增100的影响。

    前面已经对引用类型参数传递的一些看法,下面我们先来看一个例子:

    public static void setName(Person p) {

   p.setName("作为参数后的值");

  }

  Person p = new Person();

  p.setName("作为参数前的值");

  setName(p);

  System.out.println(p.getName()); // 作为参数后的值

     从上面例子可以看出,当我们创建一个对象后,调用函数对对象的属性进行修改,发现函数外层的对象也跟着修改了,可以看出参数p与外层对象p指向的是堆内存中的同一个对象,换句话说,这应该是一个值传递,因为前面我们已经说过,在栈内存中引用类型变量保存的是堆内存中对应对象的地址,所以参数获得了一个被传递变量的指针类型副本,下面我们再来看一个例子

   public static void setName(Person p) {

        p.setName("操作前名称");

        p = new Person(); // 使参数指向新的堆地址

        p.setName("操作后的名称");

    }

    Person p = new Person();

    setName(p);

    System.out.println(p.getName()); // 操作前名称

    与前一个例子相比,我们在setName函数中先对参数p赋值,然后让参数p指向一个新的对象,再赋值,结果打印出来的信息是我们在使得参数P指向一个新的对象之前所做的操作,也就是说并没有修改原被传递参数的指针信息,所以同样为值传递(javascript也是一样的)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值