【JAVA基础之反射】反射详解

news2024/11/24 15:24:15

🔥作者主页:小林同学的学习笔录

🔥mysql专栏:小林同学的专栏

1.反射

1.1  概述

是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;

对于任意一个对象,都能够调用它的任意属性和方法;

这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。

通过反射可以获取到这些东西

而获取这些信息需要在字节码文件获取

1.2  获取字节码文件对象

获取class对象的三种方式:

  • Class.forName("全类名")
    • 最为常用
  • 类名.class
    • 一般当作参数来使用
  • 对象.getClass()
    • 已经有该类的对象,才可以使用

1.3  字节码文件和字节码文件对象

java文件:就是我们自己编写的java代码。

字节码文件:就是通过java文件编译之后的class文件(是在硬盘上真实存在的,用眼睛能看到的)

字节码文件对象:当class文件加载到内存之后,虚拟机自动创建出来的对象(眼睛看不到的)。

这个对象里面至少包含了:构造方法,成员变量,成员方法。

而我们的反射获取的是什么?字节码文件对象,这个对象在内存中是唯一的。

拓展:

为什么字节码对象是唯一的?

字节码文件对象在内存中是唯一的,是因为每个字节码文件对象都有一个独一无二的标识符来表示它的身份。这个标识符通常是一个地址指针,它指向存储字节码文件对象数据的内存地址。因此,当你创建一个新的字节码文件对象时,系统会为它分配一个新的内存地址,并把这个地址作为该对象的唯一标识符。这样,在内存中就不会出现相同的字节码文件对象,保证了每个字节码文件对象在内存中是唯一的。

1.4  获取构造方法

成员方法:

当使用反射机制时,可以通过Class类的对象调用newInstance()方法来实例化一个类的对象,而不需要直接使用new关键字来创建对象。这种方式在编写通用代码或者动态加载类的情况下非常有用。

代码演示:
 

public class Demo01 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class aClass = Class.forName("com.lhx.pojo.Student");
        Constructor[] constructors = aClass.getDeclaredConstructors();
//        for (Constructor constructor : constructors) {
//            System.out.println(constructor);
//        }

        Constructor[] constructors1 = aClass.getConstructors();
//        for (Constructor constructor : constructors1) {
//            System.out.println(constructor);
//        }
        
        Constructor constructor = aClass.getConstructor(String.class);
        System.out.println(constructor);

        Constructor constructor1 = aClass.getDeclaredConstructor(String.class, int.class);
        constructor1.setAccessible(true);
        System.out.println(constructor1);
        Object o1 = constructor1.newInstance("周杰伦",18);
        System.out.println(o1);
        
        Constructor constructor2 = aClass.getConstructor();
        Object o =  constructor2.newInstance();
        System.out.println(o);
    }
}

输出结果:

public com.lhx.pojo.Student(java.lang.String)
private com.lhx.pojo.Student(java.lang.String,int)
Student{name = 周杰伦, age = 18}
Student{name = null, age = 0}
public class Student {
    private String name;

    private int age;


    public Student() {

    }

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

    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 + "}";
    }
}

1.5  获取成员变量

成员方法:

代码演示:

public class Demo02 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        Class aClass = Class.forName("com.lhx.pojo.Student02");
        Field[] fields = aClass.getFields();
//        for (Field field : fields) {
//            System.out.println(field);
//        }

        Field[] fields1 = aClass.getDeclaredFields();
//        for (Field field : fields1) {
//            System.out.println(field);
//        }
        
        Field field1 = aClass.getDeclaredField("name");
        System.out.println(field1);
        //private临时修饰他的访问权限(暴力反射),不然下面没办法set()
        field1.setAccessible(true);
        Student02 student02 = new Student02();
        //参数一:表示要修改哪个对象的name?
        //参数二:表示要修改为多少?
        field1.set(student02,"林俊杰");
        String o = (String) field1.get(student02);
        System.out.println(o);

        Field field = aClass.getField("gender");
        System.out.println(field);

        Field age = aClass.getDeclaredField("age");
        System.out.println(age);
    }
}
public class Student02 {
        private String name;

