反射的学习

news2024/10/23 13:22:38

1、什么是反射

反射允许对封装类的字段,方法和构造函数的信息进行编程访问。

也就是:

反射允许对成员变量,成员方法和构造方法的信息进行编程访问。

2、获取class对象

获取一个类的字节码文件对象:

方式1:Class.forName("全类名");        此方式最常用

Class类是定义好的,用来描述字节码文件。括号里传递一个类的全类名。

适用于源代码阶段:比如:A.java文件编译成A.class文件,没有把代码加载到内存中,只是在硬盘中进行操作。

方式2:类名.class        此方式一般是当做参数进行传递,如synchronized方法中的锁对象

适用于加载阶段:把A.class文件加载到内存中时

方式3:对象.getClass();        当有了这个类的对象时,才可以使用此方式

getClass()方法定义在Object类中,所有对象都可以调用

适用于运行阶段:在内存中 A a=new A(); 创建这个类的对象,通过对象获取class字节码文件对象

3、反射获取构造方法

 通过Constructor类,该类用来描述构造方法,该类对象就表示构造方法的对象。

public class MyReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
    /*
    Class类中用于获取构造方法的方法
      Constructor<?>[] getConstructors()                                返回所有公共构造方法对象的数组
      Constructor<?>[] getDeclaredConstructors()                        返回所有构造方法对象的数组
      Constructor<T> getConstructor(Class<?>... parameterTypes)         返回单个公共构造方法对象
      Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回单个构造方法对象


    Constructor类中用于创建对象的方法
      T newInstance(Object... initargs)                   根据指定的构造方法创建对象
      setAccessible(boolean flag)                         设置为true,表示取消访问检查
    */

        //1.获取class字节码文件对象
        Class clazz = Class.forName("com.itheima.myreflect2.Student");
        System.out.println(clazz);//class com.itheima.myreflect2.Student

       
        //2.获取构造方法
        Constructor[] cons1 = clazz.getConstructors();
        for (Constructor con : cons1) {
            System.out.println(con);
        }
        /*  运行结果:
            public com.itheima.myreflect2.Student()
            public com.itheima.myreflect2.Student(java.lang.String)*/
        
     
        Constructor[] cons2 = clazz.getDeclaredConstructors();
        for (Constructor con : cons2) {
            System.out.println(con);
        }
        /*  运行结果:
            public com.itheima.myreflect2.Student()
            public com.itheima.myreflect2.Student(java.lang.String)
            protected com.itheima.myreflect2.Student(int)
            private com.itheima.myreflect2.Student(java.lang.String,int)
*/

        Constructor con1 = clazz.getDeclaredConstructor();
        System.out.println(con1);//public com.itheima.myreflect2.Student()
        
        
        Constructor con2 = clazz.getDeclaredConstructor(String.class);
        System.out.println(con2);//public com.itheima.myreflect2.Student(java.lang.String)
        
        
        Constructor con3 = clazz.getDeclaredConstructor(int.class);
        System.out.println(con3);//protected com.itheima.myreflect2.Student(int)
        
        
        
        Constructor con4 = clazz.getDeclaredConstructor(String.class,int.class);

        int modifiers = con4.getModifiers();//获取构造方法的权限修饰符
        System.out.println(modifiers);//2    (1:public,2:private)

       
        Parameter[] parameters = con4.getParameters();//获取构造方法所有的参数
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }
        /*  运行结果:
            java.lang.String arg0
            int arg1
        */
        
        //暴力反射:表示临时取消权限校验,可以访问私有的了
        con4.setAccessible(true);
        Student stu = (Student) con4.newInstance("张三", 23);
        System.out.println(stu);//Student{name = 张三, age = 23}
    }
}

Student类:

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

    public Student() {
    }

    public Student(String name) {
        this.name = name;
    }

    protected Student(int age) {
        this.age = age;
    }

    private Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
}

4、反射获取成员变量

通过Field类获取

