高级面向对象特性
本章内容
本章介绍 Java 的高级面向对象特性:抽象类、接口、枚举、匿名内部类和 Java Bean 规范。
一、抽象类(Abstract Class)
1.1 抽象类的概念
抽象类是不能被实例化的类,通常包含一个或多个抽象方法:
// 抽象类
public abstract class Animal {
protected String name;
protected int age;
// 构造方法
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
// 抽象方法:子类必须实现
public abstract void makeSound();
public abstract void move();
// 具体方法:子类可以直接使用
public void eat() {
System.out.println(name + "正在吃东西");
}
public void sleep() {
System.out.println(name + "正在睡觉");
}
public void showInfo() {
System.out.println("动物:" + name + ",年龄:" + age);
}
}
// 具体子类必须实现所有抽象方法
public class Dog extends Animal {
private String breed;
public Dog(String name, int age, String breed) {
super(name, age);
this.breed = breed;
}
@Override
public void makeSound() {
System.out.println(name + "汪汪叫");
}
@Override
public void move() {
System.out.println(name + "在地上跑");
}
public void wagTail() {
System.out.println(name + "摇尾巴");
}
}
public class Bird extends Animal {
private double wingspan;
public Bird(String name, int age, double wingspan) {
super(name, age);
this.wingspan = wingspan;
}
@Override
public void makeSound() {
System.out.println(name + "叽叽喳喳");
}
@Override
public void move() {
System.out.println(name + "在天空飞翔,翼展:" + wingspan + "米");
}
}
1.2 抽象类的特点
public abstract class Shape {
protected String color;
protected static int count = 0;
// 抽象类可以有构造方法
public Shape(String color) {
this.color = color;
count++;
}
// 抽象类可以有静态方法
public static int getCount() {
return count;
}
// 抽象方法
public abstract double calculateArea();
public abstract double calculatePerimeter();
// 具体方法
public void displayInfo() {
System.out.println("颜色:" + color + ",面积:" + calculateArea());
}
// 抽象类可以有 final 方法
public final void printType() {
System.out.println("这是一个几何图形");
}
}
二、接口(Interface)
2.1 接口的基本概念
接口定义了类必须实现的方法规范:
// 接口定义
public interface Drawable {
// 接口中的变量默认是 public static final
int MAX_SIZE = 1000;
String DEFAULT_COLOR = "black";
// 抽象方法(默认 public abstract)
void draw();
void erase();
// Java 8+ 默认方法
default void display() {
System.out.println("显示图形");
}
// Java 8+ 静态方法
static void printInfo() {
System.out.println("这是一个可绘制的接口");
}
// Java 9+ 私有方法
private void helper() {
System.out.println("辅助方法");
}
}
// 实现接口
public class Circle implements Drawable {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public void draw() {
System.out.println("绘制半径为 " + radius + " 的圆形");
}
@Override
public void erase() {
System.out.println("擦除圆形");
}
// 可以重写默认方法
@Override
public void display() {
System.out.println("显示圆形,半径:" + radius);
}
}
2.2 多接口实现
interface Flyable {
void fly();
default void takeOff() {
System.out.println("起飞");
}
}
interface Swimmable {
void swim();
default void dive() {
System.out.println("潜水");
}
}
// 一个类可以实现多个接口
public class Duck implements Flyable, Swimmable {
private String name;
public Duck(String name) {
this.name = name;
}
@Override
public void fly() {
System.out.println(name + "在天空中飞翔");
}
@Override
public void swim() {
System.out.println(name + "在水中游泳");
}
// 如果多个接口有相同的默认方法,必须重写
public void move() {
System.out.println(name + "可以飞行和游泳");
}
}
2.3 接口继承
// 基础接口
interface Vehicle {
void start();
void stop();
}
// 接口可以继承接口
interface Car extends Vehicle {
void drive();
default void honk() {
System.out.println("按喇叭");
}
}
interface ElectricVehicle extends Vehicle {
void charge();
default void showBatteryLevel() {
System.out.println("显示电量");
}
}
// 接口可以继承多个接口
interface ElectricCar extends Car, ElectricVehicle {
void enableAutoPilot();
}
// 实现类
public class Tesla implements ElectricCar {
@Override
public void start() {
System.out.println("特斯拉启动");
}
@Override
public void stop() {
System.out.println("特斯拉停止");
}
@Override
public void drive() {
System.out.println("特斯拉行驶");
}
@Override
public void charge() {
System.out.println("特斯拉充电");
}
@Override
public void enableAutoPilot() {
System.out.println("启用自动驾驶");
}
}
2.4 抽象类 vs 接口
| 特性 | 抽象类 | 接口 |
|---|---|---|
| 关键字 | abstract class | interface |
| 继承 | 单继承 | 多实现 |
| 构造方法 | 可以有 | 不能有 |
| 成员变量 | 任意访问修饰符 | public static final |
| 方法类型 | 抽象方法 + 具体方法 | 抽象方法 + 默认方法 + 静态方法 |
| 实例化 | 不能直接实例化 | 不能实例化 |
| 使用场景 | 有共同实现的相关类 | 定义行为规范 |
// 使用场景示例
// 抽象类:适用于有共同实现的相关类
abstract class DatabaseConnection {
protected String url;
protected String username;
public DatabaseConnection(String url, String username) {
this.url = url;
this.username = username;
}
// 共同的连接逻辑
public void connect() {
System.out.println("连接到数据库:" + url);
}
// 不同数据库的具体实现
public abstract void executeQuery(String sql);
}
// 接口:适用于定义行为规范
interface Serializable {
void serialize();
void deserialize();
}
interface Cacheable {
void cache();
void evict();
}
三、枚举(Enum)
3.1 基本枚举
// 简单枚举
public enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
// 使用枚举
public class EnumDemo {
public static void main(String[] args) {
Day today = Day.MONDAY;
System.out.println("今天是:" + today);
System.out.println("序号:" + today.ordinal());
System.out.println("名称:" + today.name());
// 枚举比较
if (today == Day.MONDAY) {
System.out.println("今天是星期一");
}
// switch 语句
switch (today) {
case MONDAY:
System.out.println("周一,新的开始");
break;
case FRIDAY:
System.out.println("周五,快到周末了");
break;
case SATURDAY:
case SUNDAY:
System.out.println("周末,休息时间");
break;
default:
System.out.println("工作日");
}
// 遍历所有枚举值
for (Day day : Day.values()) {
System.out.println(day + " (" + day.ordinal() + ")");
}
}
}
3.2 带属性和方法的枚举
public enum Planet {
// 枚举常量,带参数
MERCURY(3.303e+23, 2.4397e6),
VENUS(4.869e+24, 6.0518e6),
EARTH(5.976e+24, 6.37814e6),
MARS(6.421e+23, 3.3972e6);
// 枚举属性
private final double mass; // 质量(千克)
private final double radius; // 半径(米)
// 枚举构造方法(必须是私有的)
private Planet(double mass, double radius) {
this.mass = mass;
this.radius = radius;
}
// 枚举方法
public double getMass() {
return mass;
}
public double getRadius() {
return radius;
}
// 计算表面重力
public double surfaceGravity() {
final double G = 6.67300E-11;
return G * mass / (radius * radius);
}
// 计算在该星球上的重量
public double surfaceWeight(double otherMass) {
return otherMass * surfaceGravity();
}
}
// 使用示例
public class PlanetDemo {
public static void main(String[] args) {
double earthWeight = 70.0; // 地球上的重量(千克)
for (Planet planet : Planet.values()) {
double weight = planet.surfaceWeight(earthWeight);
System.out.printf("在 %s 上的重量:%.2f kg%n", planet, weight);
}
}
}
3.3 实现接口的枚举
interface Operation {
double apply(double x, double y);
}
public enum BasicOperation implements Operation {
PLUS("+") {
@Override
public double apply(double x, double y) {
return x + y;
}
},
MINUS("-") {
@Override
public double apply(double x, double y) {
return x - y;
}
},
TIMES("*") {
@Override
public double apply(double x, double y) {
return x * y;
}
},
DIVIDE("/") {
@Override
public double apply(double x, double y) {
return x / y;
}
};
private final String symbol;
private BasicOperation(String symbol) {
this.symbol = symbol;
}
@Override
public String toString() {
return symbol;
}
}
// 使用示例
public class OperationDemo {
public static void main(String[] args) {
double x = 10.0;
double y = 3.0;
for (BasicOperation op : BasicOperation.values()) {
System.out.printf("%.1f %s %.1f = %.2f%n", x, op, y, op.apply(x, y));
}
}
}
四、内部类
4.1 成员内部类
public class OuterClass {
private String outerField = "外部类字段";
private static String staticField = "静态字段";
// 成员内部类
public class InnerClass {
private String innerField = "内部类字段";
public void innerMethod() {
// 内部类可以访问外部类的所有成员
System.out.println("访问外部类字段:" + outerField);
System.out.println("访问静态字段:" + staticField);
System.out.println("内部类字段:" + innerField);
// 调用外部类方法
outerMethod();
}
public void accessOuter() {
// 明确指定外部类实例
System.out.println("外部类字段:" + OuterClass.this.outerField);
}
}
public void outerMethod() {
System.out.println("外部类方法");
// 外部类访问内部类
InnerClass inner = new InnerClass();
inner.innerMethod();
}
public static void main(String[] args) {
// 创建外部类实例
OuterClass outer = new OuterClass();
// 创建内部类实例
OuterClass.InnerClass inner = outer.new InnerClass();
inner.innerMethod();
}
}
4.2 静态内部类
public class OuterClass2 {
private String outerField = "外部类字段";
private static String staticField = "静态字段";
// 静态内部类
public static class StaticInnerClass {
private String innerField = "静态内部类字段";
public void innerMethod() {
// 静态内部类只能访问外部类的静态成员
System.out.println("访问静态字段:" + staticField);
System.out.println("内部类字段:" + innerField);
// System.out.println(outerField); // 编译错误
}
public void accessOuter(OuterClass2 outer) {
// 通过外部类实例访问非静态成员
System.out.println("外部类字段:" + outer.outerField);
}
}
public static void main(String[] args) {
// 直接创建静态内部类实例
StaticInnerClass staticInner = new StaticInnerClass();
staticInner.innerMethod();
// 访问外部类非静态成员
OuterClass2 outer = new OuterClass2();
staticInner.accessOuter(outer);
}
}
4.3 局部内部类
public class LocalInnerClassDemo {
private String outerField = "外部类字段";
public void method() {
final String localVar = "局部变量";
int count = 10;
// 局部内部类
class LocalInnerClass {
public void localMethod() {
System.out.println("外部类字段:" + outerField);
System.out.println("局部变量:" + localVar);
System.out.println("count:" + count); // Java 8+ 可以访问 effectively final 变量
}
}
// 在方法内使用局部内部类
LocalInnerClass local = new LocalInnerClass();
local.localMethod();
}
public static void main(String[] args) {
LocalInnerClassDemo demo = new LocalInnerClassDemo();
demo.method();
}
}
4.4 匿名内部类
interface Greeting {
void sayHello(String name);
}
abstract class AbstractGreeting {
public abstract void greet();
public void commonMethod() {
System.out.println("通用方法");
}
}
public class AnonymousClassDemo {
public static void main(String[] args) {
// 匿名内部类实现接口
Greeting greeting1 = new Greeting() {
@Override
public void sayHello(String name) {
System.out.println("Hello, " + name + "!");
}
};
greeting1.sayHello("张三");
// 匿名内部类继承抽象类
AbstractGreeting greeting2 = new AbstractGreeting() {
@Override
public void greet() {
System.out.println("匿名类的问候");
}
};
greeting2.greet();
greeting2.commonMethod();
// 匿名内部类继承具体类
Thread thread = new Thread() {
@Override
public void run() {
System.out.println("匿名线程运行");
}
};
thread.start();
// 使用 Lambda 表达式(Java 8+)
Greeting greeting3 = name -> System.out.println("Hi, " + name + "!");
greeting3.sayHello("李四");
}
}
五、Java Bean 规范
5.1 标准 Java Bean
import java.io.Serializable;
// 标准 Java Bean
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
// 私有属性
private String name;
private int age;
private String email;
private boolean married;
// 无参构造方法(必须)
public Person() {
}
// 有参构造方法(可选)
public Person(String name, int age, String email, boolean married) {
this.name = name;
this.age = age;
this.email = email;
this.married = married;
}
// getter 方法
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getEmail() {
return email;
}
// boolean 类型的 getter 方法可以用 is 开头
public boolean isMarried() {
return married;
}
// setter 方法
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
if (age >= 0 && age <= 150) {
this.age = age;
}
}
public void setEmail(String email) {
this.email = email;
}
public void setMarried(boolean married) {
this.married = married;
}
// toString 方法(推荐)
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", email='" + email + '\'' +
", married=" + married +
'}';
}
// equals 和 hashCode 方法(推荐)
@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 &&
married == person.married &&
name.equals(person.name) &&
email.equals(person.email);
}
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + age;
result = 31 * result + email.hashCode();
result = 31 * result + (married ? 1 : 0);
return result;
}
}
5.2 Java Bean 的使用
import java.beans.*;
import java.lang.reflect.Method;
public class JavaBeanDemo {
public static void main(String[] args) {
// 创建 Java Bean 实例
Person person = new Person();
// 使用 setter 方法设置属性
person.setName("张三");
person.setAge(25);
person.setEmail("zhangsan@example.com");
person.setMarried(false);
// 使用 getter 方法获取属性
System.out.println("姓名:" + person.getName());
System.out.println("年龄:" + person.getAge());
System.out.println("邮箱:" + person.getEmail());
System.out.println("已婚:" + person.isMarried());
System.out.println(person);
// 使用反射和内省 API
try {
BeanInfo beanInfo = Introspector.getBeanInfo(Person.class);
PropertyDescriptor[] properties = beanInfo.getPropertyDescriptors();
System.out.println("\nBean 属性:");
for (PropertyDescriptor property : properties) {
String name = property.getName();
if (!"class".equals(name)) { // 排除 class 属性
Method readMethod = property.getReadMethod();
if (readMethod != null) {
Object value = readMethod.invoke(person);
System.out.println(name + ": " + value);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
5.3 Java Bean 规范总结
- 类必须是公共的:使用
public修饰符 - 必须有无参构造方法:用于框架实例化
- 属性必须是私有的:使用
private修饰符 - 提供 getter 和 setter 方法:遵循命名规范
- 实现 Serializable 接口:支持序列化
- 重写 toString、equals、hashCode:提供完整的对象行为
// 命名规范示例
public class NamingConventionExample {
private String firstName; // getter: getFirstName(), setter: setFirstName()
private boolean active; // getter: isActive(), setter: setActive()
private int age; // getter: getAge(), setter: setAge()
private double salary; // getter: getSalary(), setter: setSalary()
// 正确的命名
public String getFirstName() { return firstName; }
public void setFirstName(String firstName) { this.firstName = firstName; }
public boolean isActive() { return active; }
public void setActive(boolean active) { this.active = active; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public double getSalary() { return salary; }
public void setSalary(double salary) { this.salary = salary; }
}
六、作用域和静态上下文
6.1 变量作用域
public class ScopeDemo {
// 类变量(静态变量)
private static int classVar = 1;
// 实例变量
private int instanceVar = 2;
public void method(int paramVar) { // 参数变量
int localVar = 4; // 局部变量
System.out.println("类变量:" + classVar);
System.out.println("实例变量:" + instanceVar);
System.out.println("参数变量:" + paramVar);
System.out.println("局部变量:" + localVar);
// 作用域范围:局部变量 > 参数变量 > 实例变量 > 类变量
if (true) {
int blockVar = 5; // 块级变量
System.out.println("块级变量:" + blockVar);
}
// System.out.println(blockVar); // 编译错误:超出作用域
}
public static void staticMethod() {
System.out.println("类变量:" + classVar);
// System.out.println(instanceVar); // 编译错误:静态方法不能访问实例变量
}
}
6.2 静态上下文限制
public class StaticContextDemo {
private String instanceField = "实例字段";
private static String staticField = "静态字段";
public void instanceMethod() {
System.out.println("实例方法");
}
public static void staticMethod() {
System.out.println("静态方法");
}
// 静态方法的限制
public static void restrictedStaticMethod() {
// 1. 不能直接访问实例变量
// System.out.println(instanceField); // 编译错误
// 2. 不能直接调用实例方法
// instanceMethod(); // 编译错误
// 3. 不能使用 this 和 super 关键字
// System.out.println(this.staticField); // 编译错误
// 4. 可以访问静态成员
System.out.println(staticField); // 正确
staticMethod(); // 正确
// 5. 可以通过对象实例访问实例成员
StaticContextDemo obj = new StaticContextDemo();
System.out.println(obj.instanceField); // 正确
obj.instanceMethod(); // 正确
}
// 静态代码块的限制
static {
System.out.println("静态代码块");
System.out.println(staticField); // 可以访问静态字段
staticMethod(); // 可以调用静态方法
// System.out.println(instanceField); // 编译错误
// instanceMethod(); // 编译错误
}
}
总结
高级面向对象特性的核心要点:
- 抽象类:部分实现的类,用于代码复用和规范定义
- 接口:行为规范的定义,支持多实现
- 枚举:类型安全的常量集合,可以有属性和方法
- 内部类:类的嵌套定义,提供更好的封装性
- Java Bean:遵循特定规范的类,便于框架使用
- 作用域:变量的可见性范围,静态上下文的限制
设计建议:合理使用这些特性可以提高代码的可读性、可维护性和可扩展性。