        private int age;

        public String gender;

        public String address;


        public Student02() {
        }

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


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

        /**
         * 获取
         * @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;
        }

        /**
         * 获取
         * @return address
         */
        public String getAddress() {
            return address;
        }

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

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

1.6  获取成员方法

成员方法:

代码演示:

public class Demo04 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class aClass = Class.forName("com.lhx.pojo.Student");
        //返回public方法,也会把父类(Object)的public的方法也输出
        Method[] methods = aClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }

        //返回所有方法,但是不会返回父类的方法
        Method[] declaredMethods = aClass.getDeclaredMethods();
//        for (Method declaredMethod : declaredMethods) {
//            System.out.println(declaredMethod);
//        }
    }
}

输出结果:

public int com.lhx.pojo.Student.getAge()
public void com.lhx.pojo.Student.setAge(int)
public java.lang.String com.lhx.pojo.Student.getName()
public java.lang.String com.lhx.pojo.Student.toString()
public void com.lhx.pojo.Student.setName(java.lang.String)
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

public class Student {
    private String name;

    private int age;


    public Student() {

    }

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

    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 + "}";
    }
}

1.6.1  获取成员方法并运行

成员方法:

Object invoke(Object obj, Object... args) :运行方法

参数一:用obj对象调用该方法

参数二:调用方法的传递的参数(如果没有就不写)

返回值:方法的返回值(如果没有就不写)

代码演示:

public class Main {
    public static void main(String[] args) throws Exception {
        // 获取Class对象
        Class<?> clazz = ExampleClass.class;
        
        // 获取要调用的方法
        Method method = clazz.getMethod("exampleMethod", int.class, String.class);
        
        // 实例化对象
        ExampleClass instance = new ExampleClass();
        
        // 调用方法
        Object result = method.invoke(instance, 10, "Hello");
        
        System.out.println("Method result: " + result);
    }
}

class ExampleClass {
    public String exampleMethod(int number, String text) {
        return "Number: " + number + ", Text: " + text;
    }
}

1.7  面试题

你觉得反射好不好?好,有两个方向

第一个方向:无视修饰符访问类中的内容(也就是暴力反射)。但是这种操作在开发中一般不用,都是框架底层来用的。

第二个方向:反射可以跟配置文件结合起来使用,动态的创建对象,动态的调用方法。

1.7.1  泛型擦除

集合中的泛型只在java文件中存在,当编译成class文件之后,就没有泛型了。

拓展:

在Java中,泛型是一种类型安全的编程机制,可以在集合中指定要存储的元素类型。当编译Java源代码时,编译器会对泛型进行类型擦除,将泛型相关的信息在生成的class文件中删除,这个过程称为擦除。因此,当Java源代码编译为class文件之后,其中的泛型信息就被擦除了,class文件中只保留了原始类型的信息。

1.7.2  修改字符串的内容

需要你掌握的是字符串不能修改的真正原因。

字符串,在底层是一个byte类型的字节数组,名字叫做value

private final byte[] value;

真正不能被修改的原因:final和private

final修饰value表示value记录的地址值不能修改。

private修饰value而且没有对外提供getvalue和setvalue的方法。所以,在外界不能获取或修改value记录的地址值。

如果要强行修改可以用反射

1.7.3  反射和配置文件结合动态获取

需求: 利用反射根据文件中的不同类名和方法名,创建不同的对象并调用方法。

代码演示:

public class ReflectDemo9 {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //1.读取配置文件的信息
        Properties prop = new Properties();
        FileInputStream fis = new FileInputStream("prop.properties");
        prop.load(fis);
        fis.close();
        System.out.println(prop);
        
        //通过key获取值
        String classname = prop.get("classname");
        String methodname = prop.get("methodname");

        //2.获取字节码文件对象
        Class clazz = Class.forName(classname);

        //3.要先创建这个类的对象
        Constructor con = clazz.getDeclaredConstructor();
        con.setAccessible(true);
        Object o = con.newInstance();
        System.out.println(o);

