Java进阶篇

Java 是一门面向对象编程语言,不仅吸收了 C++ 语言的各种优点,还摒弃了 C++ 里难以理解的多继承、指针等概念,因此,Java 语言具有功能强大和简单易用两个特征。Java 语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。

Java 具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特点。

Java 可以编写桌面应用程序、Web 应用程序、分布式系统和嵌入式系统应用程序等。

面向对象设计

面向对象的程序设计是通过对象对程序进行设计,对象代表一个实体,实体可以清楚地被识别。

Java 作为一种面向对象语言,有以下基本概念:

  • 包(Package)
  • 接口(Interface)
  • 抽象类(Abstract Class)
  • 类(Class)
  • 对象(Object)
  • 封装(Encapsulation)
  • 继承(Inheritance)
  • 多态(Polymorphism)
  • 消息解析(Message Parsing / Method Resolution)
  • 注解(Annotation)

源文件声明规则

当在一个源文件中定义多个类,并且还有 import、package 语句时,要特别注意这些规则。

  • package 语句应该在源文件的首行。
  • 在同一源文件中,不能给不同的类不同的包声明。
  • import 语句应该放在 package 语句和类定义之间。
  • import 语句和 package 语句对源文件中定义的所有类都有效。
  • 源文件的名称应该和 public 类的类名保持一致。
  • 一个源文件中只能有一个 public 类。
  • 一个源文件可以有多个非 public 类。

包(Package)

包是 Java 中组织类和接口的机制,相当于文件系统中的文件夹。它用于将相关的类和接口分组,避免命名冲突,并控制访问权限。

详细说明:

  • 命名规范:通常使用公司域名的倒写作为包名的前缀,例如 com.example.project.module。全部小写,点号分隔。
  • 物理结构:包名必须与源代码文件的目录结构完全一致。例如,包 com.lizhao.vehicle 表示类文件位于 com/lizhao/vehicle/ 目录下。
  • 包声明:每个 .java 文件最多只能有一个 package 语句,且必须放在文件的第一行(注释除外)。
  • 默认包:如果没有声明 package,类属于“无名包”,一般不推荐用于正式项目。
  • 导入包:使用 import 语句可以简化类名书写。import java.util.*; 导入包下的所有类和接口,但不递归导入子包。
  • 静态导入import static 可以导入类的静态成员,使代码更简洁。
src
│
├── com
│   └── lizhao
│       └── vehicle
│           ├── Vehicle.java
│           ├── Car.java
│           └── Plane.java
└── VehicleApplication.java
// src/VehicleApplication.java
import com.lizhao.vehicle.Vehicle;
import com.lizhao.vehicle.Car;
import com.lizhao.vehicle.Plane;
public class VehicleApplication {
  public static void main (String[] args) {
    Vehicle vehicle = new Vehicle();
    System.out.println(vehicle.toString());

    Car car = new Car("小汽车", "black");
    System.out.println(car.getColor());

    Plane plane = new Plane();
    plane.fly();
  }
}
// src/com/lizhao/vehicle/Vehicle.java
package com.lizhao.vehicle;
public class Vehicle {
    public String name = "vehicle";
    public String toString() {
        return this.name;
    };
}
// src/com/lizhao/vehicle/Car.java
package com.lizhao.vehicle;
public class Car {
    String name;
    String color;
    public Car () {}
    public Car (String name, String color) {
        this.name = name;
        this.color = color;
    }
    public void setName (String name) {
        this.name = name;
    }
    public String getName () {
        return this.name;
    }
    public void setColor (String color) {
        this.color = color;
    }
    public String getColor () {
        return this.color;
    }
}
// src/com/lizhao/vehicle/Plane.java
package com.lizhao.vehicle;

public class Plane {
    String name = "飞机";
    public void fly() {
        System.out.println("fly:" + this.name);
    };
}

常用 Java 包:

  • java.lang:核心类(String、Math、System),自动导入。

  • java.util:工具类、集合框架(List、Set、Arrays)。

  • java.io:输入输出操作。

  • java.net:网络编程。

  • java.sql:数据库编程。

  • java.awt / javax.swing:图形界面。

接口(Interface)

