一、枚举(Enum)
1. 什么是枚举
枚举是一种特殊的类,用于定义一组固定的常量。
2. 基本用法
// 最简单的枚举 public enum Season { SPRING, SUMMER, AUTUMN, WINTER } // 使用枚举 public class TestEnum { public static void main(String[] args) { Season s = Season.SPRING; // 常用方法 System.out.println(s.name()); // SPRING System.out.println(s.ordinal()); // 0(索引位置) System.out.println(s.toString()); // SPRING // 遍历枚举 for (Season season : Season.values()) { System.out.println(season); } // 根据字符串获取枚举 Season autumn = Season.valueOf("AUTUMN"); // switch 中使用枚举 switch (s) { case SPRING: System.out.println("春天"); break; case SUMMER: System.out.println("夏天"); break; default: System.out.println("其他季节"); } } }3. 带属性和方法的枚举
public enum Grade { // 枚举常量必须首先定义,可以带参数 EXCELLENT("优秀", 90, 100) { @Override public String getDescription() { return "成绩优异,表现突出"; } }, GOOD("良好", 80, 89) { @Override public String getDescription() { return "成绩良好,继续保持"; } }, PASS("及格", 60, 79) { @Override public String getDescription() { return "成绩及格,需要努力"; } }, FAIL("不及格", 0, 59) { @Override public String getDescription() { return "成绩不及格,需要补习"; } }; // 成员变量 private String chineseName; private int minScore; private int maxScore; // 构造方法(必须是 private) private Grade(String chineseName, int minScore, int maxScore) { this.chineseName = chineseName; this.minScore = minScore; this.maxScore = maxScore; } // 普通方法 public String getChineseName() { return chineseName; } public boolean isInRange(int score) { return score >= minScore && score <= maxScore; } // 抽象方法(每个枚举常量必须实现) public abstract String getDescription(); // 静态方法 public static Grade fromScore(int score) { for (Grade grade : Grade.values()) { if (grade.isInRange(score)) { return grade; } } return FAIL; } } // 使用示例 public class TestGrade { public static void main(String[] args) { int score = 85; Grade grade = Grade.fromScore(score); System.out.println("分数:" + score); System.out.println("等级:" + grade); System.out.println("中文名:" + grade.getChineseName()); System.out.println("描述:" + grade.getDescription()); // 输出: // 分数:85 // 等级:GOOD // 中文名:良好 // 描述:成绩良好,继续保持 } }4. 枚举实现接口
interface Describable { String describe(); } enum Color implements Describable { RED { @Override public String describe() { return "热情奔放的红色"; } }, GREEN { @Override public String describe() { return "生机勃勃的绿色"; } }, BLUE { @Override public String describe() { return "宁静深邃的蓝色"; } }; // 也可以在枚举级别实现 // @Override // public String describe() { // return "这是一个颜色"; // } }二、包(Package)
1. 什么是包
包用于组织类和接口,类似于文件系统中的文件夹,避免命名冲突,提供访问保护。
2. 包的定义和使用
// 文件:com/example/model/User.java package com.example.model; // 必须在第一行(注释除外) import java.util.Date; // 导入单个类 import java.util.*; // 导入包下所有类 import static java.lang.Math.PI; // 静态导入 public class User { private String name; private Date birthday; public double getCircleArea(double radius) { return PI * radius * radius; // 直接使用静态导入的常量 } }3. 包命名规范
// 包名全部小写,使用域名倒序 // 常见包结构: com.example.project.model // 数据模型 com.example.project.dao // 数据访问层 com.example.project.service // 业务逻辑层 com.example.project.controller // 控制器层 com.example.project.util // 工具类 com.example.project.exception // 异常类 com.example.project.config // 配置类4. 包的访问权限
// 文件:com/example/Person.java package com.example; public class Person { public String name; // 任何地方都能访问 protected int age; // 子类和同包可以访问 String address; // 默认权限:同包可以访问 private String idCard; // 只有本类能访问 } // 文件:com/example/Test.java(同包) package com.example; public class Test { public static void main(String[] args) { Person p = new Person(); p.name = "张三"; // ✅ public p.age = 18; // ✅ protected(同包) p.address = "北京"; // ✅ default(同包) // p.idCard = "xxx"; // ❌ private,无法访问 } }5. 包和编译运行
# 目录结构 # src/ # com/ # example/ # Hello.java # 编译 javac -d . src/com/example/Hello.java # 运行 java com.example.Hello # 打包成jar jar cvf myapp.jar com/三、反射(Reflection)
1. 什么是反射
反射允许程序在运行时获取类的完整信息,并动态地操作类的属性和方法
2. 获取Class对象的三种方式
通俗理解:把类想象成一个设计图纸(比如person类的代码),吧Class对象想象成这个图纸的说明书,通过说明书可以知道图纸上画了什么,有什么属性,能做什么事。
// 方式1:通过类名.class Class<?> clazz1 = String.class; //适用场景 // 示例:获取任意已知类的 Class 对象 Class<?> clazz1 = Person.class; Class<?> clazz2 = ArrayList.class; Class<?> clazz3 = int.class; // 基本类型也可以 // 方式2:通过对象.getClass() String str = "hello"; Class<?> clazz2 = str.getClass(); //适用场景:手头上有了一个对象,想知道它属于哪一类 // 示例:多态情况下的实际类型 Animal animal = new Dog(); // 声明为 Animal,实际是 Dog Class<?> clazz = animal.getClass(); // 返回的是 Dog.class,不是 Animal.class // 判断对象的实际类型 if (animal.getClass() == Dog.class) { System.out.println("这实际上是一条狗"); } // 方式3:通过 Class.forName() Class<?> clazz3 = Class.forName("java.lang.String"); //适用场景:不知道具体类名,需要动态配置 public class Demo { public static void main(String[] args) throws Exception { // 1. 类名.class - 静态方式 Class<?> clazz1 = User.class; System.out.println("方式1:" + clazz1.getName()); // 2. 对象.getClass() - 已有对象 User user = new User("张三", 20); Class<?> clazz2 = user.getClass(); System.out.println("方式2:" + clazz2.getName()); // 3. Class.forName() - 动态加载 String className = "com.example.User"; // 可以从配置文件读取 Class<?> clazz3 = Class.forName(className); System.out.println("方式3:" + clazz3.getName()); // 三种方式获取的是同一个 Class 对象 System.out.println(clazz1 == clazz2); // true System.out.println(clazz1 == clazz3); // true } } class User { private String name; private int age; public User(String name, int age) { this.name = name; this.age = age; } }3.获取类的信息
public class ReflectionDemo { public static void main(String[] args) throws Exception { Class<?> clazz = Person.class; // 获取类名 System.out.println("类名:" + clazz.getName()); System.out.println("简单类名:" + clazz.getSimpleName()); // 获取包信息 Package pkg = clazz.getPackage(); System.out.println("包名:" + pkg.getName()); // 获取修饰符 int modifiers = clazz.getModifiers(); System.out.println("是否是public:" + Modifier.isPublic(modifiers)); // 获取父类 Class<?> superclass = clazz.getSuperclass(); System.out.println("父类:" + superclass.getName()); // 获取接口 Class<?>[] interfaces = clazz.getInterfaces(); // 获取构造方法 Constructor<?>[] constructors = clazz.getConstructors(); // 获取方法 Method[] methods = clazz.getDeclaredMethods(); // 获取字段 Field[] fields = clazz.getDeclaredFields(); } }4.动态创建对象
// 方式1:通过 Class 对象 Class<?> clazz = Person.class; Person person1 = (Person) clazz.newInstance(); // 已废弃 // 方式2:通过 Constructor(推荐) Constructor<Person> constructor = Person.class.getConstructor(String.class, int.class); Person person2 = constructor.newInstance("张三", 20); // 创建数组 Object array = Array.newInstance(String.class, 10); Array.set(array, 0, "hello"); String value = (String) Array.get(array, 0);5.动态调用方法
public class MethodInvokeDemo { public static void main(String[] args) throws Exception { Person person = new Person("李四", 25); Class<?> clazz = person.getClass(); // 获取并调用公有方法 Method publicMethod = clazz.getMethod("getName"); String name = (String) publicMethod.invoke(person); System.out.println(name); // 获取并调用私有方法 Method privateMethod = clazz.getDeclaredMethod("privateMethod", String.class); privateMethod.setAccessible(true); // 突破私有权限 String result = (String) privateMethod.invoke(person, "参数"); // 调用静态方法 Method staticMethod = clazz.getMethod("staticMethod"); staticMethod.invoke(null); // 静态方法不需要对象实例 } } class Person { private String name; private int age; public Person() {} public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } private String privateMethod(String param) { return "私有方法:" + param; } public static void staticMethod() { System.out.println("静态方法"); } }6.动态操作字段
Person person = new Person("王五", 30); Class<?> clazz = person.getClass(); // 获取私有字段 Field nameField = clazz.getDeclaredField("name"); nameField.setAccessible(true); // 突破私有权限 // 读取字段值 String name = (String) nameField.get(person); System.out.println("原值:" + name); // 修改字段值 nameField.set(person, "赵六"); System.out.println("新值:" + nameField.get(person));