问一个基础java问题,不要小看,或许你也没理解

mrvoce 发布于 2012/02/04 16:18
阅读 737
收藏 7

public static final Map<String, String> BEANS = new HashMap<String, String>();

 

为什么BEANS仍然可以put,如果是String、Integer等基本类型或者他的包装类就无法改值(而且无法编译),告诉为什么呢?

加载中
0
seaside_hi
seaside_hi

Map 是引用类型,final 修饰符表示它的地址是不可改变,但是里面的值是可以改变的。

Wrapped 类型的数值 比如 Integer,Boolean 你这么写

 

private static final Integer intValue = 10;
intValue = 25;
//以这个为例,Integer 是包装类型//自从jdk1.5之后 就支持自动装箱和拆箱
//所以这段代码等同于 intValue = new Integer(25) 
//这样引用改变了(改变了堆栈的地址)当然会出现错误
//我还知道Integer 有一个包装馅饼(在在128-1之间如果两个值相同会引用同样的地址)
Integer oneValue = 15;
Integer twoValue = 15;
System.out.println(oneValue==twoValue)
//这样会输入true   
//在包装馅饼的范围(在128-1之间) 指向同一个地址
Integer oneValue = 200;
Integer twoValue = 200;
System.out.println(oneValue==twoValue)
//这样会输出false 
//超出包装馅饼的范围,他会创建两个对象
//其他包装类型应该也会有,不过需要你自己去发掘(这个没有什么用,都用equals,因为馅饼也是陷阱)
如果以上成立,那么 
private static final Integer intValue =100;
intValue = 100  
这样也应该成立 

  

private static final String strValue  = "abc";

strValue ="bcd" 
//不允许,因为这样完全等于 strValue = new String("abc") 

所以String 也是会出现错误的

seaside_hi
seaside_hi
@烟头 : 但是你注意,我上面的代码是这么写的 private static final String strValue ="abc"; strValue = "bcd" 他们两个值不相等,所以是两个不同的对象。 以此推断就等同于 new String()
seaside_hi
seaside_hi
@烟头 : 这个也是关于缓存池的问题,String,Integer他们都有相应的缓存池,你可以查看源码。 String s="a",String b="b"他们两个相同,因为把他在共享缓存池里面
烟头
烟头
strValue ="bcd" //不允许,因为这样完全等于 strValue = new String("abc") 这句是错误的,strValue ="bcd"不等于 strValue = new String("abc") 前者不会新建对象,而是用原有对象。你可以测试下==是否相同
六只
六只
不错,Map的确实容易想到。但是包装类还真不知道。长进了。顶。
0
AntMaster
AntMaster
楼上正解!!
0
一剑倾城
一剑倾城
标题很有个性……
0
seaside_hi
seaside_hi

引用来自“苏毅”的答案

Map 是引用类型,final 修饰符表示它的地址是不可改变,但是里面的值是可以改变的。

Wrapped 类型的数值 比如 Integer,Boolean 你这么写

 

private static final Integer intValue = 10;
intValue = 25;
//以这个为例,Integer 是包装类型//自从jdk1.5之后 就支持自动装箱和拆箱
//所以这段代码等同于 intValue = new Integer(25) 
//这样引用改变了(改变了堆栈的地址)当然会出现错误
//我还知道Integer 有一个包装馅饼(在在128-1之间如果两个值相同会引用同样的地址)
Integer oneValue = 15;
Integer twoValue = 15;
System.out.println(oneValue==twoValue)
//这样会输入true   
//在包装馅饼的范围(在128-1之间) 指向同一个地址
Integer oneValue = 200;
Integer twoValue = 200;
System.out.println(oneValue==twoValue)
//这样会输出false 
//超出包装馅饼的范围,他会创建两个对象
//其他包装类型应该也会有,不过需要你自己去发掘(这个没有什么用,都用equals,因为馅饼也是陷阱)
如果以上成立,那么 
private static final Integer intValue =100;
intValue = 100  
这样也应该成立 

  

private static final String strValue  = "abc";

strValue ="bcd" 
//不允许,因为这样完全等于 strValue = new String("abc") 

所以String 也是会出现错误的

刚才我尝试了 在jdk1.6的环境下无法编译这段代码

private static final Integer intValue =100;

intValue = 100  

虽然是在理论上地址是没有改变的,但是java虚拟机认为这是一个错误的操作

seaside_hi
seaside_hi
@Java行者 : 你好,我个人理解的是 Integer有一个共享的数据池(-128-128) 如果在这个池范围以内比如 Integer intValue1 = 100 , intValue2=100 ; 那么 intValue1 ==intValue2 是成立的 这就进一步说明他们两个的地址是一个样
douglarek
douglarek
你这样理解的不正确,虽然都是100,但是Interger是个对象类型,会执行自动装箱的操作,实际上是指向不同的对象!
0
六只
六只
额,先占个位置,等杂家看了源码,看看能不能看出端倪再来回复。
0
烟头
烟头

final类型的不能改变地址,但可以改变地址指向的值。

 

而String,Integer是不可变类(比如String.replace实际上是生成一个新的String而不会改变原有值)

HashMap是可变类,put,clear等等,但由于是final的,地址不能改变(也就是不能再写map =  new HashMap())

 

 

0
无著方知尘亦珍
无著方知尘亦珍
。。。还以为是什么大事,理解下这些概念就知道了:引用类型,值类型,语法糖,对象池,无状态和有状态对象。
返回顶部
顶部