接口是 Java 中的一种引用类型,是抽象方法的集合。接口定义了一种规范或契约,任何实现该接口的类都必须提供接口中所有方法的具体实现(除非该类是抽象类)。

详细说明

  • 接口中的方法默认是 public abstract(Java 8 之前)。
  • 接口中的变量默认是 public static final,即常量。
  • 接口不能实例化,没有构造方法。
  • 一个类可以实现多个接口(多实现),弥补了单继承的不足。
  • 接口之间可以多继承(extends 多个接口)。
src
│
├── com
│   └── lizhao
│       └── sports
│           ├── Sports.java
│           ├── Player.java
└── Main.java
// src/Main.java
import com.lizhao.sports.Sports;
import com.lizhao.sports.Player;

public class Main {
    public static void main(String[] args) {
        Player player = new Player();
        player.play(Sports.BASKETBALL);
        player.play(Sports.FOOTBALL);
    }
}
// src/com/lizhao/sports/Sports.java
package com.lizhao.sports;

public interface Sports {
    int BASKETBALL = 1;
    int FOOTBALL = 2;
    int TENNIS = 3;

    void play(int sportType);
}
// src/com/lizhao/sports/Player.java
package com.lizhao.sports;

public class Player implements Sports {
    @Override
    public void play(int sportType) {
        switch(sportType) {
            case BASKETBALL:
                System.out.println("打篮球");
                break;
            case FOOTBALL:
                System.out.println("踢足球");
                break;
            case TENNIS:
                System.out.println("打网球");
                break;
            default:
                System.out.println("未知运动");
        }
    }
}

注意事项:

  • 实现接口方法时,不能抛出比接口声明更宽泛的强制性异常。
  • 重写方法必须保持方法名一致,返回值类型需相同或兼容(支持协变返回)。
  • 一个类只能继承一个父类,但能同时实现多个接口。
  • 接口支持多重继承,一个子接口可以继承多个父接口,extends 后跟多个接口名(逗号分隔)。
  • 标识接口是没有方法和属性的空接口,用于标记类属于某种特定类型。一般用于建立公共父接口、为类添加数据类型(通过多态)。

抽象类(Abstract Class)

抽象类是使用 abstract 关键字修饰的类,它不能被实例化,通常作为父类被其他类继承。抽象类可以包含抽象方法(没有方法体)和具体方法。

详细说明:

  • 抽象方法:只有声明,没有实现,使用 abstract 修饰。子类必须重写所有抽象方法(除非子类也是抽象类)。
  • 普通方法:抽象类中可以定义普通方法,子类直接继承使用。
  • 成员变量:抽象类可以拥有普通成员变量,与普通类相同。
  • 构造方法:抽象类可以有构造方法,但只能被子类通过 super 调用。
  • 使用场景:当多个子类有共同的属性和行为,但某些方法需要子类各自实现时,使用抽象类。
src
│
├── com
│   └── lizhao
│       └── shape
│           ├── Shape.java
│           ├── Circle.java
│           ├── Rectangle.java
└── Main.java
// src/Main.java
import com.lizhao.shape.Shape;
import com.lizhao.shape.Circle;
import com.lizhao.shape.Rectangle;

public class Main {
    public static void main(String[] args) {
        Shape c = new Circle("blue", 5.0);
        Shape r = new Rectangle("green", 3.0, 4.0);

        System.out.println(c.area());
        System.out.println(r.area());
        c.displayColor();
    }
}
// src/com/lizhao/shape/Shape.java
package com.lizhao.shape;

public abstract class Shape {
  protected String color;

  public Shape(String color) {
    this.color = color;
  }

  // 抽象方法:子类必须实现
  public abstract double area();

  // 具体方法:子类可以直接使用
  public void displayColor() {
    System.out.println("Color: " + color);
  }
}
// src/com/lizhao/shape/Circle.java
package com.lizhao.shape;

public class Circle extends Shape {
  private double radius;

  public Circle(String color, double radius) {
    super(color);
    this.radius = radius;
  }

  @Override
  public double area() {
    return Math.PI * radius * radius;
  }
}
// src/com/lizhao/shape/Rectangle.java
package com.lizhao.shape;