        //4.获取方法的对象
        Method method = clazz.getDeclaredMethod(methodname);
        method.setAccessible(true);

        //5.运行方法
        method.invoke(o);


    }
}

配置文件中的信息:
classname=com.itheima.a02reflectdemo1.Student
methodname=sleep

后续想要其他类或者其他方法来实现,只需要修改配置文件

1.7.4  利用反射保存对象中的信息

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.动态代理

2.1  概述

动态代理是一种设计模式,它允许在运行时创建代理对象来代替原始对象,从而实现对原始对象的控制或增强。在Java中,动态代理通常通过反射机制实现,主要使用了java.lang.reflect.Proxy类。动态代理可以在不修改原始类的情况下,对其方法调用进行增强、拦截或控制。

动态代理通常用于以下场景:

  1. 在原始类的方法执行前后添加日志记录、性能监控等功能。
  2. 实现远程方法调用(如RMI)。
  3. 实现事务管理。
  4. 实现权限控制。

动态代理实现在Java中比较灵活,能够在运行时动态生成代理类,并关联到目标对象上,从而实现代理模式的各种功能。需要注意的是,动态代理基于接口的实现,因此被代理的类必须实现一个或多个接口。

需求:

代理实现

代码实现:
 

public class Test {
    public static void main(String[] args) {
    /*
        需求:
            外面的人想要大明星唱一首歌
             1. 获取代理的对象
                代理对象 = ProxyUtil.createProxy(大明星的对象);
             2. 再调用代理的唱歌方法
                代理对象.唱歌的方法("只因你太美");
     */
        //1. 获取代理的对象
        BigStar bigStar = new BigStar("鸡哥");
        Star proxy = ProxyUtil.createProxy(bigStar);

        //2. 调用唱歌的方法
        String result = proxy.sing("只因你太美");
        System.out.println(result);
    }
}
/*
*
* 类的作用:
*       创建一个代理
*
* */
public class ProxyUtil {
    /*
    *
    * 方法的作用:
    *       给一个明星的对象,创建一个代理
    *
    *  形参:
    *       被代理的明星对象
    *
    *  返回值:
    *       给明星创建的代理
    *
    *
    *
    * 需求:
    *   外面的人想要大明星唱一首歌
    *   1. 获取代理的对象
    *      代理对象 = ProxyUtil.createProxy(大明星的对象);
    *   2. 再调用代理的唱歌方法
    *      代理对象.唱歌的方法("只因你太美");
    * */
    public static Star createProxy(BigStar bigStar){
       /* java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:

        public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
        参数一:用于指定用哪个类加载器,去加载生成的代理类
        参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
        参数三:用来指定生成的代理对象要干什么事情*/
        Star star = (Star) Proxy.newProxyInstance(
                ProxyUtil.class.getClassLoader(),//参数一:用于指定用哪个类加载器,去加载生成的代理类
                new Class[]{Star.class},//参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
                //参数三:用来指定生成的代理对象要干什么事情
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        /*
                        * 参数一:代理的对象
                        * 参数二:要运行的方法 sing
                        * 参数三:调用sing方法时,传递的实参
                        * */
                        if("sing".equals(method.getName())){
                            System.out.println("准备话筒,收钱");
                        }else if("dance".equals(method.getName())){
                            System.out.println("准备场地,收钱");
                        }
                        //去找大明星开始唱歌或者跳舞
                        //代码的表现形式:调用大明星里面唱歌或者跳舞的方法
                        return method.invoke(bigStar,args);
                    }
                }
        );
        return star;
    }
}
public interface Star {
    //我们可以把所有想要被代理的方法定义在接口当中
    //唱歌
    public abstract String sing(String name);
    //跳舞
    public abstract void dance();
}
public class BigStar implements Star {
    private String name;


    public BigStar() {
    }

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

    //唱歌
    @Override
    public String sing(String name){
        System.out.println(this.name + "正在唱" + name);
        return "谢谢";
    }

    //跳舞
    @Override
    public void dance(){
        System.out.println(this.name + "正在跳舞");
    }

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

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

    public String toString() {
        return "BigStar{name = " + name + "}";
    }
}

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

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