public class MyReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
    /*
       Class类中用于获取成员变量的方法
            Field[] getFields():                返回所有公共成员变量对象的数组
            Field[] getDeclaredFields():        返回所有成员变量对象的数组
            Field getField(String name):        返回单个公共成员变量对象
            Field getDeclaredField(String name):返回单个成员变量对象

       Field类中用于创建对象的方法
            void set(Object obj, Object value):赋值
            Object get(Object obj)              获取值

    */
        //1.获取class字节码文件的对象
        Class clazz = Class.forName("com.itheima.myreflect3.Student");

//        Field[] fields = clazz.getFields();//获取公共的成员变量
        //2.获取所有的成员变量,私有的也能获取到
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        //获取单个的成员变量,获取私有的
        Field name = clazz.getDeclaredField("name");
        System.out.println(name);

        //获取权限修饰符
        int modifiers = name.getModifiers();
        System.out.println(modifiers);

        //获取成员变量的名字
        String n = name.getName();
        System.out.println(n);

        //获取成员变量的数据类型
        Class<?> type = name.getType();
        System.out.println(type);

        //获取成员变量记录的值,跟对象有关系,先获取对象
        Student s = new Student("zhangsan",23,"男");
        name.setAccessible(true);
        String value = (String) name.get(s);
        System.out.println(value);

        //修改对象里面记录的值
        name.set(s,"lisi");

        System.out.println(s);
    }
}
public class Student {
    private String name;
    private int age;
    public String gender;

    public Student() {
    }

    public Student(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    /**
     * 获取
     * @return gender
     */
    public String getGender() {
        return gender;
    }

    /**
     * 设置
     * @param gender
     */
    public void setGender(String gender) {
        this.gender = gender;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + ", gender = " + gender + "}";
    }
}

5、反射获取成员方法

通过Method类

public class MyReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    /*
       Class类中用于获取成员方法的方法
            Method[] getMethods():返回所有公共成员方法对象的数组,包括继承的
            Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
            Method getMethod(String name, Class<?>... parameterTypes) :返回单个公共成员方法对象
            Method getDeclaredMethod(String name, Class<?>... parameterTypes):返回单个成员方法对象


       Method类中用于创建对象的方法
            Object invoke(Object obj, Object... args):运行方法
            参数一:用obj对象调用该方法
            参数二:调用方法的传递的参数(如果没有就不写)
            返回值:方法的返回值(如果没有就不写)

        获取方法的修饰符
        获取方法的名字
        获取方法的形参
        获取方法的返回值
        获取方法的抛出的异常

    */
        
        //1. 获取class字节码文件对象
        Class clazz = Class.forName("com.itheima.myreflect4.Student");

        //2. 获取里面所有的方法对象(包含父类中所有的公共方法)
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }

        // 获取里面所有的方法对象(不能获取父类的,但是可以获取本类中私有的方法)
        Method[] methods1 = clazz.getDeclaredMethods();
        for (Method method : methods1) {
            System.out.println(method);
        }

        // 获取指定的单一方法
        Method m = clazz.getDeclaredMethod("eat", String.class);//方法的名字,方法的形参
        System.out.println(m);

        // 获取方法的修饰符
        int modifiers = m.getModifiers();
        System.out.println(modifiers);

        // 获取方法的名字
        String name = m.getName();
        System.out.println(name);

        // 获取方法的形参
        Parameter[] parameters = m.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }

        //获取方法的抛出的异常
        Class[] exceptionTypes = m.getExceptionTypes();
        for (Class exceptionType : exceptionTypes) {
            System.out.println(exceptionType);
        }

        //方法运行
        /*Method类中用于创建对象的方法
        Object invoke(Object obj, Object... args):运行方法
        参数一:用obj对象调用该方法
        参数二:调用方法的传递的参数(如果没有就不写)
        返回值:方法的返回值(如果没有就不写)*/
        
        Student s = new Student();
        m.setAccessible(true);
        //参数一s:表示方法的调用者
        //参数二"汉堡包":表示在调用方法的时候传递的实际参数
        String result = (String) m.invoke(s, "汉堡包");
        System.out.println(result);
    }
}
public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    public void sleep(){
        System.out.println("睡觉");
    }

    private String eat(String something) throws IOException,NullPointerException,ClassCastException {
        System.out.println("在吃" + something);
        return "奥利给";
    }

    private void eat(String something,int a) {
        System.out.println("在吃" + something);
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
}

