新网创想网站建设,新征程启航
为企业提供网站建设、域名注册、服务器等服务
这篇文章主要介绍了Java基础之Integer使用的注意事项是什么,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。
10年积累的做网站、网站设计经验,可以快速应对客户对网站的新想法和需求。提供各种问题对应的解决方案。让选择我们的客户得到更好、更有力的网络服务。我虽然不认识你,你也不认识我。但先网站设计后付款的网站建设流程,更有宾川免费网站建设让你可以放心的选择与我们合作。
JAVA中Integer对象的引用
JAVA中没有指针一说,但也有引用的概念。这里要说的主要是Integer是不是同一个对象。
1、先看一段代码:
public static void main(String[] args){ Integer a1 = 100; Integer b1 = a1;//另一种也可以b1=100 Field field = null; try { field = a1.getClass().getDeclaredField("value"); } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } field.setAccessible(true); try { field.set(a1, 5000); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("b1="+b1); Integer c1 = 100; System.out.println("c1="+c1); }
结果:
b1=5000
c1=5000
从上面,首先这里要说明几个,
1)、对于Integer来说,-128-127之间的整型已经初始化放在IntegerCache中,如果是装箱的话,就会从这里面取对象。
2)、b1=a1到底是数字赋值还是同一个对象?这个从结果实际就可以看出来,b1和a1指向同一个对象,而不是同一个数值
3)、c1=100,说明对于-128-127之间的数值,都是从IntegerCache中获取的对象,100对应的Integer对象被改变后,后续对于100的装箱都被改变。因为获取cache中对象时用的是数组索引,而不是数值比较获取的。
不过修改这个缓存会比较危险,不介意。谁知道什么jar包或者什么平台来个100的装箱,但得到结果又不是100,到时就崩溃了。
2、通过上面描述,那么如果改成这样又是什么答案
public static void main(String[] args){ Integer a1 = 200; Integer b1 = a1; Field field = null; try { field = a1.getClass().getDeclaredField("value"); } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } field.setAccessible(true); try { field.set(a1, 5000); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("b1="+b1); Integer c1 = 200; System.out.println("c1="+c1); }
3、那么再改一下
public static void main(String[] args){ Integer a1 = new Integer(100); Integer b1 = a1; Field field = null; try { field = a1.getClass().getDeclaredField("value"); } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } field.setAccessible(true); try { field.set(a1, 5000); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("b1="+b1); Integer c1 = 100; System.out.println("c1="+c1); }
这又是什么答案。对于new的操作,是不进行装箱的,而是在堆中生成对象的。
理解了装箱、缓存、引用就不难理解了。可以自己试试。
先来点基础的知识
基本类型和包装类的对应 byte Byte short Short int Integer long Long float Float double Double char Character boolean Boolean
上述的八中基本数据类型的对应关系只有 int->Integer char->Character 两个变化较大,其余都只是将首字母转换为小写。
再来了解一下JDK5的新特性:自动装箱和拆箱
自动装箱:把基本类型转换为包装类类型
自动拆箱:把包装类类型转换为基本类型
public class Demo_Integer { public static void main(String[] args) { //JDK1.5之前 int a = 100; Integer a1 = new Integer(a); //将基本数据类型包装成对象,装箱 int b = a1.intValue(); //将对象转换为基本数据类型,拆箱 //JDK1.5之后 int x = 100; Integer x1 = x; //自动装箱,把基本数据类型转换为对象 int y = x1 + x; //自动拆箱,把对象转换为基本数据类型 } }
注意事项
public class Demo_Integer { public static void main(String[] args) { Integer a = null; int b = a + 100; //自动拆箱底层将会调用a.intValue(),a为null,自然会抛出 NullPointerException System.out.println(b); } }
面试题
public class Demo_Integer { public static void main(String[] args) { Integer i1 = new Integer(97); Integer i2 = new Integer(97); System.out.println(i1 == i2); System.out.println(i1.equals(i2)); System.out.println("-----------"); Integer i3 = new Integer(197); Integer i4 = new Integer(197); System.out.println(i3 == i4); System.out.println(i3.equals(i4)); System.out.println("-----------"); } }
Output: false true ----------- false true -----------
原因:
new 是在堆内存开辟空间的,自然比较地址值(==)都为false.
由于Integer重写了equals方法,所以equals输出都为true.
你可能感觉太简单了,没有任何技术含量,因为上面的不是重点,看下面代码
public class Demo_Integer { public static void main(String[] args) { Integer i1 = 127; Integer i2 = 127; System.out.println(i1 == i2); System.out.println(i1.equals(i2)); System.out.println("-----------"); Integer i3 = 128; Integer i4 = 128; System.out.println(i3 == i4); System.out.println(i3.equals(i4)); System.out.println("-----------"); } }
Output: true true ----------- false true -----------
原因:
为什么当int大于127就是两个对象,127这个数字是不是觉得很熟悉?
-128到127是byte的取值范围,如果在这个取值范围内,自动装箱就不会创建新对象了,而从常量池中获取
超过了byte的取值范围就会在创建新对象
自动装箱其底层会调用valueOf()方法,简单源码分析(JDK1.8):
public final class Integer extends Number implements Comparable{ public static Integer valueOf(int i) { //当 i >= -128 且 i <= 127 时,会直接将取缓冲区中的对象 if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i);//超过了byte取值范围会在堆内存创建 } //内部类充当缓冲区 private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} } }
8种基本类型的包装类和对象池
java中基本类型的包装类的大部分都实现了常量池技术,这些类是Byte,Short,Integer,Long,Character,Boolean,另外两种浮点数类型的包装类则没有实现。另外Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值小于等于127时才可使用对象池,也即对象不负责创建和管理大于127的这些类的对象
扩展知识
在jvm规范中,每个类型都有自己的常量池。常量池是某类型所用常量的一个有序集合,包括直接常量(基本类型,String)和对其他类型、字段、方法的符号引用。之所以是符号引用而不是像c语言那样,编译时直接指定其他类型,是因为java是动态绑定的,只有在运行时根据某些规则才能确定具体依赖的类型实例,这正是java实现多态的基础。
在JVM中,类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载7个阶段。而解析阶段即是虚拟机将常量池内的符号引用替换为直接引用的过程。
感谢你能够认真阅读完这篇文章,希望小编分享的“Java基础之Integer使用的注意事项是什么”这篇文章对大家有帮助,同时也希望大家多多支持创新互联,关注创新互联行业资讯频道,更多相关知识等着你来学习!