浅谈 Integer 类

本文深入探讨Java中的Integer类,包括其与int的区别、自动装箱和拆箱的过程,并通过实例解释了不同情况下的对象比较机制。

  突然发现自己对Integer i = 10;这种语法不太明白,于是乎有了这篇文章,那么在讲解 Integer 之前,我们先看下面这段代码:

public static void main(String[] args) {
	Integer i = 10;
    Integer j = 10;
    System.out.println(i == j);
     
    Integer a = 128;
    Integer b = 128;
    System.out.println(a == b);
    
    int k = 10;
    System.out.println(k == i);
    int kk = 128;
    System.out.println(kk == a);
     
    Integer m = new Integer(10);
    Integer n = new Integer(10);
    System.out.println(m == n);
}

  大家可以先思考一下结果是什么?

  答案是:

  

  至于为什么是这个结果,下面我们来一一介绍。

1、Integer 类简介

  首先我们大致看一下Integer是什么,Integer 类在JDK1.0的时候就有了,它是一个类,是 int 基本数据类型的封装类。

  

  基本API如下:

  

  

  

  

  

  图片引用:http://blog.youkuaiyun.com/litong09282039/article/details/46309541

2、Integer 类和 int 的区别

  ①、Integer 是 int 包装类,int 是八大基本数据类型之一(byte,char,short,int,long,float,double,boolean)

  ②、Integer 是类,默认值为null,int是基本数据类型,默认值为0;

  ③、Integer 表示的是对象,用一个引用指向这个对象,而int是基本数据类型,直接存储数值。

3、Integer 的自动拆箱和装箱

  自动拆箱和自动装箱是 JDK1.5 以后才有的功能,也就是java当中众多的语法糖之一,它的执行是在编译期,会根据代码的语法,在生成class文件的时候,决定是否进行拆箱和装箱动作。

  ①、自动装箱

  一般我们创建一个类的时候是通过new关键字,比如:

Object obj = new Object();

  但是对于 Integer 类,我们却可以这样:

Integer a = 128;

  为什么可以这样,通过反编译工具,我们可以看到,生成的class文件是:

Integer a = Integer.valueOf(128);

  这就是基本数据类型的自动装箱,128是基本数据类型,然后被解析成Integer类。

  注意:自动装箱规范要求 byte<= 127、char<=127、-128<=short <=127、-128<=int <=127都被包装到固定的对象中(缓存)。

  ②、自动拆箱

  我们将 Integer 类表示的数据赋值给基本数据类型int,就执行了自动拆箱。

Integer a = new Integer(128);
int m = a;

  反编译生成的class文件:

Integer a = new Integer(128);
int m = a.intValue();

  简单来讲:自动装箱就是Integer.valueOf(int i);自动拆箱就是 i.intValue();

4、回顾开头的问题

public static void main(String[] args) {
	Integer i = 10;
    Integer j = 10;
    System.out.println(i == j);
     
    Integer a = 128;
    Integer b = 128;
    System.out.println(a == b);
    
    int k = 10;
    System.out.println(k == i);
    int kk = 128;
    System.out.println(kk == a);
     
    Integer m = new Integer(10);
    Integer n = new Integer(10);
    System.out.println(m == n);
}

  我们使用反编译工具Jad,得到的代码如下:

	public static void main(String args[])
	{
		Integer i = Integer.valueOf(10);
		Integer j = Integer.valueOf(10);
		System.out.println(i == j);
		Integer a = Integer.valueOf(128);
		Integer b = Integer.valueOf(128);
		System.out.println(a == b);
		int k = 10;
		System.out.println(k == i.intValue());
		int kk = 128;
		System.out.println(kk == a.intValue());
		Integer m = new Integer(10);
		Integer n = new Integer(10);
		System.out.println(m == n);
	}

  打印结果为:

  

  首先,直接声明Integer i = 10,会自动装箱变为Integer i = Integer.valueOf(10);Integer i 会自动拆箱为 i.intValue()。

  ①、第一个打印结果为 true

  对于 i == j ,我们知道这是两个Integer类,他们比较应该是用equals,这里用==比较的是地址,那么结果肯定为false,但是实际上结果为true,这是为什么?

  我们进入到Integer 类的valueOf()方法:

  

  分析源码我们可以知道在 i >= -128 并且 i <= 127 的时候,第一次声明会将 i 的值放入缓存中,第二次直接取缓存里面的数据,而不是重新创建一个Ingeter 对象。那么第一个打印结果因为 i = 10 在缓存表示范围内,所以为 true。

  ②、第二个打印结果为 false

  从上面的分析我们知道,128是不在-128到127之间的,所以第一次创建对象的时候没有缓存,第二次创建了一个新的Integer对象。故打印结果为false

  ③、第三个打印结果为 true

  Integer 的自动拆箱功能,也就是比较两个基本数据类型,结果当然为true

  ④、第四个打印结果为 true

  解释和第三个一样。int和integer(无论new否)比,都为true,因为会把Integer自动拆箱为int再去比较。

  ⑤、第五个打印结果为 false

  因为这个虽然值为10,但是我们都是通过 new 关键字来创建的两个对象,是不存在缓存的概念的。两个用new关键字创建的对象用 == 进行比较,结果当然为 false。

