java快速学习速查(5)
这个部分包含了Java面向对象部分的全部数据类型,继承,重载,多态,抽象类,封装,接口,枚举,包,反射
接下来是详解部分:
Java 继承全面解析 继承是面向对象编程的三大特性之一(封装、继承、多态),下面我将系统地讲解 Java 继承的各种功能和使用场景。
一、继承基础 1. 基本语法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Animal { private String name; public Animal (String name) { this .name = name; } public void eat () { System.out.println(name + "正在吃东西" ); } } class Dog extends Animal { private String breed; public Dog (String name, String breed) { super (name); this .breed = breed; } public void bark () { System.out.println("汪汪叫" ); } @Override public void eat () { System.out.println(getName() + "(" + breed + ")正在啃骨头" ); } public String getBreed () { return breed; } }
2. 继承的特点
子类拥有父类非 private 的属性和方法
子类可以添加自己的属性和方法
子类可以重写父类的方法
Java 是单继承,一个类只能直接继承一个父类
构造方法不能被继承,但可以通过 super 调用
二、方法重写(Override) 1. 重写规则 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Shape { public void draw () { System.out.println("绘制形状" ); } public double getArea () { return 0.0 ; } } class Circle extends Shape { private double radius; public Circle (double radius) { this .radius = radius; } @Override public void draw () { System.out.println("绘制圆形,半径: " + radius); } @Override public double getArea () { return Math.PI * radius * radius; } }
重写规则 :
方法名和参数列表必须相同
返回类型可以相同或是父类返回类型的子类
访问修饰符不能比父类更严格
不能抛出比父类更宽泛的异常
2. @Override 注解
不是必须的,但建议使用
帮助编译器检查是否满足重写条件
提高代码可读性
三、super 关键字 1. 使用场景 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Vehicle { protected String brand; public Vehicle (String brand) { this .brand = brand; } public void start () { System.out.println("车辆启动" ); } } class Car extends Vehicle { private int year; public Car (String brand, int year) { super (brand); this .year = year; } @Override public void start () { super .start(); System.out.println(year + "年款" + brand + "汽车启动" ); } public void showInfo () { System.out.println("品牌: " + super .brand + ", 年份: " + year); } }
四、继承中的构造方法 1. 构造方法调用顺序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class GrandParent { public GrandParent () { System.out.println("GrandParent构造方法" ); } } class Parent extends GrandParent { public Parent () { System.out.println("Parent构造方法" ); } } class Child extends Parent { public Child () { System.out.println("Child构造方法" ); } } public class ConstructorTest { public static void main (String[] args) { new Child (); } }
2. super() 使用规则
必须出现在子类构造方法的第一行
如果没有显式调用 super(),编译器会自动添加无参 super()
如果父类没有无参构造方法,子类必须显式调用 super(参数)
五、final 关键字 1. final 用法 1 2 3 4 5 6 7 8 9 final class CannotInherit { final int MAX_VALUE = 100 ; final void cannotOverride () { System.out.println("这是最终方法" ); } }
六、Object 类 1. 常用方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Person { private String name; private int age; public Person (String name, int age) { this .name = name; this .age = age; } @Override public boolean equals (Object obj) { if (this == obj) return true ; if (obj == null || getClass() != obj.getClass()) return false ; Person person = (Person) obj; return age == person.age && name.equals(person.name); } @Override public int hashCode () { return Objects.hash(name, age); } @Override public String toString () { return "Person{name='" + name + "', age=" + age + "}" ; } }
七、抽象类与继承 1. 抽象类示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 abstract class Animal { protected String name; public Animal (String name) { this .name = name; } public abstract void makeSound () ; public void sleep () { System.out.println(name + "正在睡觉" ); } } class Cat extends Animal { public Cat (String name) { super (name); } @Override public void makeSound () { System.out.println(name + "说: 喵喵~" ); } }
八、继承与多态 1. 多态示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 class Employee { protected String name; protected double salary; public Employee (String name, double salary) { this .name = name; this .salary = salary; } public double calculateBonus () { return salary * 0.1 ; } } class Manager extends Employee { private double bonus; public Manager (String name, double salary, double bonus) { super (name, salary); this .bonus = bonus; } @Override public double calculateBonus () { return salary * 0.15 + bonus; } public void manageTeam () { System.out.println(name + "正在管理团队" ); } } public class PolymorphismDemo { public static void main (String[] args) { Employee emp1 = new Employee ("张三" , 5000 ); Employee emp2 = new Manager ("李四" , 8000 , 2000 ); System.out.println("张三的奖金: " + emp1.calculateBonus()); System.out.println("李四的奖金: " + emp2.calculateBonus()); if (emp2 instanceof Manager) { Manager manager = (Manager) emp2; manager.manageTeam(); } } }
九、继承最佳实践 1. 设计原则
里氏替换原则 :子类应该能够替换父类而不影响程序正确性
优先使用组合而非继承 :除非确实是”is-a”关系,否则考虑使用组合
避免过深的继承层次 :通常不超过3层
将通用方法放在高层类 :提高代码复用性
使用抽象类定义接口 :为子类提供通用实现
2. 示例:图形类继承体系 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 abstract class Shape { protected String color; public Shape (String color) { this .color = color; } public abstract double getArea () ; public abstract double getPerimeter () ; @Override public String toString () { return "Shape[color=" + color + "]" ; } } class Circle extends Shape { private double radius; public Circle (String color, double radius) { super (color); this .radius = radius; } @Override public double getArea () { return Math.PI * radius * radius; } @Override public double getPerimeter () { return 2 * Math.PI * radius; } @Override public String toString () { return "Circle[" + super .toString() + ",radius=" + radius + "]" ; } } class Rectangle extends Shape { private double length; private double width; public Rectangle (String color, double length, double width) { super (color); this .length = length; this .width = width; } @Override public double getArea () { return length * width; } @Override public double getPerimeter () { return 2 * (length + width); } @Override public String toString () { return "Rectangle[" + super .toString() + ",length=" + length + ",width=" + width + "]" ; } } public class ShapeDemo { public static void main (String[] args) { Shape[] shapes = { new Circle ("Red" , 5.0 ), new Rectangle ("Blue" , 4.0 , 6.0 ) }; for (Shape shape : shapes) { System.out.println(shape); System.out.println("Area: " + shape.getArea()); System.out.println("Perimeter: " + shape.getPerimeter()); System.out.println(); } } }
十、常见面试问题
继承和接口的区别 ?
继承:is-a关系,单继承,可以包含实现
接口:can-do关系,多实现,只有抽象方法(Java 8前)
什么时候用继承 ?
当两个类之间有明显的is-a关系时
需要复用父类代码时
需要实现多态时
为什么Java不支持多继承 ?
避免”钻石问题”(菱形继承问题)
简化语言设计,减少复杂性
构造方法能否被重写 ?
不能,构造方法不是成员方法
子类构造方法必须调用父类构造方法
如何防止类被继承 ?
使用final修饰类
将构造方法设为private,并提供静态工厂方法
Java 重写(Override)与重载(Overload)全面解析 下面我将系统地讲解 Java 中方法重写和方法重载的核心概念、使用场景和实际应用。
一、方法重写(Override)深度解析 1. 重写基础示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Animal { public void makeSound () { System.out.println("动物发出声音" ); } protected String getInfo () { return "动物基本信息" ; } } class Cat extends Animal { @Override public void makeSound () { System.out.println("喵喵叫" ); } @Override public String getInfo () { return "猫的信息: " + super .getInfo(); } } public class OverrideDemo { public static void main (String[] args) { Animal myCat = new Cat (); myCat.makeSound(); System.out.println(myCat.getInfo()); } }
2. 重写规则详解
方法签名必须相同 :方法名、参数列表完全一致
返回类型协变 :Java 5+ 允许子类方法返回父类方法返回类型的子类
访问修饰符不能更严格 :可以更宽松但不能更严格
异常限制 :
不能抛出新的检查异常
不能抛出比父类更宽泛的检查异常
可以抛出更具体的检查异常或不抛出异常
可以抛出任何非检查异常
不能重写 final/static/private 方法
3. @Override 注解的重要性 1 2 3 4 5 6 7 8 9 10 11 12 13 class Parent { public void show (String msg) { System.out.println("Parent: " + msg); } } class Child extends Parent { @Override public void sho (String msg) { System.out.println("Child: " + msg); } }
二、方法重载(Overload)深度解析 1. 重载基础示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class Calculator { public int add (int a, int b) { return a + b; } public int add (int a, int b, int c) { return a + b + c; } public double add (double a, double b) { return a + b; } public String add (String s, int n) { return s + n; } public String add (int n, String s) { return n + s; } } public class OverloadDemo { public static void main (String[] args) { Calculator calc = new Calculator (); System.out.println(calc.add(5 , 3 )); System.out.println(calc.add(5 , 3 , 2 )); System.out.println(calc.add(2.5 , 3.7 )); System.out.println(calc.add("ID" , 100 )); System.out.println(calc.add(100 , "ID" )); } }
2. 重载规则详解
必须改变参数列表 :
可以改变的内容 :
不能仅靠返回类型区分重载
自动类型转换影响重载解析
3. 重载解析过程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class OverloadResolution { public void process (int i) { System.out.println("处理整数: " + i); } public void process (double d) { System.out.println("处理浮点数: " + d); } public void process (String s) { System.out.println("处理字符串: " + s); } public static void main (String[] args) { OverloadResolution resolver = new OverloadResolution (); resolver.process(10 ); resolver.process(10.0 ); resolver.process("10" ); resolver.process('A' ); resolver.process(10L ); } }
三、重写与重载对比 1. 核心区别对照表
特性
方法重写(Override)
方法重载(Overload)
发生位置
子类与父类之间
同一个类或父子类之间
方法签名
必须相同
必须不同
返回类型
相同或子类(协变返回)
可以不同
访问修饰符
不能比父类更严格
可以不同
异常抛出
不能更宽泛
可以不同
调用机制
运行时根据对象类型决定
编译时根据参数类型决定
多态性体现
子类替换父类行为
同一方法名处理不同类型参数
2. 典型场景示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class OverrideVsOverload { static class Base { public void execute (int num) { System.out.println("Base execute with int: " + num); } public void show () { System.out.println("Base show" ); } } static class Derived extends Base { public void execute (String str) { System.out.println("Derived execute with String: " + str); } @Override public void show () { System.out.println("Derived show" ); } } public static void main (String[] args) { Base obj = new Derived (); ((Derived)obj).execute("test" ); obj.show(); } }
四、高级话题与应用场景 1. 构造方法的重载 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 class Person { private String name; private int age; public Person () { this ("无名氏" , 18 ); } public Person (String name) { this (name, 18 ); } public Person (String name, int age) { this .name = name; this .age = age; } public void introduce () { System.out.println("我是" + name + ",今年" + age + "岁" ); } public void introduce (String greeting) { System.out.println(greeting + ",我是" + name); } } public class ConstructorOverload { public static void main (String[] args) { Person p1 = new Person (); Person p2 = new Person ("张三" ); Person p3 = new Person ("李四" , 25 ); p1.introduce(); p2.introduce("你好" ); } }
2. 重写 equals 和 hashCode 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 class Student { private String id; private String name; public Student (String id, String name) { this .id = id; this .name = name; } @Override public boolean equals (Object o) { if (this == o) return true ; if (o == null || getClass() != o.getClass()) return false ; Student student = (Student) o; return id.equals(student.id) && name.equals(student.name); } @Override public int hashCode () { return Objects.hash(id, name); } @Override public String toString () { return "Student{id='" + id + "', name='" + name + "'}" ; } } public class ObjectMethodOverride { public static void main (String[] args) { Student s1 = new Student ("1001" , "张三" ); Student s2 = new Student ("1001" , "张三" ); Student s3 = new Student ("1002" , "李四" ); System.out.println("s1.equals(s2): " + s1.equals(s2)); System.out.println("s1.equals(s3): " + s1.equals(s3)); System.out.println("s1 hashCode: " + s1.hashCode()); System.out.println("s2 hashCode: " + s2.hashCode()); System.out.println("s1 toString: " + s1); } }
3. 桥接方法与重写 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 interface Processor <T> { void process (T t) ; } class StringProcessor implements Processor <String> { @Override public void process (String s) { System.out.println("处理字符串: " + s); } } public class BridgeMethod { public static void main (String[] args) { Processor<String> processor = new StringProcessor (); processor.process("测试" ); for (Method method : StringProcessor.class.getMethods()) { if (method.getName().equals("process" )) { System.out.println(method + " is bridge: " + method.isBridge()); } } } }
五、常见问题与最佳实践 1. 常见陷阱
意外重载而非重写 :
1 2 3 4 5 6 7 8 class Parent { void doSomething (List<String> list) {} } class Child extends Parent { void doSomething (ArrayList<String> list) {} }
**静态方法”重写”**:
1 2 3 4 5 6 7 8 9 10 11 12 class Parent { static void staticMethod () { System.out.println("Parent static" ); } } class Child extends Parent { static void staticMethod () { System.out.println("Child static" ); } }
2. 最佳实践
总是使用 @Override 注解 :避免意外重载而非重写
保持重写方法行为一致 :遵守里氏替换原则
谨慎重载可变参数方法 :容易导致混淆
避免过度重载 :考虑使用不同方法名提高可读性
文档化重写方法 :说明与父类方法的差异
Java 面向对象核心特性全面解析(多态、抽象类、封装和接口这四大面向对象特性) 下面我将依次详细讲解Java面向对象编程的四大核心特性:多态、抽象类、封装和接口。
一、多态(Polymorphism) 1. 多态基础 多态是指同一操作作用于不同对象时,可以有不同的解释和执行结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 class Animal { public void makeSound () { System.out.println("动物发出声音" ); } } class Dog extends Animal { @Override public void makeSound () { System.out.println("汪汪叫" ); } public void fetch () { System.out.println("叼回飞盘" ); } } class Cat extends Animal { @Override public void makeSound () { System.out.println("喵喵叫" ); } public void scratch () { System.out.println("挠沙发" ); } } public class PolymorphismDemo { public static void main (String[] args) { Animal myPet1 = new Dog (); Animal myPet2 = new Cat (); myPet1.makeSound(); myPet2.makeSound(); if (myPet1 instanceof Dog) { ((Dog)myPet1).fetch(); } } public static void animalSound (Animal animal) { animal.makeSound(); } }
2. 多态实现形式
**方法重写(Override)**:子类重写父类方法
**方法重载(Overload)**:同名不同参
接口实现 :不同类实现同一接口
抽象类和抽象方法 :提供统一接口,具体实现由子类完成
3. 多态的优势
可替换性 :子类对象可以替换父类对象
可扩展性 :新增子类不影响已有代码
灵活性 :同一方法不同表现
简化性 :统一接口处理不同对象
二、抽象类(Abstract Class) 1. 抽象类基础 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 abstract class Shape { protected String color; public Shape (String color) { this .color = color; } public abstract double getArea () ; public String getColor () { return color; } public static void printShapeInfo (Shape shape) { System.out.println("颜色: " + shape.color); System.out.println("面积: " + shape.getArea()); } } class Circle extends Shape { private double radius; public Circle (String color, double radius) { super (color); this .radius = radius; } @Override public double getArea () { return Math.PI * radius * radius; } } class Rectangle extends Shape { private double length; private double width; public Rectangle (String color, double length, double width) { super (color); this .length = length; this .width = width; } @Override public double getArea () { return length * width; } } public class AbstractClassDemo { public static void main (String[] args) { Shape circle = new Circle ("红色" , 5.0 ); Shape rectangle = new Rectangle ("蓝色" , 4.0 , 6.0 ); Shape.printShapeInfo(circle); Shape.printShapeInfo(rectangle); } }
2. 抽象类特点
不能被实例化 :只能被继承
可以包含抽象方法 :没有实现的方法,必须被子类实现
可以包含具体方法 :有实现的方法,子类可以直接使用或重写
可以包含成员变量 :可以是各种访问修饰符
构造方法 :虽然不能实例化,但可以有构造方法供子类调用
3. 抽象类应用场景
定义通用接口 :为相关类提供统一的操作规范
部分实现 :提供部分通用实现,子类完成剩余部分
模板方法模式 :定义算法骨架,具体步骤由子类实现
三、封装(Encapsulation) 1. 封装基础实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 class BankAccount { private String accountNumber; private double balance; private String owner; public BankAccount (String accountNumber, String owner, double initialBalance) { this .accountNumber = accountNumber; this .owner = owner; this .balance = initialBalance; } public void deposit (double amount) { if (amount > 0 ) { balance += amount; System.out.println("存款成功,当前余额: " + balance); } else { System.out.println("存款金额必须大于0" ); } } public void withdraw (double amount) { if (amount > 0 && amount <= balance) { balance -= amount; System.out.println("取款成功,当前余额: " + balance); } else { System.out.println("取款失败,金额无效或余额不足" ); } } public double getBalance () { return balance; } public String getAccountNumber () { return accountNumber; } public String getOwner () { return owner; } public void setOwner (String owner) { if (owner != null && !owner.trim().isEmpty()) { this .owner = owner; } } } public class EncapsulationDemo { public static void main (String[] args) { BankAccount account = new BankAccount ("123456789" , "张三" , 1000 ); account.deposit(500 ); account.withdraw(200 ); account.withdraw(2000 ); System.out.println("账户余额: " + account.getBalance()); } }
2. 封装原则
最小访问原则 :使用最严格的访问修饰符
数据隐藏 :字段通常设为private
受控访问 :通过public方法暴露必要操作
不变性保护 :对不应修改的字段不提供setter
3. 封装优势
安全性 :防止外部直接访问内部数据
灵活性 :可以修改内部实现而不影响外部代码
可维护性 :易于修改和扩展
数据验证 :可以在方法中添加业务规则验证
四、接口(Interface) 1. 接口基础 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 interface Switchable { int MAX_BRIGHTNESS = 100 ; void turnOn () ; void turnOff () ; default void adjustBrightness (int level) { System.out.println("调整亮度至: " + Math.min(level, MAX_BRIGHTNESS)); } static void printMaxBrightness () { System.out.println("最大亮度: " + MAX_BRIGHTNESS); } } interface SmartDevice extends Switchable { void connectToWifi (String ssid) ; void runApp (String appName) ; } class LightBulb implements Switchable { @Override public void turnOn () { System.out.println("灯泡亮起" ); } @Override public void turnOff () { System.out.println("灯泡熄灭" ); } } class SmartTV implements SmartDevice { @Override public void turnOn () { System.out.println("智能电视开机" ); } @Override public void turnOff () { System.out.println("智能电视关机" ); } @Override public void connectToWifi (String ssid) { System.out.println("连接到WiFi: " + ssid); } @Override public void runApp (String appName) { System.out.println("运行应用: " + appName); } @Override public void adjustBrightness (int level) { System.out.println("智能电视亮度调节至: " + level); } } public class InterfaceDemo { public static void main (String[] args) { Switchable bulb = new LightBulb (); bulb.turnOn(); bulb.adjustBrightness(80 ); bulb.turnOff(); SmartTV tv = new SmartTV (); tv.turnOn(); tv.connectToWifi("HomeWiFi" ); tv.runApp("Netflix" ); tv.adjustBrightness(60 ); tv.turnOff(); Switchable.printMaxBrightness(); } }
2. 接口特性
多继承 :一个类可以实现多个接口
默认方法 :Java 8+ 允许接口包含具体实现的方法
静态方法 :Java 8+ 允许接口包含静态方法
私有方法 :Java 9+ 允许接口包含私有方法
常量定义 :接口中定义的变量默认是public static final
3. 接口与抽象类对比
特性
接口(Interface)
抽象类(Abstract Class)
实例化
不能
不能
方法实现
Java 8+ 可以有默认方法
可以有具体方法
字段
只能是常量(public static final)
可以是普通成员变量
构造方法
没有
有
多继承
一个类可实现多个接口
一个类只能继承一个抽象类
访问修饰符
方法默认public
方法可以有各种访问修饰符
设计目的
定义行为规范
提供通用实现和规范
五、四大特性综合应用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 abstract class Vehicle { private String model; protected Vehicle (String model) { this .model = model; } public String getModel () { return model; } public abstract void start () ; public abstract void stop () ; public void displayInfo () { System.out.println("车型: " + model); } } interface Electric { void charge () ; int getBatteryLevel () ; } class ElectricCar extends Vehicle implements Electric { private int batteryLevel; public ElectricCar (String model) { super (model); this .batteryLevel = 100 ; } @Override public void start () { System.out.println(getModel() + "电动车静音启动" ); } @Override public void stop () { System.out.println(getModel() + "电动车再生制动停止" ); } @Override public void charge () { batteryLevel = 100 ; System.out.println(getModel() + "已充满电" ); } @Override public int getBatteryLevel () { return batteryLevel; } public void autoPilot () { System.out.println(getModel() + "自动驾驶模式激活" ); } } public class OOPIntegration { public static void main (String[] args) { Vehicle[] vehicles = { new ElectricCar ("Tesla Model S" ), }; for (Vehicle vehicle : vehicles) { vehicle.displayInfo(); vehicle.start(); if (vehicle instanceof Electric) { Electric electric = (Electric) vehicle; System.out.println("电量: " + electric.getBatteryLevel() + "%" ); electric.charge(); } if (vehicle instanceof ElectricCar) { ((ElectricCar)vehicle).autoPilot(); } vehicle.stop(); System.out.println(); } } }
六、设计原则与最佳实践 1. SOLID原则
**单一职责原则(SRP)**:一个类只负责一个功能领域
**开闭原则(OCP)**:对扩展开放,对修改关闭
**里氏替换原则(LSP)**:子类必须能替换父类
**接口隔离原则(ISP)**:客户端不应依赖它不需要的接口
**依赖倒置原则(DIP)**:依赖抽象而非具体实现
2. 面向对象设计技巧
优先使用组合而非继承 :除非明确is-a关系
面向接口编程 :提高灵活性和可扩展性
合理使用访问控制 :遵循最小权限原则
避免过度设计 :根据实际需求设计类结构
保持类和方法小巧 :单一职责,高内聚低耦合
Java 枚举、包与反射全面解析 下面我将系统地讲解 Java 中枚举、包和反射的核心概念与使用场景。
一、枚举(Enum) 1. 枚举基础 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 public enum Day { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY } public enum Planet { MERCURY(3.303e+23 , 2.4397e6 ), VENUS(4.869e+24 , 6.0518e6 ), EARTH(5.976e+24 , 6.37814e6 ); private final double mass; private final double radius; Planet(double mass, double radius) { this .mass = mass; this .radius = radius; } public double surfaceGravity () { return 6.67300E-11 * mass / (radius * radius); } public double surfaceWeight (double otherMass) { return otherMass * surfaceGravity(); } } public class EnumDemo { public static void main (String[] args) { Day today = Day.WEDNESDAY; System.out.println("Today is: " + today); System.out.println("All days:" ); for (Day day : Day.values()) { System.out.println(day); } double earthWeight = 70 ; double mass = earthWeight / Planet.EARTH.surfaceGravity(); for (Planet p : Planet.values()) { System.out.printf("Your weight on %s is %f%n" , p, p.surfaceWeight(mass)); } switch (today) { case MONDAY: System.out.println("星期一综合症" ); break ; case FRIDAY: System.out.println("感谢上帝,今天是星期五" ); break ; default : System.out.println("普通工作日" ); } } }
2. 枚举高级特性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 public enum Operation { PLUS("+" ) { public double apply (double x, double y) { return x + y; } }, MINUS("-" ) { public double apply (double x, double y) { return x - y; } }, TIMES("*" ) { public double apply (double x, double y) { return x * y; } }, DIVIDE("/" ) { public double apply (double x, double y) { return x / y; } }; private final String symbol; Operation(String symbol) { this .symbol = symbol; } @Override public String toString () { return symbol; } public abstract double apply (double x, double y) ; public static Operation fromSymbol (String symbol) { for (Operation op : Operation.values()) { if (op.symbol.equals(symbol)) { return op; } } throw new IllegalArgumentException ("未知运算符: " + symbol); } } public class AdvancedEnum { public static void main (String[] args) { double x = 10.5 ; double y = 2.5 ; for (Operation op : Operation.values()) { System.out.printf("%f %s %f = %f%n" , x, op, y, op.apply(x, y)); } Operation op = Operation.fromSymbol("*" ); System.out.println("10 * 5 = " + op.apply(10 , 5 )); } }
3. 枚举最佳实践
单例模式实现 :枚举是实现单例的最佳方式
策略模式 :利用枚举的抽象方法实现策略模式
状态机 :适合用枚举实现有限状态机
替代常量 :比常量类更类型安全
二、包(Package) 1. 包基础使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package com.example.utils;public class MathUtils { public static int add (int a, int b) { return a + b; } public static int factorial (int n) { if (n <= 1 ) return 1 ; return n * factorial(n - 1 ); } } package com.example;import com.example.utils.MathUtils;import static com.example.utils.MathUtils.add; public class Main { public static void main (String[] args) { System.out.println(com.example.utils.MathUtils.factorial(5 )); System.out.println(MathUtils.add(3 , 4 )); System.out.println(add(5 , 6 )); } }
2. 包的组织原则
功能相关性 :相同功能的类放在同一包中
层次结构 :按功能模块分层,如com.公司名.项目名.模块名
访问控制 :利用包级私有(package-private)保护实现细节
避免循环依赖 :包之间不应有循环依赖关系
3. JDK常用包
包名
描述
java.lang
核心类(自动导入)
java.util
工具类和集合框架
java.io
输入输出相关
java.net
网络编程
java.sql
数据库操作
java.time
日期时间API
三、反射(Reflection) 1. 反射基础 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import java.lang.reflect.*;public class ReflectionBasics { public static void main (String[] args) throws Exception { Class<?> stringClass1 = String.class; Class<?> stringClass2 = "Hello" .getClass(); Class<?> stringClass3 = Class.forName("java.lang.String" ); System.out.println(stringClass1 == stringClass2); System.out.println(stringClass2 == stringClass3); System.out.println("类名: " + stringClass1.getName()); System.out.println("简单类名: " + stringClass1.getSimpleName()); System.out.println("是否是接口: " + stringClass1.isInterface()); int modifiers = stringClass1.getModifiers(); System.out.println("修饰符: " + Modifier.toString(modifiers)); Class<?> superClass = stringClass1.getSuperclass(); System.out.println("父类: " + superClass.getName()); Class<?>[] interfaces = stringClass1.getInterfaces(); System.out.println("实现的接口:" ); for (Class<?> iface : interfaces) { System.out.println(" " + iface.getName()); } } }
2. 反射操作类成员 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 import java.lang.reflect.*;import java.util.*;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; } public int getAge () { return age; } private void privateMethod () { System.out.println("私有方法被调用" ); } } public class ReflectionMembers { public static void main (String[] args) throws Exception { Class<?> personClass = Person.class; System.out.println("构造方法:" ); Constructor<?>[] constructors = personClass.getConstructors(); for (Constructor<?> c : constructors) { System.out.println(" " + c); } Constructor<?> constructor = personClass.getConstructor(String.class, int .class); Object person = constructor.newInstance("张三" , 25 ); System.out.println(((Person)person).getName()); System.out.println("\n字段:" ); Field[] fields = personClass.getDeclaredFields(); for (Field field : fields) { System.out.println(" " + field); } Field nameField = personClass.getDeclaredField("name" ); nameField.setAccessible(true ); nameField.set(person, "李四" ); System.out.println("修改后name: " + nameField.get(person)); System.out.println("\n方法:" ); Method[] methods = personClass.getDeclaredMethods(); for (Method method : methods) { System.out.println(" " + method); } Method getNameMethod = personClass.getMethod("getName" ); System.out.println("调用getName: " + getNameMethod.invoke(person)); Method privateMethod = personClass.getDeclaredMethod("privateMethod" ); privateMethod.setAccessible(true ); privateMethod.invoke(person); } }
3. 反射应用场景
动态代理 :AOP实现的基础
注解处理 :框架中处理自定义注解
类浏览器/IDE :获取类结构信息
序列化/反序列化 :JSON/XML库的实现
插件架构 :动态加载类
测试工具 :Mock框架的实现
4. 反射性能与安全 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public class ReflectionPerformance { private static final int ITERATIONS = 1000000 ; public static void main (String[] args) throws Exception { long start = System.nanoTime(); Person person = new Person (); for (int i = 0 ; i < ITERATIONS; i++) { person.getName(); } long directTime = System.nanoTime() - start; Method getNameMethod = Person.class.getMethod("getName" ); start = System.nanoTime(); for (int i = 0 ; i < ITERATIONS; i++) { getNameMethod.invoke(person); } long reflectionTime = System.nanoTime() - start; getNameMethod.setAccessible(true ); start = System.nanoTime(); for (int i = 0 ; i < ITERATIONS; i++) { getNameMethod.invoke(person); } long reflectionAccessibleTime = System.nanoTime() - start; System.out.printf("直接调用耗时: %,d ns%n" , directTime); System.out.printf("反射调用耗时: %,d ns%n" , reflectionTime); System.out.printf("反射(setAccessible)调用耗时: %,d ns%n" , reflectionAccessibleTime); SecurityManager sm = System.getSecurityManager(); if (sm != null ) { sm.checkPermission(new ReflectPermission ("suppressAccessChecks" )); } } }
性能提示 :
反射操作比直接调用慢
通过setAccessible(true)可以提升性能
缓存Method/Field/Constructor对象避免重复查找
安全考虑 :
反射可以绕过访问控制检查
安全管理器可以限制反射操作
生产环境应谨慎使用反射
四、综合应用示例 1. 注解处理器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 import java.lang.annotation.*;import java.lang.reflect.*;@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @interface Test { int priority () default 5 ; } class TestRunner { public static void runTests (Class<?> testClass) throws Exception { Object testInstance = testClass.getDeclaredConstructor().newInstance(); Method[] methods = testClass.getDeclaredMethods(); Arrays.sort(methods, (m1, m2) -> { Test t1 = m1.getAnnotation(Test.class); Test t2 = m2.getAnnotation(Test.class); int p1 = t1 != null ? t1.priority() : 0 ; int p2 = t2 != null ? t2.priority() : 0 ; return Integer.compare(p2, p1); }); for (Method method : methods) { if (method.getAnnotation(Test.class) != null ) { System.out.println("Running test: " + method.getName()); method.invoke(testInstance); } } } } class MyTests { @Test(priority = 1) public void testFeatureA () { System.out.println("Testing important feature A" ); } @Test(priority = 3) public void testFeatureB () { System.out.println("Testing feature B" ); } @Test public void testFeatureC () { System.out.println("Testing feature C" ); } public void helperMethod () { } } public class AnnotationProcessor { public static void main (String[] args) throws Exception { TestRunner.runTests(MyTests.class); } }
2. 简单DI容器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 import java.lang.annotation.*;import java.lang.reflect.*;import java.util.*;@Retention(RetentionPolicy.RUNTIME) @interface Inject {}class SimpleDIContainer { private Map<Class<?>, Object> instances = new HashMap <>(); public void register (Class<?> clazz) throws Exception { Constructor<?>[] constructors = clazz.getConstructors(); if (constructors.length != 1 ) { throw new RuntimeException ("类必须有且只有一个公共构造方法" ); } Constructor<?> constructor = constructors[0 ]; Object[] params = Arrays.stream(constructor.getParameterTypes()) .map(paramType -> { if (!instances.containsKey(paramType)) { throw new RuntimeException ("未注册的依赖类型: " + paramType); } return instances.get(paramType); }) .toArray(); Object instance = constructor.newInstance(params); instances.put(clazz, instance); } public <T> T getInstance (Class<T> clazz) { return clazz.cast(instances.get(clazz)); } public void injectFields (Object obj) throws Exception { for (Field field : obj.getClass().getDeclaredFields()) { if (field.isAnnotationPresent(Inject.class)) { field.setAccessible(true ); Class<?> fieldType = field.getType(); if (!instances.containsKey(fieldType)) { throw new RuntimeException ("未注册的依赖类型: " + fieldType); } field.set(obj, instances.get(fieldType)); } } } } class ServiceA { public void execute () { System.out.println("ServiceA executed" ); } } class ServiceB { @Inject private ServiceA serviceA; public void doWork () { System.out.println("ServiceB starting work" ); serviceA.execute(); System.out.println("ServiceB finished work" ); } } public class DIContainerDemo { public static void main (String[] args) throws Exception { SimpleDIContainer container = new SimpleDIContainer (); container.register(ServiceA.class); container.register(ServiceB.class); ServiceB serviceB = container.getInstance(ServiceB.class); serviceB.doWork(); } }
五、关键知识点总结
枚举 :
类型安全的常量集合
可以包含字段、方法和构造方法
适合实现单例、策略模式等
包 :
组织类和接口的命名空间
控制访问权限(包级私有)
避免命名冲突
反射 :
运行时检查和操作类、方法、字段
强大的但应谨慎使用
性能开销较大,适合框架开发