6、反射的作用

作用1:获取一个类里面所有的信息,获取到了之后,再执行其他的业务逻辑

作用2:结合配置文件,动态的创建对象并调用方法


练习1:保存任意对象的数据

public class MyReflectDemo {
    public static void main(String[] args) throws IllegalAccessException, IOException {
    /*
        对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去
    */
       Student s = new Student("小A",23,'女',167.5,"睡觉");
       Teacher t = new Teacher("播妞",10000);
       saveObject(s);
    }

    //把对象里面所有的成员变量名和值保存到本地文件中
    public static void saveObject(Object obj) throws IllegalAccessException, IOException {
        //1.获取字节码文件的对象
        Class clazz = obj.getClass();
        //2. 创建IO流
        BufferedWriter bw = new BufferedWriter(new FileWriter("myreflect\\a.txt"));
        //3. 获取所有的成员变量
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            //获取成员变量的名字
            String name = field.getName();
            //获取成员变量的值
            Object value = field.get(obj);
            //写出数据
            bw.write(name + "=" + value);
            bw.newLine();
        }
        bw.close();
    }
}
public class Student {
    private String name;
    private int age;
    private char gender;
    private double height;
    private String hobby;

    public Student() {
    }

    public Student(String name, int age, char gender, double height, String hobby) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.height = height;
        this.hobby = hobby;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    /**
     * 获取
     * @return gender
     */
    public char getGender() {
        return gender;
    }

    /**
     * 设置
     * @param gender
     */
    public void setGender(char gender) {
        this.gender = gender;
    }

    /**
     * 获取
     * @return height
     */
    public double getHeight() {
        return height;
    }

    /**
     * 设置
     * @param height
     */
    public void setHeight(double height) {
        this.height = height;
    }

    /**
     * 获取
     * @return hobby
     */
    public String getHobby() {
        return hobby;
    }

    /**
     * 设置
     * @param hobby
     */
    public void setHobby(String hobby) {
        this.hobby = hobby;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + ", gender = " + gender + ", height = " + height + ", hobby = " + hobby + "}";
    }
}
public class Teacher {
    private String name;
    private double salary;

    public Teacher() {
    }

    public Teacher(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return salary
     */
    public double getSalary() {
        return salary;
    }

    /**
     * 设置
     * @param salary
     */
    public void setSalary(double salary) {
        this.salary = salary;
    }

    public String toString() {
        return "Teacher{name = " + name + ", salary = " + salary + "}";
    }
}

练习2:利用反射动态的创建对象和运行方法

public class MyReflectDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
    /*
        反射可以跟配置文件结合的方式,动态的创建对象,并调用方法
    */


        //1.读取配置文件中的信息
        Properties prop = new Properties();
        FileInputStream fis = new FileInputStream("myreflect\\prop.properties");
        prop.load(fis);
        fis.close();
        System.out.println(prop);


        //2.获取全类名和方法名
        String className = (String) prop.get("classname");
        String methodName = (String) prop.get("method");

        System.out.println(className);
        System.out.println(methodName);

        //3.利用反射创建对象并运行方法
        Class clazz = Class.forName(className);

        //获取构造方法
        Constructor con = clazz.getDeclaredConstructor();
        Object o = con.newInstance();
        System.out.println(o);

        //获取成员方法并运行
        Method method = clazz.getDeclaredMethod(methodName);
        method.setAccessible(true);
        method.invoke(o);


    }
}
package com.itheima.myreflect6;

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

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void study(){
        System.out.println("学生在学习!");
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
}
package com.itheima.myreflect6;

public class Teacher {
    private String name;
    private double salary;