public class Rectangle extends Shape {
  private double width, height;

  public Rectangle(String color, double width, double height) {
    super(color);
    this.width = width;
    this.height = height;
  }

  @Override
  public double area() {
    return width * height;
  }
}

类(Class)

类是 Java 中面向对象编程的基本单元,是创建对象的模板。

类定义了对象所拥有的属性(成员变量)和行为(方法)。

类的组成

  • 构造方法:用于创建并初始化对象。如果没有显式地为类定义构造方法,Java 编译器将会为该类提供一个默认构造方法。构造方法的名称必须与类同名。
  • 成员变量(字段):存储对象的状态。
  • 方法:定义对象的行为。
  • 初始化块:在构造方法之前执行。
  • 内部类:定义在类内部的类。
// src/Main.java
import com.lizhao.Student;
public class Main {
    public static void main(String[] args) {

        Student s1 = new Student("Hello", 18);
        s1.introduce();
        s1.study("数学");

        Student s2 = new Student("Lizhao", 19);
        s2.introduce();

        Student.school = "第二中学";
        s1.introduce();
        s2.introduce();

        System.out.println("\n--- 内部类示例 ---");
        Student.Score score1 = s1.new Score(90, 88);
        score1.printScore();

        Student.SchoolInfo schoolInfo = new Student.SchoolInfo("教育路123号");
        schoolInfo.printInfo();

        Student.printSchool();
    }
}
// src/com/lizhao/Student.java
package com.lizhao;

public class Student {
    public static String school = "第一中学";
    private static int studentCount = 0;

    private String name;
    private int age;
    private String id;

    // ========== 初始化块 ==========
    // 实例初始化块:每次创建对象时,在构造方法之前执行
    {
        id = generateId();
        studentCount++;  // 每创建一个学生,总数加1
        System.out.println("执行初始化块,当前学生总数:" + studentCount);
    }

    // 静态初始化块:类加载时执行一次
    static {
        System.out.println("静态初始化块:Student类被加载");
        System.out.println("学校:" + school);
    }

    // ========== 构造方法 ==========
    public Student() {
        this("未知", 0);
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("执行构造方法:创建学生 " + name);
    }

    // ========== 方法 ==========
    // 实例方法
    public void introduce() {
        String info = "我叫" + name + ",今年" + age + "岁";
        System.out.println(info + ",学号:" + id + ",学校:" + school);
    }

    public void study(String subject) {
        String action = "正在学习";
        System.out.println(name + action + subject);
    }

    // 静态方法
    public static void printSchool() {
        System.out.println("全校名称:" + school + "," + "学生总数:" + studentCount);
    }

    // getter/setter
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    // 私有方法:生成学号
    private String generateId() {
        return "S" + System.currentTimeMillis();
    }

    // ========== 内部类 ==========
    // 成员内部类
    public class Score {
        private int chinese;
        private int math;

        public Score(int chinese, int math) {
            this.chinese = chinese;
            this.math = math;
        }

        public void printScore() {
            // 内部类可以访问外部类的私有成员
            System.out.println(name + "的成绩 - 语文:" + chinese + ",数学:" + math);
        }
    }

    // 静态内部类
    public static class SchoolInfo {
        private String address;

        public SchoolInfo(String address) {
            this.address = address;
        }

        public void printInfo() {
            System.out.println("学校:" + school + ",地址:" + address);
        }
    }
}

对象(Object)

对象是类的具体实例,具有状态和行为。在内存中,对象是存储具体数据的一块区域。

详细说明:

  • 创建对象:使用 new 关键字调用构造方法。
  • 对象引用:变量存储的是对象的引用(内存地址),而不是对象本身。
  • 对象生命周期:从 new 创建开始,到不再被引用后被垃圾回收器回收。
  • 匿名对象:没有引用的对象,例如 new Student("Tom").introduce();,使用一次后即成为垃圾。

注意事项:

  • == 比较两个引用是否指向同一个对象;equals() 一般用于比较内容,需要根据业务需求重写。
  • 对象的销毁由垃圾回收器自动完成,不需要手动释放内存(除非使用了外部资源如文件、网络连接,需要显式关闭)。

