Java数据结构(2)-变量与对象

变量与对象是所有数据类型的底层,如果不能准确理解变量与对象,就无法准确理解各种数据类型。

识别变量与对象

看看以下代码中,哪些是变量,哪些是对象。
		int a = 1;
		int b = a;
		int c = 1;
		String x = new String();
		String y = x;
		String z = new String();
  • 基本类型变量:java中有8种基本类型,其首字母小写,如int。a、b、c都是基本类型变量。
  • 引用类型变量:除基本类型以外的变量都是引用类型变量,其首字母大写,如String。x、y、z都是引用类型变量。
  • 对象:代码中有两个new,创建了两个对象。其实这里还隐式创建了几个对象,以后再详解。现在只看表面的对象。

内存结构

下图是上述代码的变量和对象在内存中的存储情况。

  • 基本类型变量:在内存中直接存储其值。如a和c的值都为1,b = a表示将a的值复制给b,所以a==b==c。虽然它们的值相同,但是会占用三块不同的内存来保存。
  • 对象:代码中有两个new String(),无论它们的字符串值是否一样,都会创建两个不同的对象,占用两块不同的内存。
  • 引用类型变量:在内存中存储的是引用,它会指向一个对象。上面说了两个new String()是不同的对象,所以x和z指向两个不同的对象,它们在内存中存储的引用也必不相同。而y=x将y引用复制给x,x和y存储的引用相同,这个引用指向第一个对象,所以x==y!=z。

调试方法

为了证实以上内容,现在通过eclipse调试这段代码, 打开调试视图。


  • 基本类型:a、b、c的值都是1,它们相等。
  • 引用类型:x、y、z的值是引用,并不是图中的"",这里无视""。重点看括号里面的"标识",这就是引用变量所指向对象的唯一标识,可以把这个标识理解为引用变量真正的值。x和y的标识都是22,而z的标识为26,x==y !=z。

引用与对象

  • 在java中,经常通过引用来调用方法,比如z.length()。但这并不是调用z引用的length()方法,而是通过z来找到其引用的对象,然后再调用对象的length()方法。引用是指向对象的地址,它是没有方法的,只有对象才有方法。


  • 如果引用z被修改,指向了其他对象,此时在程序中将无法再找到标识为26的对象,这个对象只有等待被内存回收。


  • 如果对象被修改,假如x调用set方法修改了对象的一个参数值,那么y在调用get方法获取对象的这个参数时,得到的是修改后的结果,因为y指向的对象被x修改了,但是x和y本生并没有改变,仍然指向同一个对象,只是对象内部的参数发生了变化。


  • 如果引用被赋null值,如z = null,此时z调用任何方法都会报空指针异常,因为z已经找不到任何对象了,没有对象无法调用方法。注意,null是引用类型,指引用变量为null,而不是对象为null。对象要么不存在,而不可能为null。
  • Object abc = new String();这段代码到底是Object还是String类型?引用变量的类型主要是为了强制类型检查,在编码或编译时就发现可能的类型错误。在运行时引用变量的类型是没有意义的,此时真正使用的是对象,即String类型。参考java多态性。

引用变量的意义

既然在内存中已经存储了对象,为何还要再存储引用?是不是多余的?它的意义何在?

  • 一个对象可以有很多参数,每个参数又可以是一个对象。也就是说一个对象可以比一个引用大很多,创建和销毁引用的开销比对象要小的多。如spring单例模式,会在初始时创建一个单例对象,每次用户请求时,只需要创建该对象的引用,就可以通过引用来使用对象。而不需要每次都去创建和销毁对象。

  • 引用的内存长度是固定的,这一特性对java的大多数据结构都起着至关重要的作用。以后会讲,现在先测试一下其内存长度

引用的内存长度测试

	public static void main(String[] args){
		//m1是初始时 已经使用的内存数量,即总内存减可用内存
		long m1 = Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory();
		//创建一个10万String的数组,系统会按10万个引用变量的长度来分配内存
		String[] s = new String[100000];
		//m2再次记录分配内存后的 使用数量 
		long m2 = Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory();
		//输出m2-m1,即分配后的内存使用量减分配前的,结果就是为数组分配的内存数
		System.out.println(m2-m1);
	}
  • 执行这段代码,最终输出结果是400016,16是数组对象本生占用的内存,用来存储数组的信息。(400016-16)/100000=4,说明10万个引用变量,每一个的长度是4字节,和基本类型int是一样的。将String换成其他任何引用类型,结果不变。注意:java虚拟机划分不同的内存区域,这里统计的是堆区内存。而s等变量并不存储在堆区,不会被统计。
  • 根据不同内存配置及运行状况,测试结果可能有时会出现一定偏差,都是正常的。
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值