相关文章

Edge 浏览器键入时如何关闭显示搜索和站点建议

Edge 浏览器键入时如何关闭显示搜索和站点建议

ssm104园区停车管理系统+jsp

园区停车管理系统的设计与实现 摘 要 网络技术和计算机技术发展至今&#xff0c;已经拥有了深厚的理论基础&#xff0c;并在现实中进行了充分运用&#xff0c;尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代&#xff0c;所以对于信息的宣传和管…

基于SSM SpringBoot vue宾馆网上预订综合业务服务系统

基于SSM SpringBoot vue宾馆网上预订综合业务服务系统 系统功能 首页 图片轮播 宾馆信息 饮食美食 休闲娱乐 新闻资讯 论坛 留言板 登录注册 个人中心 后台管理 登录注册 个人中心 用户管理 客房登记管理 客房调整管理 休闲娱乐管理 类型信息管理 论坛管理 系统管理 新闻资讯…

【VueUse】超越基本功能的高级 Vue 元素操作

在vue开发中我们经常需要操作DOM元素&#xff0c;从简单的添加类到动态创建元素&#xff0c;这些操作都是不可避免的。而在VueUse库中&#xff0c;Elements相关API函数为我们提供了一系列强大而灵活的工具&#xff0c;帮助我们更轻松地处理DOM元素。无论是优雅地处理元素、动态…

25计算机考研院校数据分析 | 哈尔滨工业大学

哈尔滨工业大学&#xff08;Harbin Institute of Technology&#xff09;&#xff0c;简称哈工大&#xff0c; 校本部位于黑龙江省哈尔滨市&#xff0c;是由工业和信息化部直属的全国重点大学&#xff0c;位列国家“双一流”、“985工程”、“211工程”&#xff0c;九校联盟 、…

数据结构与算法之经典排序算法

一、简单排序 在我们的程序中&#xff0c;排序是非常常见的一种需求&#xff0c;提供一些数据元素&#xff0c;把这些数据元素按照一定的规则进行排序。比如查询一些订单按照订单的日期进行排序&#xff0c;再比如查询一些商品&#xff0c;按照商品的价格进行排序等等。所以&a…

ServiceNow 研究:通过RAG减少结构化输出中的幻觉

论文地址&#xff1a;https://arxiv.org/pdf/2404.08189 原文地址&#xff1a;rag-hallucination-structure-research-by-servicenow 在灾难性遗忘和模型漂移中&#xff0c;幻觉仍然是一个挑战。 2024 年 4 月 18 日 灾难性遗忘&#xff1a; 这是在序列学习或连续学习环境中出现…

Costas-Barker序列模糊函数仿真

文章目录 前言一、Costas 序列二、Barker 码三、Costas-Barker 序列模糊函数仿真1、MATLAB 核心代码2、仿真结果①、Costas-Barker 模糊函数图②、Costas-Barker 距离模糊函数图③、Costas-Barker 速度模糊函数图 四、资源自取 前言 Costas 码是一种用于载波同步的频率调制序列…

20232810 2023-2024-2 《网络攻防实践》实验七

一、实践内容 &#xff08;1&#xff09;使用Metasploit进行Linux远程渗透攻击 任务&#xff1a;使用Metasploit渗透测试软件&#xff0c;攻击Linux靶机上的Samba服务Usermap_script安全漏洞&#xff0c;获取目标Linux靶机的主机访问权限。实践步骤如下&#xff1a; ①启动Met…

字节跳动发起AI战争 寻找下一个TikTok

现如今在字节跳动&#xff0c;已近乎隐退的张一鸣&#xff0c;只重点关注两件事&#xff1a;其一&#xff0c;是风暴中的TikTok&#xff1b;其二&#xff0c;就是字节跳动正在全力追赶的AI战略业务。 提及字节的AI战略远望,多个接近字节的人士均认为,以Flow部门出品最为“正统…

缩小COCO数据集