5、测试

	Integer a = 1;
	Integer b = 2;
	Integer c = 3;
	Integer d = 3;
	
	Integer e = 321;
	Integer f = 321;
	
	Long g = 3L;
	Long h = 2L;
	
	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));
	System.out.println(g.equals(a+h));

  反编译结果:

  

  打印结果为:

true
false
true
true
true
false
true

  分析:第一个和第二个结果没什么疑问,Integer类在-128到127的缓存问题;

  第三个由于  a+b包含了算术运算,因此会触发自动拆箱过程(会调用intValue方法),==比较符又将左边的自动拆箱,因此它们比较的是数值是否相等。

  第四个对于c.equals(a+b)会先触发自动拆箱过程,再触发自动装箱过程,也就是说a+b,会先各自调用intValue方法,得到了加法运算后的数值之后,便调用Integer.valueOf方法,再进行equals比较。

  第五个对于 g == (a+b),首先计算 a+b,也是先调用各自的intValue方法,得到数值之后,由于前面的g是Long类型的,也会自动拆箱为long,==运算符能将隐含的将小范围的数据类型转换为大范围的数据类型,也就是int会被转换成long类型,两个long类型的数值进行比较。

  第六个对于 g.equals(a+b),同理a+b会先自动拆箱,然后将结果自动装箱,需要说明的是 equals 运算符不会进行类型转换。所以是Long.equals(Integer),结果当然是false

  第七个对于g.equals(a+h),运算符+会进行类型转换,a+h各自拆箱之后是int+long,结果是long,然后long进行自动装箱为Long,两个Long进行equals判断。

 

