Java 集合框架:Map 与 Collections
学完了单列的 Collection,本篇进入双列世界:Map 用”键找值”的模型组织数据,是现实开发中出现频率最高的结构。同时把 Collections 工具类和集合嵌套一并拿下,至此集合框架的主干就齐了。 本篇目标 理解 Map 的键值对模型,说清它和 Collection 的区别 掌握 HashMap、LinkedHashMap、TreeMap、Hashtable 的特点与选型 熟练 Map 的四种遍历方式 会用 Collections 工具类的常用方法,理解集合嵌套 Map:键值对模型Map 存储”键 → 值”的映射:一个键最多映射一个值,键不允许重复(put 同键会覆盖旧值并返回旧值),值随意。这种模型也叫字典或关联数组,Python 的 dict、JS 的对象字面量都是同一种思想。和 Collection 的区别一句话说清:Collection 单列、Map 双列;Map 的数据结构只针对键有效,和值无关——所以自定义对象做键和放进 HashSet 一样,必须重写 hashCode/equals,否则两个内容相同的键会被当成不同的键。 HashMap&l...
Java 集合框架:HashSet 与 TreeSet
Set 的核心承诺只有四个字:元素唯一。HashSet 靠哈希算法高效判重,TreeSet 靠排序顺便判重,LinkedHashSet 则额外记住插入顺序。本篇把三种 Set 的原理讲透,重点是 hashCode/equals 这对孪生方法和 Comparable/Comparator 两种排序方案。 本篇目标 理解 Set 去重的语义和 HashSet 的判重流程 说清为什么自定义对象必须成对重写 hashCode() 和 equals() 区分 HashSet、LinkedHashSet、TreeSet 的适用场景 掌握 Comparable 自然排序与 Comparator 比较器排序 Set 的核心语义:不重复List 允许重复、有索引;Set 不允许重复、没有索引(也就没了按下标操作的方法)。先看 HashSet 的基本使用: HashSet<String> hs = new HashSet<>();boolean b1 = hs.add("a");boolean b2 = hs.add("...
Java 集合框架:LinkedList、泛型与 Set
LinkedList 用链表换来了头尾操作的极致速度,泛型把类型错误从运行期提前到编译期,增强 for 则是迭代器的语法糖。本篇把这几个看似零散的知识点串成一条线:容器怎么选、遍历怎么写、类型怎么管。 本篇目标 理解 LinkedList 的链表结构,说清它和 ArrayList 的取舍 看透增强 for 的本质,知道三种遍历方式谁能删除 掌握可变参数的写法和坑,认识静态导入 理解泛型为什么存在,会写泛型类和泛型方法 LinkedList:链表结构的 ListArrayList 底层是数组,元素连续排布,按下标查询一步到位;代价是中间增删要整体搬家。LinkedList 反其道而行:每个节点除装数据外还记着前后邻居的地址,像一串手拉手的人。于是查询慢(找第 100 个节点得从头或尾数过去),增删快(摘掉一个节点只要让前后邻居互相牵手),并配齐 addFirst/addLast、getFirst/getLast、removeFirst/removeLast 一套头尾方法。 LinkedList<String> list = new LinkedList<&g...
Java 集合框架:List 与迭代器
数组能存数据,但长度一旦 new 出来就改不了,而真实开发中数据量往往事先未知,于是 Java 提供了一整套可伸缩的集合框架。本篇作为系列开篇,讲清 Collection 体系的顶层设计、Iterator 迭代器这一统一的遍历抽象,以及最常用的 ArrayList。 本篇目标 说清数组与集合的区别,知道什么场景用谁 看懂 Collection 体系,记住根接口的常用方法 掌握 Iterator 遍历,初步认识 fail-fast 熟练使用 ArrayList 的增删改查 为什么数组不够用需求:存 3 个学生对象并逐个打印。用数组很自然: Student[] arr = new Student[3];arr[0] = new Student("张三", 23);arr[1] = new Student("李四", 24);arr[2] = new Student("王五", 25);for (int i = 0; i < arr.length; i++) { System.out.println...
Java 正则表达式与常用工具类
本篇是 2017 年 Java 学习笔记系列的第十四天,是一篇工具类大合集:先用正则表达式解决”字符串匹配”问题,再快速过一遍 Math、Random、System 三小件,接着用 BigDecimal 讲清浮点数的精度问题,最后把 Date 与 Calendar 这对遗留 API 和现代的 java.time 替代方案一次说清。 本篇目标 掌握正则的字符类、量词、分组三块核心语法 会在 Java 中用 matches、split、replaceAll 与 Pattern/Matcher 四种方式使用正则 了解 Math、Random、System 的常用静态方法 明白为什么算钱必须用 BigDecimal 而不是 double 知道 Date/Calendar 是遗留 API,会用 LocalDateTime 等 java.time 类替代 正则表达式:用规则描述字符串正则表达式是一门微型的”匹配语言”:用一个字符串描述”什么样的字符串才算合法”。比如校验 QQ 号——要求 5 到 15 位、不能以 0 开头、必须全是数字——不用正则要写一串循环和判断...
Java StringBuffer、排序与包装类型
本篇是 2017 年 Java 学习笔记系列的第十三天,三个主题:可变字符序列 StringBuffer 与 StringBuilder 的选型逻辑,冒泡和选择这两个入门级排序算法的原理与代码,以及基本类型包装类、自动装箱拆箱机制和 Integer 缓存那道经典面试题。 本篇目标 讲清 String、StringBuffer、StringBuilder 三兄弟的区别与选型 能手写冒泡排序和选择排序,并知道生产环境该用什么 理解八种包装类存在的意义与自动装箱拆箱 说清 Integer 缓存的范围和 == 比较的坑 三兄弟:String、StringBuffer、StringBuilder上一篇说过 String 不可变,每次拼接都新建对象;StringBuffer 和 StringBuilder 则内部维护一个可自动扩容的字符数组,append、insert、delete 都是原地修改,不产生新对象。两者的唯一区别在线程安全:StringBuffer 是 JDK 1.0 就有的元老,每个方法都加了 synchronized,多线程安全但慢;StringBuilder 是 JD...
Java 字符串与常用对象
本篇是 2017 年 Java 学习笔记系列的第十二天,主角是开发中使用频率最高的类——String。先建立”不可变性 + 字符串常量池”的入门认知,再把几十个常用方法按判断、获取、转换、替换四大类整理清楚,顺带聊聊字符串拼接的性能意识和 Scanner 键盘录入的换行陷阱。 本篇目标 理解 String 不可变的含义与字符串常量池的作用 按功能分类掌握 String 的常用方法 知道为什么循环里不该用 + 拼字符串 会用 Scanner 接收键盘输入,并避开 nextInt 与 nextLine 混用的坑 String 的不可变性:从常量池说起String s = "abc"; 这行代码里,字面量 "abc" 存放在字符串常量池中,s 只是一个指向它的引用。再写 String s2 = "abc";,JVM 发现池中已有相同内容,直接复用同一个对象——所以 s == s2 是 true。常量池本质上是一块”字符串缓存区”,目的是让内容相同的字符串在内存里只存一份,避免浪费。 除了字面量赋值,String 也提供了...
Eclipse 开发技巧与 Java Object 类
本篇是 2017 年 Java 学习笔记系列的第十一天。前半段聊聊 Eclipse 这碗”老酒”怎么喝才高效,并附上它与当今主流 IntelliJ IDEA 的快捷键对照;后半段讲透 Java 万类之祖 Object——equals、hashCode、toString 这三个几乎天天见面的方法,默认实现有什么问题、为什么要重写、重写时必须遵守什么契约。 本篇目标 了解 Eclipse 的核心高效操作,并能在 IntelliJ IDEA 中找到对应功能 理解 Object 作为类层次结构根类的意义 掌握 toString、equals、hashCode 的默认行为与重写动机 记住 equals 与 hashCode 之间必须共同遵守的契约 能手写一个”标准的”学生类 写在前面:这是一篇 Eclipse 时代的笔记本文写于 2017 年,当时 Eclipse 是国内 Java 课堂的标配 IDE;如今业界主流早已换成 IntelliJ IDEA。工具会变,但”用熟 IDE”的思路不变:内容辅助、快速修复、代码重构、断点调试,这四板斧在哪个 IDE 里都是吃饭的家伙。Eclips...
Java 包、权限修饰符与内部类
类多了要分门别类,成员多了要控制可见性,类里还能再定义类。本篇讲 package 与 import 的组织规则、四种权限修饰符的可见性矩阵,以及成员、局部、匿名三种内部类的写法与场景——匿名内部类正是今天 lambda 表达式的前身。 本篇目标 会用 package 组织类、用 import 引入类 背出四种权限修饰符的可见性矩阵 掌握成员内部类、局部内部类的语法 理解匿名内部类的本质,知道它如何演进到 lambda package 与 import为什么要有包:类一多就会重名、难管理,包就是分类存放 .class 的文件夹,也是类的命名空间。分包通常按模块(如 student、teacher 各一包),而不是按动作(add、delete、update 各一包),因为模块的内聚性更高。规则只有几条:package 必须是文件第一条有效语句且只能有一个;多级包用点分隔,包名约定全小写、用公司域名倒置保证唯一;不带 package 的类属于默认包,正式项目里不该出现。 带包编译运行:javac -d . HelloWorld.java 让编译器自动建目录,java com.ex...
Java 多态、抽象类与接口
多态让”同一个父类引用,装不同子类对象,表现出不同行为”,是面向对象扩展性的核心。本篇拆解多态三要素、”编译看左边、运行看右边”的含义、转型与 instanceof 保护,再讲抽象类与接口的设计意图,并用模板方法模式把它们串起来。 本篇目标 记住多态三要素,并理解每一条的必要性 说清多态下成员变量、成员方法、静态方法的访问规则 会用向上转型与 instanceof + 向下转型 分清抽象类与接口的设计意图:is-a 与 like-a 初识模板方法模式 多态三要素多态即事物存在的多种形态,代码上体现为 Animal a = new Cat();。成立需要三个条件,缺一不可:要有继承关系(没有父类就没有”左边”);要有方法重写(不重写,子类没有新行为,多态毫无意义);要有父类引用指向子类对象(多态的书写形式本身)。 编译看左边,运行看右边多态下的访问规则分三类。成员变量:编译看左边(父类得有这字段),运行也看左边(拿到的是父类字段值,变量不参与多态)。成员方法:编译看左边(父类必须有方法声明,否则编译失败),运行看右边(实际执行子类重写后的版本,即动态绑定)。静态方法:编译运行...