    public Teacher() {
    }

    public Teacher(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    public void teach(){
        System.out.println("老师在教书!");
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return salary
     */
    public double getSalary() {
        return salary;
    }

    /**
     * 设置
     * @param salary
     */
    public void setSalary(double salary) {
        this.salary = salary;
    }

    public String toString() {
        return "Teacher{name = " + name + ", salary = " + salary + "}";
    }
}

配置文件里的内容:

 想要运行某个类中的方法,直接更改配置文件中的类名和方法名就行了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2211552.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux 环境运行 jenkins.war包,有可能会出现字体问题,jdk版本:11 jenkins 版本:2.420

jenkins的目录&#xff1a; /usr/jenkins 启动命令 java -Djava.awt.headlesstrue sudo timedatectl set-timezone Asia/Shanghai-Xmx1024m -jar jenkins.war --httpPort8090 任意目录启动&#xff1a; nohup java -Djava.awt.headlesstrue -Xms1024m -Xmx1024m -jar /usr/j…

基于opencv答题卡识别判卷

我们是一个深度学习领域的独立工作室。团队成员有&#xff1a;中科大硕士、纽约大学硕士、浙江大学硕士、华东理工博士等&#xff0c;曾在腾讯、百度、德勤等担任算法工程师/产品经理。全网20多万粉丝&#xff0c;拥有2篇国家级人工智能发明专利。 社区特色&#xff1a;深度实…

Excel使用技巧:数据-》分列:处理log数据,把有用的信息提取出来;查找Ctrl+F,替换Ctrl+H;通配符

Excel的正确用法&#xff1a; Excel是个数据库&#xff0c;不要随意合并单元格。 数据输入的时候一定要按照行列输入&#xff0c;中间不要留空&#xff0c;不然就没有关联。 数据-》分列&#xff1a;处理log数据&#xff0c;把有用的信息提取出来。 按照向导一步一步操作。…

D36【python 接口自动化学习】- python基础之函数

day36 函数的定义 学习日期&#xff1a;20241013 学习目标&#xff1a;输入输出与文件操作&#xfe63;-49 函数定义&#xff1a;如何优雅地反复引用同一段代码&#xff1f; 学习笔记&#xff1a; 函数的用途 定义函数 调用函数 # 定义函数 def foo():print(foo)print(foo …

数据传送指令

文章目录 MOVXCHGPUSH和POPIN和OUTXLATLEA LDS LESLEALDSLES LAHF SAHFPUSHF POPF总结 MOV MOV dst, src ; dst <-- src可以进行8位或16位数据的传送源操作数可为立即数、寄存器、存储器操作数目的操作数不可为立即数&#xff0c;CS、IP寄存器两操作数必有一个寄…

Hi3244 应用指导

Hi3244 是一款DIP8封装高性能、多模式工作的原边控制功率开关。Hi3244内高精度的恒流、恒压控制机制结合完备的保护功能&#xff0c;使其适用于小功率离线式电源应用中。在恒压输出模式中&#xff0c;Hi3244 采用多模式工作方式&#xff0c;即调幅控制&#xff08;AM&#xff0…

LLM - 配置 ModelScope SWIFT 环境与 Qwen2-VL 模型推理 教程 (1)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/142827217 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 SWIFT …

AI 工具大比拼:ChatGPT 与豆包的魅力与未来展望

&#x1f9d1; 博主简介&#xff1a;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编程&#xff0c;…

C++的类和动态内存分配(深拷贝与浅拷贝)并实现自己的string类

首先&#xff0c;我们先写一个并不完美的类&#xff1a; #include<iostream> #include<cstring> using namespace std;class Mystring{private:char *p;int len;static int num;friend ostream& operator<<(ostream& os, const Mystring& c);pu…

QT开发--多线程

第十四章 多线程 QThread 是 Qt 中实现多线程编程的核心类&#xff0c;提供跨平台线程管理。 使用 QThread 有两种方法&#xff1a; 1、 继承 QThread&#xff1a;重写 run() 方法&#xff0c;实现线程的具体操作。Qt4.8 之前较常用。 2、 使用 QObject 和 moveToThread()&…

2024-10-13 NO.1 Quest3 激活教程

文章目录 1 下载 Occlus 助手2 打开 quest 热点3 Quest3 连接 wifi4 详细文档5 参考教程 1 下载 Occlus 助手 ​ 网址&#xff1a;https://ochelper.xlemon.cn/home.html。 2 打开 quest 热点 ​ 下载 Occlus 助手后&#xff0c;双击 exe 文件打开。 ​ 过程中按照程序提示执…

各类排序详解

前言 本篇博客将为大家介绍各类排序算法&#xff0c;大家知道&#xff0c;在我们生活中&#xff0c;排序其实是一件很重要的事&#xff0c;我们在网上购物&#xff0c;需要根据不同的需求进行排序&#xff0c;异或是我们在高考完报志愿时&#xff0c;需要看看院校的排名&#…

【动手学深度学习】6.2 图像卷积(个人向笔记)

1. 互相关运算 严格来说&#xff0c;卷积层是一个错误的叫法&#xff0c;因为它本质上是互相关运算而不是卷积运算。我们暂时忽略通道看看二维图像数据和隐藏表示。那么输出大小可以表示为 我们自己实现一个二维互相关运算 2. 卷积层 卷积层中有两个参数&#xff1a;卷积核权…

Medieval Kingdom UI 中世纪王国AAA级UI游戏界面

这款中世纪王国风格的大型素材包包含大量绘图、图标、用户界面(UI)元素、完整的世界地图和文明图标。它将助您打造一款游戏,或为您的3D游戏增添亮点。您还可以为对话制作国王的动画,为4K游戏创建独特的面板和窗口。提供两种独特皮肤:经典(冷色调)和白金(暖色调)。 素…

国家基本药物目录数据库查询3种方法(2018、2012、2009年版)

国家基本药物目录是一份由国家卫生健康委员会等相关部门制定的药品清单&#xff0c;旨在满足国家公共卫生需求&#xff0c;保障基本医疗服务。该目录包括了多种药品&#xff0c;覆盖了不同的疾病治疗领域&#xff0c;如抗生素、心血管药物、神经系统药物、抗肿瘤药物、维生素和…

STM32 -- USB CDC 虚拟串口通信

本篇操作: 通过CubeMX Keil&#xff0c;配置STM32作为USB设备端&#xff0c;与电脑上位机进行通信&#xff08;CDC&#xff09;&#xff1b;通用带USB功能的 STM32 芯片 &#xff08;如F1、F4等&#xff0c;系统时钟配置不同&#xff0c;代码通用&#xff09;。 目录 一、 S…

[论文精读]Active and Semi-Supervised Graph Neural Networks for Graph Classification

论文网址&#xff1a;Active and Semi-Supervised Graph Neural Networks for Graph Classification | IEEE Journals & Magazine | IEEE Xplore英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若…

大数据-168 Elasticsearch 单机云服务器部署运行 详细流程

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

PyQt: QMessageBox Duplication

在使用 PyQt 的 QMessageBox 时&#xff0c;如果你遇到 消息框重复显示 或 QMessageBox 重复实例化 的问题&#xff0c;通常是因为消息框没有正确管理或关闭&#xff0c;或者消息框的创建和显示逻辑中存在重复调用。以下是一些常见原因和解决方案。 1、问题背景 在 PyQt 中使用…

无心剑七绝《泊院雕楼》

七绝泊院雕楼 清歌咏尽桂花香 泊院雕楼醉夕阳 逸兴无端飞万里 幽情宛转忆潇湘 2024年10月13日 平水韵七阳平韵 这首七绝《泊院雕楼》以清新脱俗的语言&#xff0c;描绘了一幅宁静致远的画面。 首句“清歌咏尽桂花香”&#xff0c;以“清歌”起兴&#xff0c;形象地描绘了桂花香…