封装(Encapsulation)

面向对象编程的三大特征封装、继承、多态

封装是将对象的状态(属性)隐藏在对象内部,通过公共方法(getter/setter)来访问和修改,从而保护数据的完整性和安全性。

详细说明:

  • 将成员变量声明为 private
  • 提供公共的 gettersetter 方法。
  • setter 中可以加入校验逻辑。
package com.lizhao;

public class Student {
    private String name;
    private int age;
    private double score;

    public Student(String name, int age, double score) {
        this.name = name;
        setAge(age);
        setScore(score);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        if (name != null && !name.trim().isEmpty()) {
            this.name = name;
        } else {
            System.out.println("姓名不能为空");
        }
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age >= 0 && age <= 150) {
            this.age = age;
        } else {
            System.out.println("年龄必须在 0-150 之间");
        }
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        if (score >= 0 && score <= 100) {
            this.score = score;
        } else {
            System.out.println("成绩必须在 0-100 之间");
        }
    }

    public void printInfo() {
        System.out.println("姓名:" + name + ",年龄:" + age + ",成绩:" + score);
    }
}

继承(Inheritance)

面向对象编程的三大特征封装、继承、多态

继承是面向对象的核心特性之一,子类可以复用父类的属性和方法,并可以添加新的成员或重写父类的方法。

详细说明:

  • 关键字extends 用于类继承,implements 用于实现接口。
  • 单继承:Java 中一个类只能有一个直接父类,但可以间接继承多个祖先类。
  • 方法重写:子类可以重新实现父类的方法,但需要保持方法签名一致。
  • super 关键字:用于访问父类的成员或调用父类的构造方法。super() 必须放在子类构造方法的第一行。
  • 访问性:子类可以访问父类的 publicprotected 成员,以及同包下的默认成员。不能访问 private 成员。
package com.lizhao.shape;

public class Circle extends Shape {
    private double radius;

    public Circle(String color, double radius) {
        super(color);
        this.radius = radius;
    }

    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}

多态(Polymorphism)

面向对象编程的三大特征封装、继承、多态

多态指同一个行为具有多个不同表现形式。在 Java 中,多态分为编译时多态(重载)和运行时多态(重写)。

通常所说的多态指的是运行时多态:父类引用指向子类对象,调用方法时表现出子类的行为。

多态的必要条件

  • 继承关系或接口实现。
  • 子类重写父类方法(或实现接口方法)。
  • 父类引用指向子类对象。

多态的体现

  • 方法重写。
  • 接口实现。
  • 抽象类。

注意:静态方法不被多态影响,始终根据引用类型调用。

public class Main {
    static class Shape {
        public void draw() {
            System.out.println("绘制一个形状");
        }

        public double getArea() {
            return 0;
        }
    }

    static 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;
        }
    }

    static class Rectangle extends Shape {
        private double width;
        private double height;

        public Rectangle(double width, double height) {
            this.width = width;
            this.height = height;
        }

        @Override
        public void draw() {
            System.out.println("■ 绘制一个 " + width + " x " + height + " 的矩形");
        }

        @Override
        public double getArea() {
            return width * height;
        }
    }

    public static void main(String[] args) {
        // 1. 父类引用指向子类对象
        System.out.println("【1. 父类引用指向子类对象】");
        Shape shape1 = new Circle(5);
        Shape shape2 = new Rectangle(4, 6);

        // 调用同一个方法,表现出不同的行为
        shape1.draw();
        shape2.draw();
        System.out.println();

        // 2. 多态参数:方法接收父类类型,可以传入任何子类
        System.out.println("【2. 多态参数】");
        printShapeInfo(new Circle(3));
        printShapeInfo(new Rectangle(5, 8));
        System.out.println();

        // 3. 多态数组:可以存放不同类型的对象
        System.out.println("【3. 多态数组】");
        Shape[] shapes = {
            new Circle(2.5),
            new Rectangle(3, 4),
            new Circle(4),
            new Rectangle(2, 9)
        };

        // 统一遍历处理,不需要关心具体是什么形状
        for (int i = 0; i < shapes.length; i++) {
            System.out.print("第" + (i+1) + "个:");
            shapes[i].draw();
        }
        System.out.println();

        // 4. 计算总面积(多态的便利)
        System.out.println("【4. 计算总面积(多态的便利)】");
        double totalArea = 0;
        for (Shape shape : shapes) {
            totalArea += shape.getArea();
            System.out.printf("面积:%.2f\n", shape.getArea());
        }
        System.out.printf("总面积:%.2f\n", totalArea);
    }

    // 多态参数:不需要为每个形状单独写方法
    public static void printShapeInfo(Shape shape) {
        System.out.print("形状信息:");
        shape.draw();
        System.out.printf("面积:%.2f\n\n", shape.getArea());
    }
}