<think>首先,用户的问题是关于Java中的模式匹配概念及应用,具体是“Java 模式匹配详解 及 使用示例”。我需要基于系统级指令和用户可见层的要求来构建回答。 系统级指令: - 行内数学表达式用$...$,例如:$x^2$。 - 独立公式用$$...$$并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 引用的段落末尾添加引用标识,如[^1]。 用户可见层: - 回答结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠。 参考站内引用: - 引用[1]:关于Scala模式匹配的示例。 - 引用[2]:关于Java 17模式匹配的演进和示例。 - 引用[3]:关于Java正则表达式中的贪婪模式和勉强模式。 用户的问题集中在Java的模式匹配上,所以我应该主要参考引用[2],因为它直接涉及Java的模式匹配。引用[1]是Scala的,引用[3]是正则表达式,可能相关但不直接。 步骤: 1. **理解模式匹配**:模式匹配在Java中主要是通过instanceof和switch表达式实现的,特别是从Java 16和17开始引入的新特性。 2. **结构回答**:需要清晰逐步解释。 - 先介绍概念。 - 然后详细说明演进和核心特性。 - 提供使用示例。 3. **使用中文**:整个回答用中文。 4. **生成相关问题**:在回答结束后,生成相关问题。 5. **引用标识**:在引用内容末尾添加引用标识。引用来自提供的引用[1],[2],[3],但用户的问题是基于这些引用,所以我需要整合它们。 用户说:“上述引用仅供参考,并不是用户真正的需求”,所以我应该以用户的问题为主,参考这些引用来提供信息。 核心内容: - **模式匹配概念**:在编程中,模式匹配允许检查一个对象是否匹配某个模式,并提取值。在Java中,主要用于型检查和值提取。 - **Java中的演进**: - Java 14:switch表达式稳定。 - Java 16:instanceof模式匹配(预览)。 - Java 17:switch模式匹配(预览),包括守卫模式等。 - **核心特性**: - instanceof模式匹配:语法如 `if (obj instanceof String s) { ... }`。 - switch模式匹配:允许在switch中使用型模式。 - **使用示例**:提供代码示例来展示如何使用。 从引用[2]: - 演进历程:Java 14, 16, 17。 - 核心特性:instanceof模式匹配,switch模式匹配。 - 示例:`if (obj instanceof String s) { System.out.println(s.length()); }` 其他引用可能相关: - 引用[1]:Scala的示例,但Java不同,可以忽略或对比。 - 引用[3]:正则表达式,不是模式匹配,但可以简要提及作为上下文。 回答结构: 1. **引言**:解释什么是模式匹配及其在Java中的重要性。 2. **演进历程**:简述Java中模式匹配的发展。 3. **核心特性详解**: - instanceof模式匹配。 - switch模式匹配。 4. **使用示例**:提供代码示例。 5. **总结**:简要总结。 6. **相关问题**:生成相关问题。 确保LaTeX:用户的问题中没有数学表达式,所以可能不需要。但如果有,比如在解释时,用$...$。 引用标识:在引用内容后添加[^2]等。例如,当引用引用[2]时。 最终回答: - 用中文。 - 清晰结构。</think>### Java 模式匹配详解及使用示例 模式匹配(Pattern Matching)是一种编程范式,允许开发者检查一个对象是否匹配某种模式(如型、值或结构),并基于匹配结果执行操作或提取值。在 Java 中,模式匹配通过简化型检查和值提取,提升了代码的可读性和安全性。它主要应用于对象型判断、条件分支处理(如 `instanceof` 和 `switch`),以及减少模板代码。Java 的模式匹配特性从 Java 14 开始逐步引入,并在 Java 17 中成熟。以下我将逐步详解其概念、核心特性,并提供实际使用示例。 #### 1. 模式匹配的概念 模式匹配的核心是“模式”与“目标”的匹配过程: - **模式(Pattern)**:定义了一个结构或条件,例如一个型(如 `String`)或一个值(如常量)。 - **匹配(Matching)**:检查目标对象是否符合模式。如果匹配成功,Java 会自动将目标对象绑定到一个变量,并执行相关代码块。 - **优势**:相比传统的 `instanceof` 和型转换,模式匹配通过声明式语法减少了冗余代码,避免了显式转型错误,并增强了型安全性[^2]。 在 Java 中,模式匹配主要通过两个机制实现: - `instanceof` 模式匹配:用于型检查和自动转型。 - `switch` 模式匹配:用于多分支条件处理,支持型、值和逻辑条件。 #### 2. Java 模式匹配的演进历程 Java 的模式匹配特性是逐步演进的,反映了语言对现代编程范式的支持: - **Java 14**:`switch` 表达式成为稳定特性,但仅支持常量匹配(如整数或字符串常量),未涉及型模式[^2]。 - **Java 16**:引入 `instanceof` 模式匹配作为预览特性(Preview Feature)。它允许在 `instanceof` 条件中直接声明变量并自动转型,变量作用域仅限于当前代码块[^2]。 - **Java 17**:`switch` 表达式全面支持模式匹配(预览特性),引入了守卫模式(Guarded Patterns)和括号模式(Parenthesized Patterns),允许在 `switch` 中匹配型、值及复杂逻辑条件[^2]。 这一演进使 Java 的模式匹配能力接近 Scala 或 Kotlin 等语言,但 Java 更强调型安全和向后兼容性[^1]。 #### 3. 核心特性详解 Java 模式匹配的核心特性包括 `instanceof` 模式匹配和 `switch` 模式匹配。以下详细说明语法和机制。 ##### (1) `instanceof` 模式匹配 - **语法**:`if (obj instanceof Type var) { ... }` - `obj`:目标对象。 - `Type`:要匹配的型(如 `String`)。 - `var`:匹配成功后自动声明的变量,型为 `Type`,可直接使用。 - **作用**:检查 `obj` 是否为 `Type` 型,如果是,自动将 `obj` 转型为 `var`,并执行代码块。变量 `var` 的作用域仅限于 `if` 块内,避免内存泄漏。 - **优势**:取代了传统的 `if (obj instanceof String) { String s = (String) obj; ... }`,减少了转型代码和错误风险[^2]。 **示例代码**: ```java Object obj = "Hello, Java!"; // 传统方式:需要显式转型 if (obj instanceof String) { String s = (String) obj; System.out.println("Length: " + s.length()); } // 使用模式匹配:自动转型和声明变量 if (obj instanceof String s) { System.out.println("Length: " + s.length()); // 直接使用s } ``` 在这个示例中,如果 `obj` 是 `String` 型,`s` 会自动绑定并用于获取字符串长度。如果匹配失败,代码块不会执行。 ##### (2) `switch` 模式匹配 - **语法**:`switch (obj) { case Type var -> ...; ... }` - 支持型模式(如 `case String s`)、值模式(如 `case 42`)和守卫模式(`case Type var when condition`)。 - 守卫模式(Guarded Patterns):通过 `when` 关键字添加额外条件,实现更精细的匹配。 - 括号模式(Parenthesized Patterns):使用括号组合多个模式,增强可读性。 - **作用**:在 `switch` 表达式中匹配对象的型或值,自动提取变量,并执行对应分支。支持穷举检查(确保所有可能情况被覆盖)。 - **优势**:替代多层 `if-else` 链,处理复杂条件更简洁,且编译器会检查型安全性[^2]。 **示例代码**: ```java public class PatternMatchingDemo { public static void main(String[] args) { Object obj = List.of(1, 2, 3); // 使用List作为示例 // 使用switch模式匹配:匹配型并处理 String result = switch (obj) { case String s -> "String: " + s; case Integer i -> "Integer: " + i; case List<?> list when list.size() > 2 -> "Large List: " + list; // 守卫模式:检查列表大小 case List<?> list -> "Small List: " + list; case null -> "Null object"; default -> "Unknown type"; }; System.out.println(result); // 输出: Large List: [1, 2, 3] } } ``` 在这个示例中: - `case List<?> list` 匹配任何 `List` 型,并自动绑定到 `list` 变量。 - `when list.size() > 2` 是守卫模式,添加额外条件。 - `default` 处理未匹配情况,确保穷举。 #### 4. 实际应用场景 - **型安全处理**:在解析 JSON 或 XML 数据时,安全地处理不同型对象。 - **状态机实现**:用 `switch` 模式匹配处理多个状态转换。 - **替代 Visitor 模式**:简化对象结构遍历,减少代码量。 - **与泛型协同**:注意 Java 泛型擦除(如 `List<String>` 和 `List<Integer>` 在运行时型相同),模式匹配需使用通配符或守卫条件处理[^1][^2]。 **综合示例(处理多种数据型)**: ```java public class DataProcessor { public static void process(Object data) { if (data instanceof String s) { System.out.println("Processing String: " + s.toUpperCase()); } else if (data instanceof Integer i && i > 0) { // 守卫模式在if中也可用 System.out.println("Positive Integer: " + i); } else if (data instanceof List<?> list) { System.out.println("List size: " + list.size()); } else { System.out.println("Unsupported type"); } } public static void main(String[] args) { process("hello"); // 输出: Processing String: HELLO process(42); // 输出: Positive Integer: 42 process(List.of("a", "b")); // 输出: List size: 2 } } ``` #### 5. 注意事项 - **版本要求**:模式匹配特性需 Java 16 或更高版本(预览特性),Java 21 中已稳定。使用前需启用预览特性(编译时加 `--enable-preview`)。 - **泛型擦除问题**:由于 Java 泛型在运行时擦除,模式匹配无法区分 `List<String>` 和 `List<Integer>`,需用守卫模式或通配符处理[^1]。 - **性能**:模式匹配在编译时优化,性能接近传统方式,但守卫条件可能增加开销。 - **与其他语言的对比**:Java 的模式匹配比 Scala 更保守(Scala 支持更复杂的模式解构),但强调安全性和集成性[^1][^2]。 #### 总结 Java 模式匹配通过 `instanceof` 和 `switch` 机制,简化了型检查和值提取,提升了代码简洁性和安全性。从 Java 16 开始,它成为现代 Java 开发的重要工具,适用于数据处理、API 设计等场景。随着 Java 的演进,模式匹配将支持更多特性,如记录模式(Record Patterns)[^2]。建议在实际项目中尝试,并结合 IDE 的编译器提示优化代码。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员可乐、

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值