深圳大鹏住房和建设局网站织梦企业网站
2026/2/26 4:03:53 网站建设 项目流程
深圳大鹏住房和建设局网站,织梦企业网站,百度推广价格表,望江县住房和城乡建设局网站一、包装类 1.1 基本类型的痛点 Java 是一种面向对象的语言#xff0c;但为了性能#xff0c;保留了 int、double 等 8 种基本数据类型。然而#xff0c;Java 的集合框架#xff08;如 ArrayList#xff09;要求所有存入的元素必须是对象#xff08;引用类型#xff09;…一、包装类1.1 基本类型的痛点Java 是一种面向对象的语言但为了性能保留了 int、double 等 8 种基本数据类型。然而Java 的集合框架如 ArrayList要求所有存入的元素必须是对象引用类型。这就导致了一个问题我们无法直接写 List因为 int 不是对象。1.2 包装类的登场为了解决这个问题Java 给每种基本类型都提供了一个对应的包装类基本数据类型特殊情况intIntegerCharCharacter其余首字母大写1.3自动装箱和拆箱装箱基本类型→\rightarrow→包装类。编译器自动调用Integer。valueOf(520);拆箱包装类→\rightarrow→基本类型。编译器自动调用int num a.intValue();1.4面试题public static void main(String[] args) { Integer a 127; // 走数组 Integer b 127; System.out.println(a b); // true同一对象 Integer c 128; // 超出数组 Integer d 128; System.out.println(c d); // false两次 new }Java 为了性能对 Integer 做了缓存优化。JVM 在启动时把 -128 到 127 这 256 个整数提前做成对象并放进数组以后只要自动装箱的值落在这个区间就直接把数组里现成的对象给你不再 new。如果数值在 -128 到 127 之间自动装箱时会直接使用缓存池中的对象所以 a 和 b 是同一个对象。如果超出这个范围如 128每次都会 new 一个新对象地址自然不同。缓存只影响 比较代码里比较包装类一律用 equals()就行记忆 比“是不是同一个人”equals() 比“长得是不是一样”。二、泛型2.1为什么要有泛型泛型Generics就是参数化类型。它就像给容器贴了一个标签告诉编译器“我这里只能装这种东西别乱放。”ArrayListInteger 就是贴了“只能装整数”标签的瓶子。没有泛型之前取数据时必须强制类型转换如 (String) obj同时编译器不检查类型万一你把 int 强转成 String运行时会报ClassCastException2.2语法占位符 T定义类时我不知道将来要存什么先用 T (Type) 占个座。class MyArrayT { // T 标志这是一个泛型类 public void set(T val) { ... } public T get() { ... } }2.3 类型擦除泛型最核心的原理JVM 根本就不认识泛型。编译时编译器进行严格的类型检查。class MyArrayT { T data; }编译后泛型信息被擦除。所有的 T都会被替换成 Object或者指定的上界。class MyArray { Object data; // T 变成了 Object }这意味着ArrayList 和 ArrayList 在运行时的类是完全一样的都是 ArrayList。三、泛型的通配符难泛型虽然好用但它是不兼容的。3.1引进即便 Apple 是 Fruit 的子类ListApple 也不是 ListFruit 的子类。接下来讲解一下定义一个方法参数是 ListFruit调用这个方法试图传入 ListApple它的参数声明是 ListFruit意味着它接收一个装水果的列表。// 这是一个接收“水果表”的方法 public static void processFruits(ListFruit fruits) { // 因为参数声明是 ListFruit // 所以在方法内部Java 允许我往里 add 任何 Fruit 的子类 // 比如这里我合法的 add 了一个香蕉 fruits.add(new Banana()); }你手里有一个 List你想把它传给上面的方法。public static void main(String[] args) { // 1. 创建一个只能装苹果的 List ListApple appleList new ArrayList(); appleList.add(new Apple()); // 2. 【报错发生在这里】 // 你想把 appleList 传给 processFruits 方法 // processFruits(appleList); 报错 }我们看上面代码的冲突点1.看 processFruits 方法内部它拥有写入权限调用了 fruits.add(new Banana())。这是完全合法的因为它的参数类型是 ListFruit水果列表当然可以加香蕉。2.看 main 方法你传入的是 appleList苹果列表。如果 Java 允许你传进去那么 processFruits 方法里的那句 add(new Banana())实际上就是在往你的苹果列表里塞香蕉。总结方法定义方 (ListFruit) 说我有权利往里放任何水果包括香蕉。方法调用方 (ListApple) 说我只能装苹果绝对不能混进香蕉。这两个承诺是冲突的。为了防止 processFruits 方法利用它的“大权限”破坏你“小范围”的列表Java 在参数传递这一步就报错毕竟总不能往苹果列表塞一个榴莲进去对吧所以 Java 告诉你它们是不兼容的类型为了解决这个问题Java 引入了通配符。3.2上界通配符? extends Fruit含义这个盘子装的是 Fruit 或者 Fruit 的子类 。形象比喻“水果列表”。我只知道里面是水果但不知道具体是哪种。能力限制能取 (Get)取出来的肯定是 Fruit安全。不能存 (Set)编译器禁止写入任何数据除了 null因为它怕你往苹果盘里塞香蕉 。适用场景生产者 (Producer)你需要从集合中读取数据。3.3下界通配符? super Fruit含义这个盘子装的是 Fruit 或者 Fruit 的父类 。形象比喻“水果回收站”。既然标准是“至少能装水果”那你扔苹果、香蕉进去都行。能力限制能存 (Set)可以往里存 Fruit 及其子类。难取 (Get)取出来的数据丢失了类型信息只能当做 Object 处理 。适用场景消费者 (Consumer)你需要往集合里写入数据。3.4 PECS 原则Producer Extends你要读用 extends。 Consumer Super你要写用 super。四、 总结包装类解决了基本类型无法放入集合的问题但要注意 -128~127 的缓存坑。泛型提供了编译期的类型安全但底层是通过类型擦除实现的。通配符解决了泛型不兼容的问题。遇到 ? 时牢记 PECS 原则不要试图往 extends 容器里存东西也不要指望从 super容器里取出具体类型

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询