Java内部类与常用类详解
一、内部类概念与分类
内部类是指在一个类内部完整定义的另一个类。它编译后会生成独立的字节码文件,并能直接访问外部类的私有成员,同时不破坏封装性。根据定义位置和特性,内部类分为以下几种:
1. 成员内部类
成员内部类与实例变量和实例方法处于同一级别,是外部类的实例成员。创建其对象时,必须先有外部类对象:
Outer outer = new Outer();
Inner inner = outer.new Inner();
当外部类和内部类有同名属性时,内部类会优先访问自己的属性。此类内部类不能定义静态成员,但可以定义静态常量(如 static final)。
2. 静态内部类
静态内部类无需外部类对象即可创建,可通过类名直接访问。它只能访问外部类的静态成员,若需访问实例成员,必须通过外部类对象:
Outer.Inner inner = new Outer.Inner();
Outer.Inner.show();
3. 局部内部类
局部内部类定义在外部类的方法内,其作用域仅限于该方法。它不能添加任何访问修饰符,且访问方法内的局部变量时,这些变量必须为 final(JDK 1.8 后隐式添加)。
4. 匿名内部类
匿名内部类是没有名字的局部内部类,必须继承一个父类或实现一个接口。它将定义、实现和创建对象合并,只能生成一个实例。优点是减少代码量,缺点是降低可读性。
二、常用类详解
1. Object 类
Object 是 Java 中所有类的直接或间接父类,位于继承树顶层。任何未显式继承其他类的类都默认继承 Object。Object 类型可存储任何对象,常作为参数或返回值类型。
核心方法
- getClass():返回实际存储的对象类型,用于判断两个引用是否指向同类型对象。
- hashCode():返回对象的哈希码值,基于地址或内容计算得出。
- toString():返回对象的字符串描述,可通过重写展示属性值。
- equals():默认比较对象地址,可重写以比较内容。
- finalize():当对象被判定为垃圾时由 JVM 调用,进入回收队列。
public class TestStudent {
public static void main(String[] args) {
Student s1 = new Student("张三", 18);
Student s2 = new Student("李四", 19);
// getClass() 示例
System.out.println("=== getClass() ===");
System.out.println(s1.getClass() == s2.getClass()); // true
// hashCode() 示例
System.out.println("=== hashCode() ===");
System.out.println("s1 hash: " + s1.hashCode());
Student s3 = s1;
System.out.println("s3 same as s1: " + (s1.hashCode() == s3.hashCode()));
// toString() 示例
System.out.println("=== toString() ===");
System.out.println(s1);
System.out.println(s2);
// equals() 示例
System.out.println("=== equals() ===");
Student s4 = new Student("王五", 20);
Student s5 = new Student("王五", 20);
System.out.println("s1 equals s2: " + s1.equals(s2));
System.out.println("s4 equals s5: " + s4.equals(s5));
}
}
2. 包装类
包装类将基本数据类型转换为引用类型,并默认值为 null。常用映射如下:
| 基本类型 | 包装类 |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| boolean | Boolean |
| char | Character |
装箱与拆箱
public class Demo01 {
public static void main(String[] args) {
// 手动装箱(JDK 1.5 前)
int num = 10;
Integer boxed1 = new Integer(num);
Integer boxed2 = Integer.valueOf(num);
// 手动拆箱
Integer obj = new Integer(100);
int unboxed = obj.intValue();
// 自动装箱与拆箱(JDK 1.5+)
int age = 30;
Integer autoBoxed = age; // 自动装箱
int autoUnboxed = autoBoxed; // 自动拆箱
// 基本类型转字符串
int i = 255;
String str1 = i + ""; // "255"
String str2 = Integer.toString(i, 16); // "ff"
// 字符串转基本类型
String numStr = "100";
int parsed = Integer.parseInt(numStr); // 100
String boolStr = "true";
boolean boolVal = Boolean.parseBoolean(boolStr); // true
}
}
整数缓冲区
Java 预先创建了 -128 到 127 范围内的 256 个 Integer 对象,这些对象被复用:
public class Demo02 {
public static void main(String[] args) {
Integer a = new Integer(100);
Integer b = new Integer(100);
System.out.println(a == b); // false(不同对象)
Integer c = Integer.valueOf(100);
Integer d = Integer.valueOf(100);
System.out.println(c == d); // true(来自缓冲区)
Integer e = Integer.valueOf(200);
Integer f = Integer.valueOf(200);
System.out.println(e == f); // false(超出范围)
}
}
3. String 类
字符串是不可变的常量,创建后无法修改。字符串字面值存储在 字符串池(String Pool)中,相同内容可共享。使用 new 关键字会额外创建堆对象。
常用方法
public class Demo02 {
public static void main(String[] args) {
String s = "java是世界上最好的语言";
// 基本操作
System.out.println("长度: " + s.length()); // 13
System.out.println("首字符: " + s.charAt(0)); // j
System.out.println("包含 'java': " + s.contains("java")); // true
// 转换与查找
char[] chars = s.toCharArray(); // 转数组
System.out.println("首次 'a' 索引: " + s.indexOf('a')); // 1
System.out.println("最后 'a' 索引: " + s.lastIndexOf('a')); // 3
// 修剪与大小写
String trimmed = " abc ".trim(); // "abc"
System.out.println("大写: " + trimmed.toUpperCase()); // "ABC"
// 替换与分割
String replaced = s.replace("java", "php");
String[] parts = "word1,word2,word3".split(",");
System.out.println("替换后: " + replaced);
System.out.println("分割数组长度: " + parts.length); // 3
// 比较
String s1 = "hello";
String s2 = "Hello";
System.out.println("忽略大小写比较: " + s1.equalsIgnoreCase(s2)); // true
}
}
StringBuffer 与 StringBuilder
两者都是可变字符串。StringBuffer(JDK 1.0)线程安全但慢;StringBuilder(JDK 5.0)非线程安全但快:
public class Demo03 {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
sb.append("张三").append("李四"); // 链式追加
System.out.println(sb); // "张三李四"
sb.insert(0, "第一"); // 插入
sb.replace(0, 2, "第二"); // 替换
sb.delete(0, 2); // 删除
}
}
4. BigDecimal
用于精确浮点数计算,位于 java.math 包:
import java.math.BigDecimal;
public class Demo01 {
public static void main(String[] args) {
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("0.9");
// 加减乘除
System.out.println("加法: " + a.add(b)); // 1.9
System.out.println("减法: " + a.subtract(b)); // 0.1
System.out.println("乘法: " + a.multiply(b)); // 0.90
// 除法需指定精度和舍入模式
BigDecimal result = new BigDecimal("20")
.divide(new BigDecimal("3"), 2, BigDecimal.ROUND_HALF_UP);
System.out.println(result); // 6.67
}
}
5. Date
表示时间点,精确到毫秒。大部分方法已被 Calendar 取代:
import java.util.Date;
public class Demo01 {
public static void main(String[] args) {
Date now = new Date();
System.out.println("当前时间: " + now.toLocaleString());
Date yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);
System.out.println("昨天: " + yesterday.toLocaleString());
System.out.println("now after yesterday: " + now.after(yesterday)); // true
System.out.println("compareTo: " + now.compareTo(yesterday)); // 正数
}
}
6. Calendar
用于操作日期字段。通过 getInstance() 获取实例:
import java.util.Calendar;
public class Demo01 {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
// 获取各部分
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH) + 1; // 加1
int day = cal.get(Calendar.DAY_OF_MONTH);
// 设置与增减
cal.set(Calendar.DAY_OF_MONTH, 23);
cal.add(Calendar.HOUR, -1);
// 最大/最小天数
int maxDays = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
int minDays = cal.getActualMinimum(Calendar.DAY_OF_MONTH);
}
}
7. SimpleDateFormat
用于日期格式化与解析:
import java.text.SimpleDateFormat;
import java.util.Date;
public class Demo01 {
public static void main(String[] args) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
// 日期转字符串
Date now = new Date();
String formatted = sdf.format(now);
System.out.println(formatted);
// 字符串转日期
Date parsed = sdf.parse("2021年02月24日 12:05:42");
System.out.println(parsed);
}
}
8. System 类
提供系统级操作,所有方法均为静态:
public class Demo01 {
public static void main(String[] args) {
// 数组复制
int[] src = {2, 4, 6, 8, 10};
int[] dest = new int[5];
System.arraycopy(src, 0, dest, 1, 3);
// dest: [0, 2, 4, 6, 0]
// 时间测量
long start = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100000; i++) sb.append(i);
long end = System.currentTimeMillis();
System.out.println("耗时: " + (end - start) + "ms");
// 建议垃圾回收
System.gc();
// 退出 JVM
System.exit(0);
}
}