05常用类
包装类
在Java中,包装类(Wrapper Class)是用于将基本数据类型封装为对象的类。每个基本数据类型都有一个对应的包装类,这些类位于java.lang包中,主要用于在需要对象的场景中使用基本数据类型。
基本数据类型与对应包装类
| 基本数据类型 | 对应包装类 |
|---|---|
boolean | Boolean |
char | Character |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
Integer 类的常用方法
Integer 类是 Java 中用于包装基本数据类型int的一个类,提供了丰富的静态和实例方法,用于数值处理、类型转换、进制转换等操作。
基本数据类型→包装类对象
Integer a = new Integer(3); Integer b = Integer.valueOf(30);包装类对象→基本数据类型
Integer b = 123; // 假设 b 是一个 Integer 对象 int c = b.intValue(); // 将 Integer 转换为 int 类型 double d = b.doubleValue(); // 将 Integer 转换为 double 类型字符串→包装对象
Integer e = new Integer("9999"); Integer f = Integer.parseInt("9999");包装对象→字符串
String str = f.toString();MIN_VALUE / MAX_VALUE
int min = Integer.MIN_VALUE; // -2147483648 int max = Integer.MAX_VALUE; // 2147483647自动装箱与拆箱
在Java中,自动装箱(Autoboxing)是指将基本数据类型(如int、double、boolean等)自动转换为对应的包装类对象(如Integer、Double、Boolean等)。自动拆箱(Unboxing)则是将包装类对象自动转换回对应的基本数据类型。
自动装箱
当基本数据类型被赋值给其对应的包装类引用时,Java编译器会自动调用包装类的静态工厂方法进行转换。
Integer num = 10; // 自动装箱:int → Integer Double price = 3.14; // 自动装箱:double → Double Boolean flag = true; // 自动装箱:boolean → Boolean上述代码等价于:
Integer num = Integer.valueOf(10); Double price = Double.valueOf(3.14); Boolean flag = Boolean.valueOf(true);自动拆箱
当包装类对象被用于需要基本数据类型的表达式中时,编译器会自动调用包装类的实例方法提取值。
Integer num = 20; int value = num; // 自动拆箱:Integer → int double d = num; // 自动拆箱:Integer → double(通过提升)上述代码等价于:
int value = num.intValue(); double d = num.doubleValue();注意事项
性能开销
自动装箱和拆箱涉及对象创建与方法调用,频繁使用可能带来性能损耗,尤其是在循环中。空指针异常风险
若包装类变量为null,自动拆箱会导致NullPointerException。Integer a = null; int b = a; // 运行时抛出 NullPointerExceptionInteger缓存机制
Integer.valueOf(int)对于 -128 到 127 之间的值会返回缓存对象,因此比较时应使用equals()或注意使用==的陷阱。Integer a = 100; Integer b = 100; System.out.println(a == b); // true(来自缓存) Integer c = 200; Integer d = 200; System.out.println(c == d); // false(不同对象)
- 避免在性能敏感的循环中频繁进行装箱/拆箱。
- 使用
Objects.equals()比较包装类对象,避免空指针。- 在比较包装类值时,优先使用
.equals()而非==。- 明确处理可能为null的情况,防止运行时异常。
StringBuilder 与 StringBuffer类
StringBuilder和StringBuffer都是 Java 中用于动态构建字符串的可变字符序列类,它们都继承自AbstractStringBuilder。
可变性
StringBuilder和StringBuffer的核心优势在于其可变性。与不可变的String类不同,它们允许在不创建新对象的情况下修改字符串内容,从而显著提升频繁拼接操作的性能。
StringBuilder sb = new StringBuilder("abcdefg"); System.out.println(Integer.toHexString(sb.hashCode())); // f6f4d33 System.out.println(sb); // abcdefg sb.setCharAt(2, 'm'); System.out.println(Integer.toHexString(sb.hashCode())); // f6f4d33 System.out.println(sb); // abmdefg线程安全性
StringBuffer的所有关键方法(如append、insert、reverse)都被声明为synchronized,这意味着在多线程环境下,StringBuffer是线程安全的,多个线程可以安全地共享同一个StringBuffer实例而不会引发数据竞争。
StringBuilder没有使用同步机制,因此在单线程环境中性能更高,但在多线程场景下若多个线程同时访问同一实例,可能导致结果不一致或异常行为。
方法一致性
两者支持相同的方法集合,包括:
append(Object obj):追加指定对象的字符串表示。insert(int offset, Object obj):在指定位置插入内容。delete(int start, int end):删除指定范围内的字符。replace(int start, int end, String str):替换指定范围的内容。reverse():反转当前字符序列。toString():返回最终构建的字符串。
StringBuilder sb = new StringBuilder(); sb.append("Hello"); sb.append(" "); sb.append("World"); System.out.println(sb.toString()); // 输出: Hello World StringBuffer sbf = new StringBuffer(); sbf.append("Thread-safe"); sbf.reverse(); System.out.println(sbf.toString()); // 输出: efas-daerhT性能差异分析
- String 拼接操作:在循环中使用
+拼接字符串时,每次都会生成新的对象,导致大量临时对象堆积,内存开销大,性能下降明显。 - StringBuilder 拼接操作:通过
append()方法直接在内部缓冲区中修改内容,避免了频繁创建新对象,显著提升性能。
// 使用 String 拼接(低效) String result = ""; for (int i = 0; i < 1000; i++) { result += "a"; } // 使用 StringBuilder 拼接(高效) StringBuilder sb = new StringBuilder(); for (int i = 0; i < 1000; i++) { sb.append("a"); } String result = sb.toString();DateFormat类
格式化日期为字符串
使用SimpleDateFormat类将Date对象格式化为指定格式的字符串。
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String str = df.format(new Date(4000000)); System.out.println(str); // 1970-01-01 09:06:40解析字符串为日期对象
SimpleDateFormat df2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = df2.parse("1990-02-01 18:15:55"); System.out.println(date); // Thu Feb 01 18:15:55 CST 1990测试其他格式字符
利用D获得本时间对象是所处年份的第几天
SimpleDateFormat df3 = new SimpleDateFormat("D"); String str3 = df3.format(new Date()); System.out.println(str3); // 269自定义格式符号说明
| 符号 | 含义 |
|---|---|
y | 年份 |
M | 月份(大写) |
d | 日期 |
H | 小时(0-23) |
h | 小时(1-12) |
m | 分钟 |
s | 秒 |
S | 毫秒 |
注意:大小写敏感,MM表示两位月份,M表示一位月份。
Calendar 类
Calendar 类是 Java 中用于处理日期和时间的抽象类,位于java.util包中。它提供了一种灵活的方式来操作日期和时间,支持多种日历系统(如格里高利历),并可以进行日期的加减、比较、格式化等操作。
获取当前日历实例
Calendar calendar = Calendar.getInstance();设置时间字段
calendar.set(Calendar.YEAR, 2025); calendar.set(Calendar.MONTH, Calendar.APRIL); // 注意:月份从 0 开始,4 表示 5 月 calendar.set(Calendar.DAY_OF_MONTH, 5);获取时间字段值
int year = calendar.get(Calendar.YEAR); int month = calendar.get(Calendar.MONTH) + 1; // 转换为 1~12 的月份 int day = calendar.get(Calendar.DAY_OF_MONTH);时间操作(增加/减少)
calendar.add(Calendar.DAY_OF_MONTH, 7); // 向后推 7 天 calendar.add(Calendar.YEAR, -1); // 前移 1 年比较两个日期
Calendar cal1 = Calendar.getInstance(); cal1.set(2025, Calendar.APRIL, 5); Calendar cal2 = Calendar.getInstance(); cal2.set(2025, Calendar.MAY, 1); if (cal1.compareTo(cal2) < 0) { System.out.println("cal1 在 cal2 之前"); }与 Date 类的关系
Calendar与Date都用于表示时间,但Calendar更强大且可变。Calendar可以直接转换为Date:
Date date = calendar.getTime();Date也可以转换为Calendar:
calendar.setTime(date);
Calendar.MONTH从 0 开始(0 表示一月),使用时需注意加 1。Calendar是可变对象,多次操作会修改原实例状态。- 推荐在新项目中使用
java.time包中的LocalDateTime、ZonedDateTime等现代日期时间类,因为它们更安全、线程友好且语义清晰。
获取时间的方法
public static void printlnCalendar(Calendar c) { int year = c.get(Calendar.YEAR); int month = c.get(Calendar.MONTH) + 1; int day = c.get(Calendar.DAY_OF_MONTH); int dayOfWeek = c.get(Calendar.DAY_OF_WEEK) - 1; String dayOfWeekStr = dayOfWeek == 0 ? "日" : String.valueOf(dayOfWeek); int hour = c.get(Calendar.HOUR); int minute = c.get(Calendar.MINUTE); int second = c.get(Calendar.SECOND); System.out.println(year + "年" + month + "月" + day + "日 周" + dayOfWeekStr + hour + "时" + minute + "分" + second + "秒"); } printlnCalendar(b); // 2026年9月27日 周日6时6分11秒Math类
Java中的Math类位于java.lang包中,是一个提供基本数学运算方法的工具类。
常见方法
Math.abs(x):返回x的绝对值。Math.max(x, y):返回x和y中的较大值。Math.min(x, y):返回x和y中的较小值。Math.ceil(x):向上取整,返回大于等于x的最小整数。Math.floor(x):向下取整,返回小于等于x的最大整数。Math.rint(x):返回最接近x的整数值,若有两个相等的整数,则取偶数。Math.round(x):返回最接近x的long或int值(四舍五入)。Math.trunc(x):截断小数部分,返回整数部分(仅在某些JDK版本支持,建议使用Math.floor或Math.ceil配合类型转换实现)
public class MathExample { public static void main(String[] args) { double a = 16.0; double b = 3.0; System.out.println("sqrt(16): " + Math.sqrt(a)); // 4.0 System.out.println("pow(2, 3): " + Math.pow(2, 3)); // 8.0 System.out.println("max(5, 10): " + Math.max(5, 10)); // 10 System.out.println("min(5, 10): " + Math.min(5, 10)); // 5 System.out.println("sin(π/2): " + Math.sin(Math.PI / 2)); // 1.0 System.out.println("random: " + Math.random()); // 0.0 ~ 1.0 System.out.println("round(3.7): " + Math.round(3.7)); // 4 } }随机数生成
Math.random():返回一个介于0.0(含)到1.0(不含)之间的双精度浮点数
int randomNum = (int)(Math.random() * 100);
- 所有方法均为静态方法,无需创建
Math对象即可调用。- 参数和返回值多为
double类型,注意类型转换。- 某些方法在输入无效时会返回特殊值,如
Math.sqrt(-1)返回NaN。Math.random()不支持自定义范围,需手动扩展。- 高精度计算应考虑使用
BigDecimal而非Math类。
Random类
Java中的Random类位于java.util包中,用于生成伪随机数。它提供了多种方法来生成不同类型的随机数,适用于需要随机性场景的程序开发。
生成随机整数
使用nextInt()方法可以生成一个介于0(包括)和指定值(不包括)之间的随机整数。例如:
Random random = new Random(); int randomNumber = random.nextInt(10); // 生成0到9之间的随机整数若需生成指定范围内的随机整数,如5到15之间,可采用以下方式:
int min = 5; int max = 15; int randomNumber = random.nextInt(max - min + 1) + min;生成随机浮点数
nextDouble()方法返回一个介于0.0(包括)和1.0(不包括)之间的双精度浮点数。
double randomDouble = random.nextDouble(); // 0.0 <= randomDouble < 1.0若需生成指定范围内的浮点数,例如2.5到7.5之间:
double min = 2.5; double max = 7.5; double randomDouble = min + (max - min) * random.nextDouble();生成随机布尔值
nextBoolean()方法返回一个随机的布尔值,真或假的概率各为50%。
boolean randomBoolean = random.nextBoolean();生成随机长整数
nextLong()方法生成一个64位的随机长整数。
long randomLong = random.nextLong();线程安全性
Random类不是线程安全的。在多线程环境中,建议每个线程使用独立的Random实例,或使用ThreadLocalRandom替代。
import java.util.concurrent.ThreadLocalRandom; // 推荐在多线程中使用 int randomValue = ThreadLocalRandom.current().nextInt(1, 100);File类
Java中的File类位于java.io包中,是用于表示文件和目录路径名的抽象表示。它不直接操作文件内容,而是提供对文件系统中文件和目录的属性、路径、权限等信息的访问与管理。
创建File对象
通过构造函数创建File实例,可以指定文件或目录的路径:
File file = new File("example.txt"); File directory = new File("/home/user/documents"); File nested = new File("/home/user", "documents/file.txt");支持绝对路径和相对路径,路径分隔符在不同操作系统中自动适配(如Windows使用\,Unix/Linux使用/)。
判断文件类型
boolean isFile = file.isFile(); // 是否为文件 boolean isDirectory = file.isDirectory(); // 是否为目录检查是否存在
boolean exists = file.exists();创建文件或目录
boolean created = file.createNewFile(); // 仅适用于文件,若已存在则返回false boolean dirCreated = directory.mkdir(); // 创建单级目录 boolean dirCreated2 = directory.mkdirs(); // 创建多级目录(包括父目录)获取文件信息
String name = file.getName(); // 获取文件名 String path = file.getPath(); // 获取路径字符串 String absolutePath = file.getAbsolutePath(); // 获取绝对路径 long lastModified = file.lastModified(); // 最后修改时间(毫秒) long length = file.length(); // 文件大小(字节),若为目录则返回0文件重命名与移动
File newFile = new File("newname.txt"); boolean renamed = file.renameTo(newFile);该方法可实现文件重命名或移动到其他目录,前提是目标位置不存在且权限允许。
删除文件或目录
boolean deleted = file.delete(); // 只能删除文件或空目录若要删除非空目录,需先递归删除其内部所有内容。
遍历目录内容
File dir = new File("/path/to/directory"); String[] files = dir.list(); // 返回文件名数组 File[] allFiles = dir.listFiles(); // 返回File对象数组配合过滤器可筛选特定类型文件:
File[] txtFiles = dir.listFiles((d, name) -> name.endsWith(".txt"));路径处理与标准化
File canonicalFile = file.getCanonicalFile(); // 获取规范路径(消除符号链接、相对路径等) File parentDir = file.getParentFile(); // 获取父目录
File类本身不涉及文件读写操作,读写需结合InputStream、OutputStream、Reader、Writer等流类。- 在多线程环境下,
File对象不可变,但其对应文件可能被外部修改。- 使用
File类时需注意异常处理,例如文件访问权限不足可能导致失败。
mkdir和mkdirs
mkdir是 Javajava.io.File类中的一个方法,用于创建单个目录。该方法仅在父目录存在且目标路径不存在时成功创建目录,否则返回 false。
mkdirs也是 Javajava.io.File类中的方法,功能与mkdir类似,但具有递归创建目录的能力。它会自动创建所有必需的父目录,直到路径完整。
File f3 = new File("d:/电影/港台/陈奕迅"); boolean flag1 = f3.mkdir(); System.out.println(flag1); // false boolean flag2 = f3.mkdirs(); System.out.println(flag2); // true递归打印目录树结构
public class TestFile1 { public static void main(String[] args) { File f = new File("D:\\7-Zip"); printlnFile(f, 0); } static void printlnFile(File f, int level) { for (int i = 0; i < level; i++) { System.out.print("-"); } System.out.println(f.getName()); if (f.isDirectory()) { File[] files = f.listFiles(); if (files != null) { for (File file : files) { printlnFile(file, level + 1); } } } } }枚举
语法结构
在 Java 中,枚举(enum)是一种特殊的数据类型,用于定义一组命名的常量。通过enum关键字可以声明一个枚举类型。
public enum 枚举名 { 枚举体1(参数列表), 枚举体2(参数列表), 枚举体3(参数列表); // 构造函数 private 枚举名(参数类型 参数) { // 初始化逻辑 } // 其他方法或字段 public 参数类型 获取方法() { // 返回逻辑 } }定义一个表示颜色的枚举
public enum Color { RED("红色", 0xFF0000), GREEN("绿色", 0x00FF00), BLUE("蓝色", 0x0000FF); private final String name; private final int rgb; Color(String name, int rgb) { this.name = name; this.rgb = rgb; } public String getName() { return name; } public int getRgb() { return rgb; } }public class Main { public static void main(String[] args) { Color color = Color.RED; System.out.println("颜色名称: " + color.getName()); System.out.println("RGB值: " + Integer.toHexString(color.getRgb())); } }颜色名称: 红色 RGB值: ff0000
- 枚举常量必须在第一行声明,且以分号结尾。
- 枚举可以包含构造函数、方法和字段。
- 枚举默认是
public static final,不可被继承。- 可通过
values()方法获取所有枚举值的数组。- 可通过
valueOf(String)方法根据名称获取枚举实例。