重载(Overload)

在同一个类中,多个方法拥有相同的名称但参数列表不同(参数数量、类型、顺序不同),称为重载。

重载是编译时多态。

详细说明:

  • 参数列表区分:编译器根据参数个数、类型、顺序来区分不同方法。
  • 返回类型无关:仅返回类型不同不足以构成重载,也不是重写,而是编译错误。
  • 访问修饰符无关:可以不同。
  • 异常无关:可以抛出不同的异常。
  • 发生在同一类或继承关系中:子类也可以重载父类的方法(方法名相同但参数不同)。
public 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 void print(String name, int age) {
        System.out.println(name + " is " + age);
    }

    public void print(int age, String name) {
        System.out.println("Age " + age + ", name " + name);
    }
}

// 不是重载,也不是重写,而是编译错误
// 父类已有 int add(int, int),子类参数列表相同、返回类型不兼容,不构成重写,也不构成重载,属于编译错误。
class AdvancedCalculator extends Calculator {
    public double add(int a, int b) {
        return (double) a + b;
    }
}

重写(Override)

子类重新实现父类中的某个方法,要求方法名、参数列表、返回类型(或父类方法返回类型的子类)完全相同。

重写是运行时多态。

详细说明:

  • 注解:推荐使用 @Override,让编译器检查是否正确地重写了父类方法。
  • 访问权限:子类重写方法的访问权限不能低于父类方法的权限(例如父类是 protected,子类可以是 public)。
  • 返回类型:可以返回父类方法返回类型的子类(协变返回类型)。
  • 异常:子类方法不能抛出比父类方法更宽泛的检查异常;可以不抛出异常或抛出更具体的异常。
  • 构造方法:不能被重写。
  • 静态方法:不能被重写。如果在子类中定义了相同的静态方法,那是“隐藏”而不是重写。
  • finalprivatefinal 方法不能被重写;private 方法不能被继承,也就不存在重写。
  • Super 关键字: 子类中调用父类的被重写方法时,要使用 super 关键字。
class Parent {
    protected Object getValue() throws Exception {
        return "Parent";
    }

    public static void say() {
        System.out.println("Parent");
    }
}

class Child extends Parent {
    @Override
    public String getValue() {   // 返回类型从 Object 变成 String(子类)
        try {
            super.getValue();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "Child";
    }

    // 这不是重写,是隐藏
    // 静态方法不存在多态,永远根据引用类型决定调用哪个方法。
    public static void say() {
        System.out.println("Child");
    }
}

public class Main {
    public static void main(String[] args) {
        Parent p1 = new Parent();
        Parent p2 = new Child(); // 父类引用指向子类对象
        Child c = new Child();

        try {
            System.out.println(p1.getValue());
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 真正调用的方法由引用类型决定,不是对象类型
        p1.say(); // Parent
        p2.say(); // Parent
        c.say(); // Child
    }
}

消息解析(Message Parsing / Method Resolution)

在面向对象编程中,“消息”是指对象之间的方法调用。消息解析(或方法解析)是指编译器或运行时如何确定调用的是哪个方法的过程。

Java 中消息解析分为编译时解析(静态绑定)和运行时解析(动态绑定)。

编译时解析(静态绑定):

  • 发生场景private 方法、static 方法、final 方法、构造方法以及重载方法的调用。
  • 解析时机:在编译阶段,编译器根据变量的声明类型(编译时类型)和方法签名(包括参数类型)确定调用的具体方法。
  • 特点:效率高,因为调用地址在编译时确定。

运行时解析(动态绑定):

