Java valueOf(int) 与 IntegerCache returns valueOf(1) 的值 3
Java valueOf(int) with IntegerCache returns value 3 for valueOf(1)
我遇到了 IntegerCache 的问题:
使用内部使用 iBatis PreparedStatement class.
的 iBatis 数据访问框架
像
一样调用数据库过程
{ call UPDATE_PROC(?,?,?,?,?,?) }
with params : [123, 234, 345, TEST1, 567, TEST2]
而 iBatis API 使用 :
设置第一个参数
typeHandler.setParameter(ps, i + 1, value, mapping.getJdbcTypeName());
i=0, value=123
这里ps是对PreparedStatement的引用,i是数据库过程中的参数索引。
内部调用
ps.setInt(i, ((Integer) parameter).intValue());
i=1, parameter=123 (Note : i is int not Integer)
在内部使用 Java 反射调用此调用 api :
public Object invoke(Object proxy, Method method, Object[] params) throws Throwable
method : setInt, params : [1, 123]
在为方法调用获取整数值 i 时,JVM 调用以下方法:
public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
IntegerCache.low = -128
IntegerCache.high = 127
IntegerCache.cache[i + (-IntegerCache.low)]
的值以 IntegerCache.cache[129]
结束 在整数缓存索引 [129] 处应该有值 1
但是当我调试代码时我发现值 3
在索引 [129] 处:
, -8, -7, -6, -5, -4, -3, -2, -1, 0, 3 **index[129]**, 2, 3 **index[131]**, 4, 5, 6, 7, 8, 9, 10, 11
因为 IntegerCache 是最终类型,所以不应有重复值,例如3 在索引 [129] 和 [131]
所以,我以例外结束:
java.sql.SQLException: Missing IN or OUT parameter at index:: 1
我的问题是这怎么可能?
请推荐
my question is how this can be possible?
某些代码可能会通过反射更改缓存实例的 Integer.value
字段。
是的,你是对的。得到了解决方案。
我认为 STS JVM 调试模式有问题。当我们更改 Integer 类型实例的原始 int 属性 的值时,它会覆盖 IntegerCache 值。
这不应该发生,因为下次我们请求相同的值时,它会给出覆盖的值。
使用以下代码在正常模式和调试模式下完成小型 POC,并且能够重现问题:
public class TestEclipseJVMDebugger {
public static void main(String[] argc) {
Integer i1 = new Integer(27);
int i2 = 7;
assert (-128 <= i1 && i1 <= 127);
assert (-128 <= i2 && i2 <= 127);
System.out.println("i1 = " + i1);
i1 = Integer.valueOf(i2);
System.out.println("i1 = " + i1);
System.out
.println("apply debug point here and change value of primitive data type of i1 to 666 from debug mode");
System.out.println("i1 = " + i1);
i1 = Integer.valueOf(i2);
System.out.println("i1 = " + i1);
}
}
我不知道为什么 Eclipse JVM 调试模式允许直接更新原始数据类型值,因为它们直接覆盖核心 JVM 的引用值类。
然后我认为 StringCache、DoubleCache 等也有同样的问题。
我遇到了 IntegerCache 的问题: 使用内部使用 iBatis PreparedStatement class.
的 iBatis 数据访问框架像
一样调用数据库过程{ call UPDATE_PROC(?,?,?,?,?,?) }
with params : [123, 234, 345, TEST1, 567, TEST2]
而 iBatis API 使用 :
设置第一个参数typeHandler.setParameter(ps, i + 1, value, mapping.getJdbcTypeName());
i=0, value=123
这里ps是对PreparedStatement的引用,i是数据库过程中的参数索引。
内部调用
ps.setInt(i, ((Integer) parameter).intValue());
i=1, parameter=123 (Note : i is int not Integer)
在内部使用 Java 反射调用此调用 api :
public Object invoke(Object proxy, Method method, Object[] params) throws Throwable
method : setInt, params : [1, 123]
在为方法调用获取整数值 i 时,JVM 调用以下方法:
public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
IntegerCache.low = -128 IntegerCache.high = 127
IntegerCache.cache[i + (-IntegerCache.low)]
的值以 IntegerCache.cache[129]
结束 在整数缓存索引 [129] 处应该有值 1
但是当我调试代码时我发现值 3
在索引 [129] 处:
, -8, -7, -6, -5, -4, -3, -2, -1, 0, 3 **index[129]**, 2, 3 **index[131]**, 4, 5, 6, 7, 8, 9, 10, 11
因为 IntegerCache 是最终类型,所以不应有重复值,例如3 在索引 [129] 和 [131]
所以,我以例外结束:
java.sql.SQLException: Missing IN or OUT parameter at index:: 1
我的问题是这怎么可能? 请推荐
my question is how this can be possible?
某些代码可能会通过反射更改缓存实例的 Integer.value
字段。
是的,你是对的。得到了解决方案。 我认为 STS JVM 调试模式有问题。当我们更改 Integer 类型实例的原始 int 属性 的值时,它会覆盖 IntegerCache 值。
这不应该发生,因为下次我们请求相同的值时,它会给出覆盖的值。
使用以下代码在正常模式和调试模式下完成小型 POC,并且能够重现问题:
public class TestEclipseJVMDebugger {
public static void main(String[] argc) {
Integer i1 = new Integer(27);
int i2 = 7;
assert (-128 <= i1 && i1 <= 127);
assert (-128 <= i2 && i2 <= 127);
System.out.println("i1 = " + i1);
i1 = Integer.valueOf(i2);
System.out.println("i1 = " + i1);
System.out
.println("apply debug point here and change value of primitive data type of i1 to 666 from debug mode");
System.out.println("i1 = " + i1);
i1 = Integer.valueOf(i2);
System.out.println("i1 = " + i1);
}
}
我不知道为什么 Eclipse JVM 调试模式允许直接更新原始数据类型值,因为它们直接覆盖核心 JVM 的引用值类。
然后我认为 StringCache、DoubleCache 等也有同样的问题。