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 关键字 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 类 Object 类是 Java 中所有类的超类,它定义了所有类的默认行为。
1. 常用方法 以下是常用的方法
方法
描述
equals()
比较对象是否相等
hashCode()
获取对象的哈希码
toString()
返回对象的字符串表示
clone()
克隆对象
finalize()
垃圾回收前调用
wait()
线程等待
notify()
线程通知
notifyAll()
线程通知所有
由于toString方法的访问结果是对象的哈希码,所以在实际开发中,通常需要重写toString方法,以便返回有意义的字符串表示。
在重写的时候可以自动拼接,无需手动书写show方法,在idea中键入toString即可
equals和 == 的区别: 重写equals前和==的区别和重写equals后和==的区别
重写equals前和==的区别:
==:比较的是两个对象的地址值
equals:默认比较的也是两个对象的地址值
重写equals后和==的区别:
==:比较的是两个对象的地址值
equals:比较的是两个对象的内容是否相同
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是一种面向对象的程序设计语言,我们在面向对象的思想的指引下编写程序。
面向过程(pop)
这是一种以过程为中心的编程思想。把事情拆成几个步骤然后按照一定的顺序执行。(强调过程)
面向对象(oop)
面向对象就是把现实世界的事物抽象成对象,这些对象都是唯一的并且都拥有自己的属性和行为。我们就可以通过调用这些对象的方法,属性去调用对象(强调对象)
区别:
面向过程:强调的是功能行为
面向对象:强调具备功能的对象
面向对象的三大特征:
类和对象是面向对象的核心概念。具体使用方式见:[类和对象详解](http://xhayane.top/2025/03/31/java%E5%BF%AB%E9%80%9F%E5%AD%A6%E4%B9%A0%E9%80%9F%E6%9F%A5%EF%BC%881%EF%BC%89/)
什么是类 类是对一类事物的描述,是抽象的、概念上的定义。例如:猫,狗,人,手机,电脑,电视,书,学生,老师,等等。
什么是对象 对象是实际存在的该类事物的每个个体,因而也称为实例(instance)。例如:张三,李四,王五,小明,小红,小绿,等等。
类和对象的关系 类是对象的模板,对象是类的实例。 -类是对一类事物的描述,是抽象
的、概念上的定义 -对象是一类实例化的存在,是具体
的、可以操作的。
其余内容请跳转[类和对象详解](http://xhayane.top/2025/03/31/java%E5%BF%AB%E9%80%9F%E5%AD%A6%E4%B9%A0%E9%80%9F%E6%9F%A5%EF%BC%881%EF%BC%89/)**java对象和类的全面解析**
Java 面向对象核心特性全面解析(多态、抽象类、封装和接口这四大面向对象特性) 下面我将依次详细讲解Java面向对象编程的四大核心特性:多态、抽象类、封装和接口 。
问到三大特性就把接口去掉就行
一、多态(Polymorphism) 1. 多态基础 多态(对象的多种状态)同一个行为具有不同的表现形态的能力,对象多种表现形态的能力
多态的前提: 1.要有继承关系1 2 3 4 public interface MyInterFace { String USERNAME="admin123" ; }
2.子类要重写父类的方法 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 26 class 员工 { public void 工作() { System.out.println("处理行政事务" ); } } class 程序员 extends 员工 { @Override public void 工作() { System.out.println("写代码" ); } } class 销售 extends 员工 { @Override public void 工作() { System.out.println("拜访客户" ); } } 员工 员工1 = new 程序员(); 员工 员工2 = new 销售(); 员工1. 工作(); 员工2. 工作();
关键点:
编译时(写代码时):员工1.工作()
看起来调用的是父类方法。
运行时(实际执行时):JVM 会根据对象的实际类型(程序员
或 销售
)调用对应的方法。
接口实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 interface 可演讲 { void 演讲(); } class 程序员 implements 可演讲 { public void 演讲() { System.out.println("讲技术方案" ); } } class 销售 implements 可演讲 { public void 演讲() { System.out.println("讲产品优势" ); } } 可演讲 人1 = new 程序员(); 可演讲 人2 = new 销售(); 人1. 演讲(); 人2. 演讲();
多态的操作应用 引用类型转换 多态的转型分为向上转型和向下转型两种:
向上转型
父类引用指向子类实例,这种转换其实就是上面的多态写法,创建一个子类的对象,我们把它当作父类 来看待,我们创建一个学生,把他当作人来看待,这种肯定使可以的。
注意事项
向上转向是安全的,对象的范围有小变大的,弊端是子类特有的方法无法调用
,类似于我们基本数据类 型中的自动转换。
向下转型父类类型向子类类型向下转换的过程,这个过程是强制的。(类似强制类型转换)
类型转换异常 1 2 3 4 5 6 Animal a = new Cat (); Cat c=(Cat)a; Dog d=(Dog)a; d.eat(); d.kanMen();
如上所示: 这段代码可以通过编译,但是运行的时间,却报错了 ClassCastException
,类型转换异常,这是因为 明明创建了Cat类型对象,运行时,当然不能转换为Dog对象,这两个类型并没有任何继承关系,不符 合类型转换的定义。为了避免 ClassCastException
的发生,java提供了instanceof
关键字,给引用变 量做类型校验1 2 变量名 instanceof 数据类型 如果变量属于该数据类型,返回true,如果变量不属于该数据类型,返回false
1 2 3 4 5 6 7 8 9 10 11 Animal a = new Cat (); if (a instanceof Cat){ Cat c=(Cat)a; c.eat(); c.zhuaLaoShu(); }else if (a instanceof Dog){ Dog d=(Dog)a; d.eat(); d.kanMen(); }
== 实战部分在最后 ==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. 接口基础 先补充个东西:大小写切换快捷键为Ctrl+Shift+CapsLk
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(); } }
五、关键知识点总结
枚举 :
类型安全的常量集合
可以包含字段、方法和构造方法
适合实现单例、策略模式等
包 :
组织类和接口的命名空间
控制访问权限(包级私有)
避免命名冲突
反射 :
运行时检查和操作类、方法、字段
强大的但应谨慎使用
性能开销较大,适合框架开发