在平时的开发中,声明一个数字类型的变量,一般有以下几种形式:
int a = 1;
Integer b = 1;
Integer c = new Integer(1);
Integer d = Integer.valueOf(1);
int类型为基本数据类型,a指向的是一个字面量,不是类的对象实例,它是编译期可知的。b、c、d一样,都是指向的类对象实例的引用。
上面这段代码编译后的class文件,用javap命令解析后,可以看到字节码指令如下:
Code:
Stack=3, Locals=5, Args_size=1
//将int型值1推至栈顶
0: iconst_1
//将栈顶的int型值放入本地变量表中的第二个
1: istore_1
//将int型值1推至栈顶
2: iconst_1
//调用java.lang.Integer的静态方法valueOf(java.lang.Integer),参数是栈顶的元素,并将返回值放入栈顶
3: invokestatic #16; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
//将栈顶的引用类型值放入本地变量表中的第三个
6: astore_2
//创建一个Integer对象
7: new #17; //class java/lang/Integer
//将该对象的引用压入栈顶
10: dup
//将int型值1推至栈顶
11: iconst_1
//调用java.lang.Integer类的初始化方法,该方法参数是栈顶的int型元素,返回值放入栈顶
12: invokespecial #22; //Method java/lang/Integer."<init>":(I)V
//将栈顶的引用类型值放入本地变量表中的第四个
15: astore_3
//将int型数值1压制栈顶
16: iconst_1
//调用java.lang.Integer的静态方法valueOf(java.lang.Integer),参数是栈顶的元素,并将返回值放入栈顶
17: invokestatic #16; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
//将栈顶的引用类型值放入本地变量表中的第四个
20: astore 4
22: return
通过分析上面的java字节码,可以印证开始的b/c/d都是指向Integer类的对象实例的论证。
但是又有了下面的问题:
System.out.println(a == b);
System.out.println(a == c);
System.out.println(a == d);
System.out.println(b == c);
System.out.println(b == d);
System.out.println(c == d);
输出是:
true
true
true
false
true
false
可见,a与bcd都相等而bc、cd不相等,bc相等,这是为什么呢?
首先,a与bcd都相等,这是常识了。当和包装类对比的对象是其对应的基本类型时,包装类会自动拆箱成基本数据类型与之对比。而bcd都是对象,相互对比的话,自然就是对比的引用地址了,由此,因为c是new Integer的操作,所以bc、cd不相等也是很显而易见的,那为什么bd是相等的呢?
我们可以在编译后的字节码的分析中看到,b和d的初始化过程是一样的,都是调用了Integer的valueOf静态方法,难道这个方法里有乾坤?
public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}
上面是Integer类valueOf方法的源码。
代码中,首先根据参数值和IntegerCache.high值和-128做了对比,如果参数值在此范围内的话,则返回IntegerCache中的一个数组元素,否则,则返回一个新的Integer对象。
那如此看来,b和d初始化时,返回的都是IntegerCache的同一个数组元素值了?
再去看看IntegerCache。
private static class IntegerCache {
static final int high;
static final Integer cache[];
static {
final int low = -128;
// high value may be configured by property
int h = 127;
if (integerCacheHighPropValue != null) {
// Use Long.decode here to avoid invoking methods that
// require Integer's autoboxing cache to be initialized
int i = Long.decode(integerCacheHighPropValue).intValue();
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - -low);
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
}
private IntegerCache() {}
}
IntegerCache 是Integer类的私有静态内部类,有两个静态元素,int型的high和Integer数组cache[].分析源码可以看到,该类主要是在初始化的时候初始化cache[]数组,其大小是high-low+1,默认情况下,大小是256,元素数值范围是[-128,127],这不也是byte类型的数值范围么?如果在JVM启动的时候设置了java.lang.Integer.IntegerCache.high参数,则cache的大小及数值由integerCacheHighPropValue决定。
由此说明,b和d返回同一个实例论证成功,那么对于如下程序呢?
Integer e = 200;
Integer f = 200;
System.out.println(e == f);
这个是打印true还是false呢?不用说了吧~~
扩展一下,下面例子的打印呢?
Integer a = 1;
Integer b = 2;
Integer c = 3;
Integer d = 3;
Integer e = 321;
Integer f = 321;
Long g = 3L;
System.out.println(c == d);
System.out.println(e == f);
System.out.println(c == (a+b));
System.out.println(c.equals(a+b));
System.out.println(g == (a+b));
System.out.println(g.equals(a+b));
分享到:
相关推荐
当声明一个变量但未初始化时,每种基本数据类型都有其默认值: - 整型默认为`0` - 浮点型默认为`0.0` - 字符型默认为`\u0000`(空字符) - 布尔型默认为`false` 3. **包装类** Java为了便于操作基本数据类型...
5. **基本数据类型包装类**:Java中的每个基本数据类型都有对应的包装类,如Integer、Double等。这些包装类允许将基本类型转换为对象,以便在需要对象的地方使用,如Vector的`add()`方法。在示例中,`args`数组中的...
Java 语言提供了多种数据类型,包括基本数据类型和引用数据类型。基本数据类型包括整型、浮点型、字符型等,引用数据类型包括数组、类等。 11. 编译错误 编译错误是指在编译 Java 源代码时出现的错误,包括语法...
基本数据类型在Java中是非常基础的,但它们也可以通过包装类(如Integer、Double等)转化为对象,使得可以使用面向对象的方法进行处理。 在数据的输入和输出方面,Java提供了多种方式,例如Scanner类用于从控制台...
- 基本数据类型的性能优于对应的包装类。 2. **包装类的应用**: - 当需要将数据类型作为参数传递给集合框架(如`ArrayList`、`HashMap`)时,必须使用包装类。 - 包装类提供了更多的功能,如自动装箱和拆箱、...
- 当需要对基本数据类型进行装箱(即转换为对应的包装类对象)或拆箱(即从包装类中提取基本数据类型值)操作时,可以使用自动装箱和拆箱机制。 2. **类型转换**: - Java中存在自动类型转换和强制类型转换。 - ...
在5月29日的实验中,学生接触了Java的包装类,这些类是基本数据类型(如`int`、`byte`等)的引用类型对应。包装类提供了与基本数据类型相互转换的方法,例如`valueOf`。在源程序`LangDemo.java`中,`Byte`, `Short`...
自动拆箱和装箱是Java自动处理基本类型与其对应的包装类之间的转换过程。 在逻辑运算符中,&和&&有显著区别。&是逻辑与运算符,总是会评估两边的表达式;而&&是短路与运算符,如果左边表达式为false,右边的表达式...
Java为每种基本数据类型都提供了对应的包装类,这些包装类提供了更多的功能和方法。 ##### 2. 基本数据类型和包装类相互转换 基本数据类型和包装类之间可以通过自动装箱和拆箱进行转换。 ##### 3. 基本类型和...
14. Java的初始化和构造方法 静态初始化块(static initializer block)、实例初始化块、构造方法(constructor)是类初始化时执行的代码块。 15. Java的泛型(Generics) 使用泛型可以创建可重用的组件,并提供...
13. **包装器类型**:Java提供了8个包装类,分别是Byte、Short、Integer、Long、Float、Double、Character和Boolean,它们对应于8种基本数据类型。包装器类主要用于将基本类型转换为对象,便于在需要对象的地方使用...
- **装箱**:将基本数据类型转换为对应的包装类的过程称为装箱。例如,将`int`类型转换为`Integer`类型。 - **拆箱**:将包装类对象转换为基本数据类型的过程称为拆箱。例如,将`Integer`类型转换为`int`类型。 - **...
- 为了适应面向对象的需求,Java为每个基本数据类型提供了对应的包装类,如Byte、Short、Integer、Long、Float、Double、Boolean和Character。包装类除了可以保存null值,还提供了一些额外的方法,如比较、格式化等...
- **自动装箱/拆箱**:允许自动在基本类型和对应的包装类之间进行转换。 - **静态导入**:可以静态导入类中的静态成员,简化代码。 - **可变参数**:方法可以接受任意数量的同类型参数。 以上是Java的基础知识和...
6.1 基本数据类型的包装类 167 6.2 处理对象 170 6.2.1 打印对象和toString方法 170 6.2.2 ==和equals比较运算符 172 6.3 类成员 175 6.3.1 理解类成员 175 6.3.2 单例(Singleton)类 176 6.4 final修饰符 ...
- Java提供了基本数据类型(如`int`、`double`等)和包装类(如`Integer`、`Double`等)。虽然基本数据类型不是包装类的简写形式,但在实际使用中,包装类可以作为基本数据类型的替代品。 - `long`和`double`确实...
Java还支持自动拆装箱机制,这是Java编译器为程序员自动进行基本数据类型与对应的包装类之间的相互转换的过程。 Java中的方法覆盖和方法重载是面向对象编程中的重要概念。方法覆盖指的是子类对继承自父类的方法提供...
4. **数组**:学习如何声明、初始化和操作一维和多维数组,以及数组作为方法参数的传递。 5. **字符串处理**:熟悉String类的常用方法,如concat、substring、indexOf、replace等,并了解字符串是不可变的特性。 6...
- 封装类(Wrapper):为每个基本数据类型提供了对应的包装类,如Integer、Double等,支持与String的转换。 - 枚举(enum):Java的枚举类型用于定义一组固定值的常量集合。 - 泛型(Generics):提供类型安全的容器...