  • 发生场景:普通实例方法(非 private、非 static、非 final)的重写方法调用。
  • 解析时机:运行时,JVM 根据对象的实际类型(运行时类型)来确定调用哪个方法。
  • 特点:支持多态,但有一定的性能开销(JVM 使用虚方法表优化)。

重载解析:

  • 当调用一个重载方法时,编译器会尝试匹配最合适的方法。匹配规则:
    • 精确匹配(参数类型完全相同)。
    • 自动类型转换(如 intlongintdouble)。
    • 装箱/拆箱(如 intInteger)。
    • 可变参数(...)。
  • 如果多个方法匹配,编译器会选择最具体的一个;如果无法确定,则报歧义错误。

重写解析:

  • 对于重写的方法,JVM 在运行时通过动态分派决定调用子类还是父类的方法。
  • 使用 invokevirtual 指令,查找对象的实际类型的方法表。

注解(Annotation)

注解是 Java 5 引入的一种元数据(关于数据的数据),它可以被添加到类、方法、字段、参数等程序元素上,为程序提供额外的信息,但不会直接影响代码的执行

注解的作用

  • 编译器指令:告诉编译器如何处理代码。如:@Override、@SuppressWarnings。

  • 编译时处理:生成代码、配置文件等。如:@Data(Lombok)。

  • 运行时处理:通过反射读取注解,执行逻辑。如:@Test(JUnit)、@RequestMapping(Spring)。

Java 内置注解(最常用):

  • @Override:标记方法是重写父类方法,编译器会检查。
  • @Deprecated:标记方法/类已过时,不推荐使用。
  • @SuppressWarnings:抑制编译器警告。
  • @FunctionalInterface:标记函数式接口(只有一个抽象方法)。
  • @SafeVarargs:抑制堆污染警告。
// src/Main.java
import com.lizhao.annotation.MyAnnotation;
import com.lizhao.processor.MyAnnotationRunner;

public class Main {
    public static void main(String[] args) {
        MyAnnotationRunner.processAnnotations(Main.class);
    }

    @MyAnnotation(value = "MyAnnotation1", message = "message")
    public static void useMyAnnotation1() {
        System.out.println("useMyAnnotation1");
    }
}
// src/com/lizhao/annotation/MyAnnotation.java
package com.lizhao.annotation;

import java.lang.annotation.*;

@Target({
    ElementType.TYPE,       // 类、接口、枚举
    ElementType.METHOD,     // 方法
    ElementType.FIELD,      // 字段
    ElementType.PARAMETER,  // 参数
    ElementType.CONSTRUCTOR // 构造方法
})
//@Retention(RetentionPolicy.SOURCE)  // 只在源码中
//@Retention(RetentionPolicy.CLASS)   // 默认,字节码中存在
@Retention(RetentionPolicy.RUNTIME) // 保留:运行时可见
public @interface MyAnnotation {
    // 注解属性(看起来像方法)
    String value() default "";
    String message() default "";
}
// src/com/lizhao/processor/MyAnnotationRunner.java
package com.lizhao.processor;

import java.lang.reflect.Method;

public class MyAnnotationRunner {
    public static void processAnnotations(Class<?> clazz) {
        Method[] methods = clazz.getDeclaredMethods();

        for (Method method : methods) {
            if (method.isAnnotationPresent(com.lizhao.annotation.MyAnnotation.class)) {
                com.lizhao.annotation.MyAnnotation annotation =
                    method.getAnnotation(com.lizhao.annotation.MyAnnotation.class);

                String value = annotation.value();
                String message = annotation.message();

                System.out.println("========================================");
                System.out.println("发现被注解标记的方法:" + method.getName());
                System.out.println("  - value 值:" + value);
                System.out.println("  - message 值:" + message);
                System.out.println("========================================");

                try {
                    // 静态方法:invoke 的第一个参数传 null
                    method.invoke(null);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

参考链接

Java 官方文档 - w3cschool

IntelliJ IDEA 2023.3

© lizhao all right reserved,powered by Gitbook文件修订时间: 2026-05-16 00:33:16

results matching ""

    No results matching ""