java的类型分两部分,基本类型和引用类型。并且,每个基本类型都对应了一个引用的类型,称为装箱基本类型。
如Integer 对应int,Double对应的double.
两者的主要区别有三:
- 基本类型只有值,而装箱类型则有与他们的值不同的同一性,也就是两个装箱类型可以具有相同的值,有不同的同一性(不同的引用)
- 基本类型只有功能完备的值,而每个装箱类型除了它对应基本类型的所有功能值外,还有个非功能的值--null
- 基本类型通常比装箱类型更节省时间和空间。
首先看装箱类型的同一性,自己写的一个比较函数代码如下:
// 比较器
public int myCompare(Integer first, Integer second) {
return first < second? -1 : (first==second ? 0 : 1);
}
该函数用来表示Integer值的递增数字顺序。若第一个参数是小于,等于 或者大于它的第二个参数,则该方法返回负数,0或者正数.
但是该函数并不能正常的工作,当你调用 myCompare(new Integer(44), new Integer(44)),时,函数返回1.
但我们期待的是0。
原因是进行first<second比较时,系统自动对两个Integer对象被进行了自动拆箱,提取了基本类型的值,经过比较44<44不成立,则进行first==second的比较,这时系统进行的是同一性的比较,也就是比较两个包装类的引用,很明显不是同一个引用,所以函数返回1.
结论:对包装类用==操作符几乎总是错误的.
修改的方法是 新增加两个局部的值类型变量来替换。
public int myCompare(Integer first, Integer second) {
// 使用两个基本类型来转化,避免进行对象的同一性比较
/* int f = first;
int s = second;
return f < s ? -1 : (f == s ? 0 : 1);*/
return first < second? -1 : (first==second ? 0 : 1);
}
再看下面的代码:
Integer i1 = 100; //自动装箱
Integer i2 = 100;
int j = 100;
System.out.println(i1 == i2);
System.out.println(i1 == j);
Integer i3 = 128; //自动装箱
Integer i4 = 128;
int k = 128;
System.out.println(i3 == i4);
System.out.println(i4 == k);
以上代码分别输出结果是什么?
输出的结果是 true,ture,false,true
对于i1和i2的结果,我们很清楚明白,但是对于i3==i4的比较,为什么为false?
当将一个int值赋值给它的一个Integer包装类型变量时,Integer类型调用了valueOf方法:
public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache
return IntegerCache.cache[i + offset];
}
return new Integer(i);
如果这个值在-128和127之间,则将该值进行了缓存处理,在内存中都是指向的一个包装类型对象.
也就是
Integer i1=100;
Integer i2=100;
Integer i3=100;
Integer i4=100;
...
Integer i100=100;
这些所有的Integer对象都是指向同一个对象地址空间的。
但是超过了这个区间,则分别创建的是不同的Integer对象.
查看IntegerCache中引用cache这个变量的部分:
private IntegerCache(){}
static final Integer cache[] = new Integer[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Integer(i - 128);
}
由于cache[]在IntegerCache类中是静态数组,也就是只需要初始化一次,即static{......}部分,所以,如果Integer对象初始化时是-128~127的范围,就不需要再重新定义申请空间,都是同一个对象---在IntegerCache.cache中,这样可以在一定程度上提高效率。
看另外的个例子:
static Integer i;
public void unbelieve() {
if (i == 42) { // 这里将抛出空指向异常 因为自动装箱和拆箱的缘故,建议修改i的定义为int 或者和new
// Integer(42)包装类型来比较
System.out.println("不敢相信");
}
这里不会输出"不敢相信",系统会报告NullPointerException异常。因为i被初始化为null,使用(i==42)时,因为i是Integer 类型,当包装类型和基本类型进行比较时,包装类型则会被自动拆箱,但i是一null,null对象引用被自动拆箱,则会得到一个NullPointerException异常。
修改的方法是将i定义为int或者将其和包装类进行比较,但同样要注意上面提到的-128~127这个区间的问题
另外一个关于性能的问题,看如下代码:
public static void main(String args[]){
Long sum=0L;
for(long i=0;i<Integer.MAX_VALUE;i++){
sum=+i;
}
System.out.println(sum);
}
这个程序中的的局部变量 sum 被声明为装箱类型Long,不是基本类型long,虽然编译和运行没有任何错误。但明显的,其在运行中被反反复复的装箱和拆箱,严重影响了性能。
分享到:
相关推荐
注意,这些知识虽然源自2010年的资料,但许多基础概念在现代Java编程中仍然适用。随着Java版本的更新,某些细节可能有所变化,比如内存管理机制和新的语法特性,学习时应结合最新版本的文档和教程。
Java编程思想笔记 本笔记涵盖了Java编程思想的多个方面,包括访问权限控制...本笔记涵盖了Java编程思想的多个方面,包括访问权限控制、封装、继承、多态、接口、内部类、持有对象等,提供了Java编程的基本概念和技术。
- 对于基本类型的包装类型,比较时应使用`equals()`而不是`==`。 - 示例:`Integer a = 1; Integer b = 1; System.out.println(a.equals(b));` **16. String和基本类型的相互转换** - `String`到整型:`Integer....
集合是Java编程语言中用于存储和操作多个元素的一种容器。它提供了动态管理元素的能力,允许在运行时添加或删除元素。 **1.2 集合与数组** - **区别**: - **灵活性**:集合的大小可以动态改变,而数组一旦创建其...
在 Java 语言中,还有另外一种基本类型 void,它也有对应的包装类 java.lang.Void,但是我们无法直接对它们进行操作。 Java 语言支持一些特殊的转义字符序列,例如 \n 代表换行、\r 代表回车、\f 代表换页符、等等...
### JAVA编程思想笔记 #### 一、编程语言与Java特性 1. **编程语言类别**: - **机器语言**:直接与硬件交互的语言,由0和1组成。 - **汇编语言**:接近机器语言,使用助记符表示指令。 - **高级语言**:更接近...
- **自动装箱/拆箱**:允许自动在基本类型和对应的包装类之间进行转换。 - **静态导入**:可以静态导入类中的静态成员,简化代码。 - **可变参数**:方法可以接受任意数量的同类型参数。 以上是Java的基础知识和...
《Java核心编程》笔记 ...以上只是Java核心编程笔记的一部分内容,实际的学习过程中还需要深入理解类库的使用,如异常处理、多线程、网络编程、反射、注解等,并结合实际项目经验,才能真正掌握Java编程的核心技巧。
- Java是一种广泛使用的高级编程语言,由Sun Microsystems于1995年发布。 - Java的设计目标是“一次编写,到处运行”,这得益于其跨平台特性和虚拟机机制。 - Java具有自动内存管理、面向对象、安全性高等特点。 ...
本笔记基于第5版第一部分(I)进行整理,旨在帮助读者深入理解和掌握Java编程的基础知识。 1. **Java环境搭建**:首先,我们需要安装Java Development Kit (JDK),设置好环境变量,包括JAVA_HOME、PATH和CLASSPATH...
- 包装类的作用:将基本类型包装为对象。 - 常用包装类:Integer、Double等。 - **匿名内部类** - 匿名内部类的定义:没有名称的内部类。 - 匿名内部类的应用场景:实现接口或继承抽象类。 #### 第七章:异常的...
- **自动装箱/拆箱**:JDK6引入了自动装箱和拆箱功能,使得基本类型和其包装类之间的转换更加便捷。 - **可变参数**:允许一个方法接受不定数量的参数,增强了方法的灵活性。 - **增强的for循环(foreach)**:...
在Java编程中,IO(Input/Output)操作是处理数据输入与输出的核心技术。Java-IO操作共19页的笔记详细介绍了这一关键领域,旨在帮助开发者掌握如何有效地读取、写入和管理数据。Java IO API提供了一套丰富的类和接口...
- Java中一切皆为对象,包括基本数据类型也是通过包装类实现的。 - **继承、组合、实现、多态**: - 继承表示类之间的层次关系。 - 组合表示类之间的整体-部分关系。 - 实现通常指接口的实现。 - 多态允许子类...
Java JDK6学习笔记是针对Java编程语言初学者和进阶者的一份宝贵资源,它涵盖了Java的基础语法,并通过经典且易于理解的实例进行讲解。在本文中,我们将深入探讨Java JDK6中的关键概念和特性,以帮助你更好地理解和...
### JAVA程序员面试宝典笔记总结 #### 1. JDK与JRE - **JDK (Java Development Kit)**:这是Java开发...此外,熟悉不同数据类型的特点、了解C++与Java之间的差异也有助于更好地理解和掌握Java编程语言的核心概念。
《Thinking in Java》是Bruce Eckel的经典之作,这本书深入探讨了Java编程的各个方面。以下是根据提供的部分内容提炼出的一些核心知识点: 1. **访问修饰符**: - `public`:公共访问修饰符,允许所有类访问。 - ...
本篇“Java学习速成笔记”旨在帮助读者在短期内快速掌握Java编程的核心概念和技术要点,并能够在学习后的七天内具备基本的工作能力。该笔记内容详实,既适合零基础的新手,也适合有一定编程经验但希望快速上手Java的...