在运行YOLOS模型的过程中&#xff0c;需要使用到COCO2017这个数据集&#xff0c;但从实验运行来看&#xff0c;其所需时间无疑是相当漫长&#xff0c;预计可能需要近几十天才能完成&#xff0c;因此便考虑缩小COCO数据集大小&#xff0c;即尽可能在遵循其分布的情况下&#xff…

Unity开发一个FPS游戏之四

在前面的系列中&#xff0c;我已介绍了如何实现一个基本的FPS游戏&#xff0c;这里将继续进行完善&#xff0c;主要是增加更换武器以及更多动作动画的功能。 之前我是采用了网上一个免费的3D模型来构建角色&#xff0c;这个模型自带了一把AR自动步枪&#xff0c;并且自带了一些…

Unity开发微信小游戏(2)分享

目录 1.概述 2.代码 3.示例 4.个人作品 1.概述 这里我们能做有两件事&#xff1a; 1&#xff09;主动发起分享 2&#xff09;监听右上角分享&#xff08;...按钮&#xff0c;发朋友圈也在这里&#xff09; API&#xff1a;官方文档 2.代码 1&#xff09;主动发起分享&…

DHCPv4_CLIENT_ALLOCATING_01: 在其本地物理子网上广播DHCPDISCOVER消息

测试目的&#xff1a; 确保客户端能够在其本地物理子网上广播DHCPDISCOVER消息。 描述&#xff1a; 该测试用例旨在验证DHCP客户端是否能够正确地在其本地物理子网上广播DHCPDISCOVER消息&#xff0c;以便进行IP地址的自动分配。 测试拓扑&#xff1a; 测试步骤&#xff1a…

生产看板:最直观的车间管理方式之一,是马是马户牵出来溜溜。

可视化生产看板在组织工业生产中扮演着重要的角色&#xff0c;它可以提供实时的信息和可视化的数据&#xff0c;帮助团队和管理层更好地监控和管理生产过程。 以下是可视化生产看板在组织工业生产中的作用&#xff1a; 实时监控&#xff1a;可视化生产看板可以显示实时的生产数…

JavaEE初阶-多线程易忘点总结

文章目录 1.PCBPID文件描述符表内存指针状态上下文优先级记账信息tgid 2.线程与进程的区别3.sleep和interrupt方法的关系变量终止线程interrupt方法终止线程 4.线程状态5.出现线程不安全的原因线程在系统中是随即调度&#xff0c;抢占式执行的。多个线程修改同一个变量线程针对…

小白也能微调大模型:LLaMA-Factory使用心得

大模型火了之后&#xff0c;相信不少人都在尝试将预训练大模型应用到自己的场景上&#xff0c;希望得到一个垂类专家&#xff0c;而不是通用大模型。 目前的思路&#xff0c;一是RAG(retrieval augmented generation)&#xff0c;在模型的输入prompt中加入尽可能多的“目标领域…

Linux-管道通信

1. 管道概念 管道&#xff0c;是进程间通信的一种方式&#xff0c;在Linux命令中“ | ”就是一种管道&#xff0c;它可以&#xff0c;连接前一条命令&#xff0c;和后一条命令&#xff0c;把前面命令处理完的内容交给后面&#xff0c;例如 cat filename | grep hello …

富文本编辑器CKEditor4简单使用-07(处理浏览器不支持通过工具栏粘贴问题 和 首行缩进的问题)

富文本编辑器CKEditor4简单使用-07&#xff08;处理浏览器不支持通过工具栏粘贴问题 和 首行缩进的问题&#xff09; 1. 前言——CKEditor4快速入门2. 默认情况下的粘贴2.1 先看控制粘贴的3个按钮2.1.1 工具栏粘贴按钮2.1.2 存在的问题 2.2 不解决按钮问题的情况下2.2.1 使用ct…

三维图形学知识分享---求平面与模型相交线

在CGAL&#xff08;Computational Geometry Algorithms Library&#xff09;中&#xff0c;Polygon_mesh_processing模块提供了用于处理多边形网格数据结构的功能。其中&#xff0c;surface_intersection函数是用来计算模型的表面相交线的工具。 CGAL_Mesh mesh_orcl;std::vect…