当前位置: 首页 > news >正文

Java 核心知识点查漏补缺(二)

在 Java 中,增强 for 循环(Enhanced for Loop) 也称为 “for-each 循环”,是 JDK 5 引入的一种简化集合和数组遍历的语法。它提供了一种更简洁、可读性更高的方式来遍历元素,无需手动控制索引或迭代器。

增强 for 循环的语法

for (元素类型 变量名 : 遍历对象) {// 循环体:使用变量名访问当前元素
}
  • 遍历对象:可以是数组,或实现了 java.lang.Iterable 接口的集合(如 ListSet 等,Java 集合框架中的集合均实现了该接口)。
  • 元素类型:必须与遍历对象中元素的类型一致(或兼容,如父类)。
  • 变量名:临时变量,代表当前遍历到的元素。

适用场景

  1. 遍历数组:直接遍历数组中的每个元素。
  2. 遍历集合:无需获取迭代器,直接遍历集合元素。

示例代码

1. 遍历数组

public class ForEachArray {public static void main(String[] args) {int[] numbers = {1, 2, 3, 4, 5};// 增强 for 循环遍历数组for (int num : numbers) {System.out.println(num); // 依次输出 1, 2, 3, 4, 5}}
}
2. 遍历集合

import java.util.ArrayList;
import java.util.List;public class ForEachCollection {public static void main(String[] args) {List<String> fruits = new ArrayList<>();fruits.add("Apple");fruits.add("Banana");fruits.add("Cherry");// 增强 for 循环遍历集合for (String fruit : fruits) {System.out.println(fruit); // 依次输出 Apple, Banana, Cherry}}
}

增强 for 循环的原理

增强 for 循环本质上是迭代器(Iterator)的语法糖。对于集合来说,编译器会自动将其转换为迭代器的遍历方式;对于数组,则转换为普通的 for 循环(通过索引访问)。

例如,遍历集合的增强 for 循环:

for (String fruit : fruits) { ... }

会被编译器转换为:

Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {String fruit = iterator.next();...
}

局限性

虽然增强 for 循环简化了遍历,但也有一些限制:

  1. 无法获取索引:遍历过程中无法直接获取元素的索引(数组或 List 的下标),如需索引需使用普通 for 循环。

  2. 不能修改集合结构:遍历集合时,不能通过集合自身的方法(如 add()remove())修改集合结构,否则会抛出 ConcurrentModificationException(与迭代器的 “快速失败” 机制一致)。

    • 注意:可以修改元素的内容(如对象的属性),但不能增删元素。
  3. 只能单向遍历:与迭代器类似,增强 for 循环只能从集合头部向尾部遍历,无法反向或随机访问。

  4. 不适用于需要中途终止或跳过元素的场景:虽然可以用 break 终止循环或 continue 跳过当前元素,但无法像普通 for 循环那样灵活控制循环变量(如 i += 2 跳过元素)。

增强 for 循环 vs 普通 for 循环 vs 迭代器

方式优点缺点适用场景
增强 for 循环语法简洁,可读性高,无需处理索引 / 迭代器无法获取索引,不能修改集合结构仅需遍历元素,不涉及修改集合
普通 for 循环可获取索引,灵活控制遍历过程语法较繁琐,需手动控制索引边界需要索引或灵活控制遍历
迭代器支持在遍历中安全删除元素(remove()语法较繁琐,需显式调用迭代器方法遍历中需要删除元素

总结

  • 增强 for 循环是遍历数组和集合的简化语法,底层依赖迭代器(集合)或索引(数组)。
  • 适合仅读取元素的场景,代码更简洁易读。
  • 不适合需要索引、修改集合结构或灵活控制遍历过程的场景,此时应使用普通 for 循环或迭代器。

迭代器(Iterator)是一种用于遍历集合(如 List、Set、Map 等)元素的接口,它提供了统一的遍历方式,无需关心集合的具体实现细节。迭代器属于 Java 集合框架的一部分,位于 java.util 包下。

迭代器的核心方法

java.util.Iterator 接口定义了以下三个核心方法:

  1. boolean hasNext()判断集合中是否还有下一个元素。如果有,返回 true;否则返回 false

  2. E next()返回集合中的下一个元素(E 是元素的泛型类型)。如果没有下一个元素,会抛出 NoSuchElementException

  3. void remove()删除 next() 方法返回的最后一个元素(可选操作)。如果在调用 next() 之前调用 remove(),会抛出 IllegalStateException

迭代器的使用步骤

  1. 通过集合的 iterator() 方法获取迭代器实例。
  2. 使用 hasNext() 判断是否有下一个元素。
  3. 使用 next() 获取下一个元素并移动指针。
  4. (可选)使用 remove() 删除当前元素。

示例代码

以 ArrayList 为例,演示迭代器的基本用法:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;public class IteratorDemo {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("Apple");list.add("Banana");list.add("Cherry");// 1. 获取迭代器Iterator<String> iterator = list.iterator();// 2. 遍历集合while (iterator.hasNext()) {String element = iterator.next(); // 获取下一个元素System.out.println(element);// 示例:删除元素 "Banana"if ("Banana".equals(element)) {iterator.remove(); // 注意:必须先调用 next() 才能调用 remove()}}System.out.println("删除后的集合:" + list); // [Apple, Cherry]}
}

迭代器的特点

  1. 统一遍历接口:无论集合类型(List、Set 等)如何,都可以通过相同的迭代器方法遍历,降低了代码耦合度。
  2. 快速失败机制(Fail-Fast):如果在迭代过程中通过集合自身的方法(如 add()remove())修改集合结构,迭代器会立即抛出 ConcurrentModificationException,避免数据不一致。
    • 注意:通过迭代器的 remove() 方法修改集合是允许的。
  3. 单向遍历:迭代器只能从集合头部向尾部遍历,无法反向或随机访问(如需反向遍历,可使用 ListIterator)。

泛型(Generic)以 <E> 形式出现(E 是 “Element” 的缩写,也可替换为其他标识符,如 TKV 等),它是 JDK 5 引入的特性,用于限制集合中元素的类型,实现编译时类型检查,避免运行时类型转换错误。

为什么需要泛型?

在没有泛型的早期版本中,集合可以存储任意类型的对象,取出时需要手动强制类型转换,容易出现 ClassCastException。例如:

import java.util.ArrayList;
import java.util.List;public class NoGenericDemo {public static void main(String[] args) {List list = new ArrayList();list.add("Hello"); // 存入字符串list.add(123);     // 存入整数(编译不报错)// 取出元素时需强制转换,运行时出错String str = (String) list.get(1); // 报错:ClassCastException}
}

泛型的出现解决了这个问题:通过指定集合中元素的类型,编译器会在编译阶段检查元素类型是否匹配,避免类型转换错误。

泛型 <E> 的基本用法

在集合中声明泛型 <E>,表示该集合只能存储类型为 E 的元素。例如:

// 声明一个只能存储 String 类型的 List
List<String> strList = new ArrayList<String>();
// JDK 7+ 支持菱形语法,右侧泛型可省略
List<String> strList = new ArrayList<>();strList.add("Apple"); // 正确:类型匹配
strList.add(123);     // 错误:编译直接报错(类型不匹配)// 取出元素时无需强制转换,编译器已确认类型
String s = strList.get(0); // 直接使用,无转换

泛型的核心作用

  1. 编译时类型安全检查限制集合只能添加指定类型的元素,不符合类型的操作在编译阶段就会报错,避免运行时异常。

  2. 消除强制类型转换取出元素时,编译器已知元素类型,无需手动转换,简化代码并提高可读性。

  3. 代码复用通过泛型可以编写通用的集合操作逻辑,适用于多种数据类型。例如 ArrayList<E> 可以是 ArrayList<String>ArrayList<Integer> 等,无需为每种类型单独实现集合类。

要实现 “随机读取”(如随机访问数组、集合中的元素),可以使用 java.util.Random 类生成随机索引,再通过索引获取对应元素。以下是具体实现方式:

核心思路

  1. 生成随机索引:通过 Random 类的 nextInt(n) 方法生成 [0, n) 范围内的随机整数(n 为数组 / 集合的长度)。
  2. 随机访问元素:利用生成的随机索引,直接访问数组或支持随机访问的集合(如 ArrayList)中的元素。

示例代码

1. 随机读取数组元素

import java.util.Random;public class RandomArrayAccess {public static void main(String[] args) {String[] fruits = {"苹果", "香蕉", "橙子", "草莓", "西瓜"};Random random = new Random();// 生成随机索引(0 到 fruits.length-1)int randomIndex = random.nextInt(fruits.length);// 随机访问元素String randomFruit = fruits[randomIndex];System.out.println("随机选中的水果:" + randomFruit);}
}
2. 随机读取集合元素(以 ArrayList 为例)

ArrayList 实现了 RandomAccess 接口,支持通过索引快速随机访问:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;public class RandomListAccess {public static void main(String[] args) {List<Integer> numbers = new ArrayList<>();for (int i = 1; i <= 10; i++) {numbers.add(i); // 集合元素:1,2,3,...,10}Random random = new Random();// 生成随机索引(0 到 numbers.size()-1)int randomIndex = random.nextInt(numbers.size());// 随机访问元素int randomNum = numbers.get(randomIndex);System.out.println("随机选中的数字:" + randomNum);}
}
3. 多次随机读取(去重)

若需要多次随机读取且不重复(如抽奖不重复),可通过移除已选中元素或记录已选索引实现:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;public class RandomUniqueAccess {public static void main(String[] args) {List<String> names = new ArrayList<>();names.add("张三");names.add("李四");names.add("王五");names.add("赵六");Random random = new Random();int count = 2; // 随机选取 2 个不重复的元素for (int i = 0; i < count; i++) {// 生成当前集合长度范围内的随机索引int randomIndex = random.nextInt(names.size());// 获取并移除元素(确保不重复)String randomName = names.remove(randomIndex);System.out.println("第 " + (i + 1) + " 个选中:" + randomName);}}
}

注意事项

  1. 随机索引范围nextInt(n) 生成的索引是 [0, n),需确保 n 等于数组 / 集合的长度(避免索引越界)。
  2. 集合类型限制
    • 支持随机访问的集合(如 ArrayList)可通过 get(index) 高效获取元素。
    • 不支持随机访问的集合(如 LinkedList),随机访问效率低(需从头遍历),建议先转为数组或 ArrayList 再操作。
  3. 去重逻辑:若需避免重复元素,可通过 remove() 移除已选元素,或用 HashSet 记录已选索引。

扩展:使用 ThreadLocalRandom(JDK 7+)

在多线程环境下,ThreadLocalRandom 比 Random 更高效(减少线程竞争),用法类似:

import java.util.concurrent.ThreadLocalRandom;public class ThreadLocalRandomDemo {public static void main(String[] args) {int[] arr = {10, 20, 30, 40};// 生成随机索引int index = ThreadLocalRandom.current().nextInt(arr.length);System.out.println("随机元素:" + arr[index]);}
}

I/O(Input/Output,输入 / 输出)流是用于处理设备间数据传输的机制,比如读写文件、网络通信等。I/O 流通过 “流” 的形式(数据按顺序传输)实现数据的输入和输出,是 Java 中处理数据传输的核心 API。

I/O 流的分类

Java 的 I/O 流体系庞大,可按不同维度分类:

1. 按数据流向划分
  • 输入流(Input Stream):数据从外部设备(如文件、网络)流向程序(内存),用于 “读” 操作。
  • 输出流(Output Stream):数据从程序(内存)流向外部设备,用于 “写” 操作。
2. 按处理数据类型划分
  • 字节流:以字节(8 位二进制)为单位处理数据,可处理所有类型的数据(文本、图片、音频等)。核心抽象类:InputStream(输入)、OutputStream(输出)。
  • 字符流:以字符(16 位 Unicode)为单位处理数据,仅用于处理文本数据(如 .txt 文件),会涉及字符编码(如 UTF-8、GBK)。核心抽象类:Reader(输入)、Writer(输出)。
3. 按流的角色划分
  • 节点流:直接连接数据源(如文件、内存)的流,直接操作数据(如 FileInputStream 直接读文件)。
  • 处理流:包裹在节点流或其他处理流之上,增强功能(如缓冲、转换编码),如 BufferedReader 提供缓冲和按行读取。

字节流(InputStream / OutputStream

字节流是所有流的基础,可处理任意类型数据。以下是常用实现类及示例:

1. 文件字节流(节点流)
  • FileInputStream:从文件读取字节数据。
  • FileOutputStream:向文件写入字节数据。

示例:复制文件(字节流)

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;public class FileByteStreamDemo {public static void main(String[] args) {// 源文件和目标文件路径String sourcePath = "source.jpg";String destPath = "copy.jpg";// 声明流对象(try-with-resources 自动关闭流)try (FileInputStream fis = new FileInputStream(sourcePath);FileOutputStream fos = new FileOutputStream(destPath)) {byte[] buffer = new byte[1024]; // 缓冲区(提高效率)int len; // 每次读取的字节数// 循环读取:当 len = -1 时表示读取完毕while ((len = fis.read(buffer)) != -1) {// 写入缓冲区中的有效字节(避免写入多余数据)fos.write(buffer, 0, len);}System.out.println("文件复制完成!");} catch (IOException e) {e.printStackTrace();}}
}
2. 缓冲字节流(处理流)

BufferedInputStream / BufferedOutputStream:通过内部缓冲区减少磁盘 IO 次数,提高读写效率(建议优先使用)。

示例:缓冲流复制文件

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;public class BufferedByteStreamDemo {public static void main(String[] args) {try (// 缓冲流包裹文件流BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.txt"))) {byte[] buffer = new byte[1024];int len;while ((len = bis.read(buffer)) != -1) {bos.write(buffer, 0, len);}System.out.println("复制完成!");} catch (IOException e) {e.printStackTrace();}}
}

字符流(Reader / Writer

字符流专为文本处理设计,自动处理字符编码转换(需注意编码格式,如 UTF-8)。

1. 文件字符流(节点流)
  • FileReader:读取文本文件(默认使用系统编码,可能存在乱码)。
  • FileWriter:写入文本文件。
2. 缓冲字符流(处理流)

BufferedReader / BufferedWriter:提供缓冲功能,且 BufferedReader 支持 readLine() 按行读取文本,极为常用。

示例:读取文本文件(按行读取)

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;public class BufferedReaderDemo {public static void main(String[] args) {try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {String line; // 存储每行内容// 按行读取,当 line 为 null 时表示读取完毕while ((line = br.readLine()) != null) {System.out.println(line); // 打印每行内容}} catch (IOException e) {e.printStackTrace();}}
}

示例:写入文本文件(带换行)

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;public class BufferedWriterDemo {public static void main(String[] args) {try (BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"))) {bw.write("Hello, 字符流!");bw.newLine(); // 写入换行符(跨平台兼容)bw.write("这是第二行文本");} catch (IOException e) {e.printStackTrace();}}
}

转换流(字节流 ↔ 字符流)

当需要指定字符编码(如避免乱码)时,需使用转换流:

  • InputStreamReader:将字节输入流转换为字符输入流(可指定编码)。
  • OutputStreamWriter:将字节输出流转换为字符输出流(可指定编码)。

示例:指定编码读取文本(UTF-8)

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;public class InputStreamReaderDemo {public static void main(String[] args) {// 字节流 → 转换流(指定 UTF-8 编码)→ 缓冲流try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("utf8.txt"), StandardCharsets.UTF_8))) {String line;while ((line = br.readLine()) != null) {System.out.println(line);}} catch (IOException e) {e.printStackTrace();}}
}

流的关闭

  • 流操作会占用系统资源(如文件句柄),必须关闭!
  • 推荐使用 try-with-resources 语法(JDK 7+):在 try() 中声明流对象,系统会自动关闭,无需手动调用 close()
  • 手动关闭需在 finally 中调用 close(),避免资源泄漏。

一、Java 数据类型

Java 是强类型语言,数据类型分为基本数据类型引用数据类型,编译时严格检查类型。

1. 基本数据类型(8 种)
类型占用空间描述
byte1 字节整数,范围 -128 ~ 127
short2 字节整数,范围 -32768 ~ 32767
int4 字节整数,范围 -2^31 ~ 2^31-1(最常用)
long8 字节长整数,范围 -2^63 ~ 2^63-1(需加后缀 L,如 100L
float4 字节单精度浮点数(需加后缀 F,如 3.14F
double8 字节双精度浮点数(默认浮点类型,如 3.14
char2 字节单个 Unicode 字符(用单引号,如 'A''中'
boolean1 字节布尔值,true 或 false(仅用于逻辑判断)
2. 引用数据类型
  • 类(class):如 StringInteger、自定义类等。
  • 接口(interface):如 ListMap 等。
  • 数组([]):如 int[]String[] 等。
  • 枚举(enum)、注解(@interface)等。

特点:变量存储的是对象的引用(内存地址),默认值为 null

二、JavaScript(JS)数据类型

JS 是弱类型、动态类型语言,变量类型无需声明,运行时自动推断,类型可动态改变。

1. 基本数据类型(6 种)
类型描述
Number数字(整数、浮点数、NaN、Infinity),如 1233.14NaN
String字符串(单 / 双引号包裹),如 "hello"'world'
Boolean布尔值:true 或 false
Null表示空值(仅一个值 null
Undefined变量未赋值时的默认值(仅一个值 undefined
SymbolES6 新增,唯一不可变的值(用于对象属性的唯一键)
2. 引用数据类型(1 种,统称 Object
类型描述
Object复杂数据类型的基类,包括:- 普通对象:{name: "Tom"}- 数组:[1, 2, 3]- 函数:function() {}- 日期:new Date()- 正则:/abc/ 等

特点:基本类型存储值,引用类型存储地址(指针),赋值时传递引用。

三、MySQL 数据类型

MySQL 是关系型数据库,数据类型围绕存储优化业务场景设计,主要分为数值、字符串、日期等。

1. 数值类型
类型范围 / 说明适用场景
TINYINT1 字节,范围 -128 ~ 127(无符号 0 ~ 255小整数(如状态值 0/1/2)
SMALLINT2 字节,范围 -32768 ~ 32767(无符号 0 ~ 65535较小整数(如数量)
INT4 字节,范围 -2^31 ~ 2^31-1(最常用)一般整数(如 ID、年龄)
BIGINT8 字节,范围 -2^63 ~ 2^63-1大整数(如雪花 ID、时间戳)
FLOAT4 字节,单精度浮点数(精度较低)非精确小数(如温度)
DOUBLE8 字节,双精度浮点数较高精度小数
DECIMAL(M,D)定点数(精确计算),M 总位数,D 小数位数(如 DECIMAL(10,2)金额、汇率等精确数值
2. 字符串类型
类型长度限制 / 说明适用场景
CHAR(N)固定长度 N(1~255),不足补空格(查询时自动截断)短字符串(如手机号、性别)
VARCHAR(N)可变长度 N(1~65535),按实际长度存储变长字符串(如姓名、地址)
TEXT长文本(最大 65535 字节)较长文本(如描述)
LONGTEXT极大文本(最大 4GB)超大文本(如文章、日志)
BLOB二进制大对象(存储图片、文件等二进制数据)非文本数据存储
3. 日期时间类型
类型格式 / 范围适用场景
DATEYYYY-MM-DD(1000-01-01 ~ 9999-12-31)仅日期(如生日)
TIMEHH:MM:SS(-838:59:59 ~ 838:59:59)仅时间
DATETIMEYYYY-MM-DD HH:MM:SS(1000-01-01 ~ 9999-12-31)日期 + 时间(如创建时间)
TIMESTAMPYYYY-MM-DD HH:MM:SS(1970-01-01 ~ 2038-01-19),受时区影响需时区转换的时间(如日志)
YEAR年份(1901 ~ 2155)仅年份

核心差异总结

维度JavaJavaScriptMySQL
类型特性强类型、编译时检查弱类型、动态类型、运行时推断存储导向,按数据特性划分
数值类型细分为 byte/short/int/long 等统一为 Number(包含整数、浮点数)按存储范围和精度细分(如 INT/BIGINT)
字符串类型String 类(引用类型)基本类型 String按长度和用途分 CHAR/VARCHAR/TEXT 等
日期类型无原生类型,依赖 java.util.Date 等Date 对象(基于时间戳)原生支持 DATE/DATETIME 等
布尔类型明确 boolean(true/false)boolean(true/false,可自动转换)无专门布尔类型,常用 TINYINT (1) 替代

http://www.dtcms.com/a/519369.html

相关文章:

  • wpf之数据类型转换
  • SpringBoot-Web开发之拦截器
  • 计算机网络:网络基础
  • C++学习——类与对象详细知识点总结
  • C primer plus (第六版)第十一章 编程练习第14题
  • 逆变器之逆变原理
  • PLL说明,quartus和vivado两款软件的pll IP核使用说明
  • Redis全解析:性能、类型与淘汰策略
  • 行业的年龄焦虑本质是“价值重构危机“
  • 自己建的网站无法打开晋城网站制作公司
  • InstructBLIP:迈向通用视觉-语言模型的新里程碑
  • list的底层实现
  • MySQL一键升级脚本(5.7-8.0)
  • 销售网站建设工资多少绿色主色调网站
  • 应用层网络协议深度解析:设计、实战与安全
  • C++:类和对象_bite
  • SQL之键与约束
  • 【vTESTstudio开发教程】--- 如何添加测试用例List
  • SpringBoot-Web开发之内容协商
  • 实现一个JSON工具类自动处理JSON转String
  • 域名注册网站那个好企业服务官网
  • SpringBoot-数据访问之MyBatis与Redis
  • iOS 26 App 运行状况全面解析 多工具协同监控与调试实战指南
  • uts ios插件开发tips
  • 单页营销型网站全国城建中心官方网站
  • 了解sip和rtp是什么
  • MySQL-3-函数应用及多表查询
  • 自然语言处理分享系列-词语和短语的分布式表示及其组合性(二)
  • 网站建设珠海 新盈科技泉州建站模板
  • ISO 8601日期时间标准及其在JavaScript、SQLite与MySQL中的应用解析