浅谈反射机制

news2024/11/26 16:22:04

1. 何为反射?

反射(Reflection)机制指的是程序在运行的时候能够获取自身的信息。具体来说,反射允许程序在运行时获取关于自己代码的各种信息。如果知道一个类的名称或者它的一个实例对象, 就能把这个类的所有方法和变量的信息(方法名,变量名,方法,修饰符,类型,方法参数等等所有信息)找出来。这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。简单来说,就是面向对象看待一个类,即以面向对象的思想来抽象一个类。

反射是一种强大的功能,广泛应用于框架设计、依赖注入、单元测试和动态代理等领域。然而,由于反射会绕过编译时的类型安全检查,所以使用不当可能会导致更高的运行时错误几率和性能开销。因此,在使用反射时需要格外谨慎,以避免潜在的风险。

2. 反射的意义所在?

  1. 通过反射机制可以让程序创建和控制任何类的对象,无需提前硬编码目标类。
  2. 使用反射机制能够在运行时构造一个类的对象、判断一个类所具有的成员变量和方法、调用一个对象的方法。
  3. 反射机制是构建框架技术的基础所在,使用反射可以避免将代码写死在框架中。

不过反射也存在明显的缺点:使用反射性能较低,需要解析字节码,且如果将内存中的对象进行解析,相对不安全,会破坏封装性。

3. 通过反射实例化对象

在Java中,可以通过反射获取类的构造器、方法、字段等信息:

class Test {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {

        // 下面这段代码是以反射机制的方式创建对象。

        // 通过反射机制,获取Class,通过Class来实例化对象
        Class c = Class.forName("com.reflectBean.User");

        // newInstance() 这个方法会调用User这个类的无参数构造方法,完成对象的创建。
        // 重点是:newInstance()调用的是无参构造,必须保证无参构造是存在的!
        Object obj = c.newInstance();

        Method method = c.getMethod("myMethod");
        method.invoke(obj);
    }
}

4. 获取Class类的三种方式

在Java编程中,获取 Class 对象的三种常用方式如下:

1. 通过类名的静态属性 class: 这是获取 Class 对象最简单的方法,适用于已知编译时类型的情况。

Class<MyClass> clazz = MyClass.class;

2. 通过对象的实例方法 getClass: 这是在运行时获取一个对象的 Class 对象的方法,适用于已知一个实例化对象的情况。

MyClass obj = new MyClass();
Class<? extends MyClass> clazz = obj.getClass();

3. 通过类名的字符串 forName: 这是动态加载类的一种方式,特别有用在类名只有在运行时才能确定的情况下。

try {
    Class<?> clazz = Class.forName("com.reflectBean.User");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

5. 常用的Class类的方法

Class 类在 Java 中定义了大量的方法,可以用来反射性地获取类的各种信息或进行操作。不过需要注意的是,在使用反射进行私有成员访问时,需要设置相应的访问权限,如 setAccessible(true)。以下是一些常用的方法:

1. 类信息获取方法

  • getName():返回完整类名带包名。

  • getSimpleName():获取类的简单名称。

  • getCanonicalName():获取类的规范名称。

  • getPackage():获取类所在的包。

  • getModifiers():获取类的修饰符(如 public, abstract, final 等)。

2. 构造函数相关方法

  • getConstructor(Class<?>... parameterTypes):获取指定参数类型的公共构造函数。

  • getConstructors():获取所有公共构造函数。

  • getDeclaredConstructor(Class<?>... parameterTypes):获取指定参数类型的任意(包括私有)构造函数。

  • getDeclaredConstructors():获取所有任意(包括私有)构造函数。

3. 方法相关方法

  • getMethod(String name, Class<?>... parameterTypes):获取指定名称和参数类型的公共方法。
  • getMethods():获取所有公共方法,包括从父类继承的方法。
  • getDeclaredMethod(String name, Class<?>... parameterTypes):获取指定名称和参数类型的任意方法。
  • getDeclaredMethods():获取所有任意方法(包括私有)。

4. 字段(成员变量)相关方法

  • getField(String name):获取指定名称的公共字段。
  • getFields():获取所有公共字段。
  • getDeclaredField(String name):获取指定名称的任意字段。
  • getDeclaredFields():获取所有任意字段(包括私有)。

5. 类层次结构相关方法

  • getSuperclass():获取父类。
  • getInterfaces():获取实现的接口。
  • isAssignableFrom(Class<?> cls):判断当前类或接口是否可以从指定类型的对象赋值(即能否进行类型转换)。

6. 实例创建方法

  • newInstance():创建类的实例,需要无参构造函数。

7. 其他方法

  • getAnnotations():获取类上的注解。
  • isAnnotation():判断类是否是注解类型。
  • isInterface():判断是否为接口。
  • isArray():判断是否为数组。
  • isPrimitive():判断是否为基本数据类型。
  • isInstance(Object obj):判断给定对象是否为该 Class 的实例。

6. 获取Field的四种方式

在Java中,可以通过Class对象获取某个类的字段(Field),Field类代表类的成员变量。获取 Field的几种常用方式如下:

1. 通过字段名获取公共字段 (public 属性):

try {
    Class<?> clazz = Class.forName("com.reflectBean.User");
    Field field = clazz.getField("userName");
    // 对 field 进行操作
    // ...

} catch (NoSuchFieldException | ClassNotFoundException e) {
    e.printStackTrace();
}

2. 获取所有公共字段 (public 属性):

try {
    Class<?> clazz = Class.forName("com.reflectBean.User");
    Field[] fields = clazz.getFields();
    for (Field field : fields) {
        // 对每个 field 进行操作
        // ...    
    }
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

3. 通过字段名获取任何字段(包括私有、保护和包访问属性):

try {
    Class<?> clazz = Class.forName("com.reflectBean.User");
    Field field = clazz.getDeclaredField("password");
    // 允许访问私有字段
    field.setAccessible(true);  
    // 对 field 进行操作,比如设置可访问性
    field.setAccessible(true);
} catch (NoSuchFieldException | ClassNotFoundException e) {
    e.printStackTrace();
}

4. 获取所有字段(包括私有、保护和包访问属性):

try {
    Class<?> clazz = Class.forName("com.reflectBean.User");
    Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields) {
        // 对每个 field 进行操作,比如设置可访问性
        field.setAccessible(true);
    }
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

7. 常用的Field类的方法

在Java中,Field类提供了许多方法,用于获取和操作类的字段(成员变量)。以下是一些常用的方法:

1. 获取字段信息的方法

  • getName():返回字段的名称。
  • getType():返回表示字段类型的 Class 对象。
  • getGenericType():返回表示字段的 Type 对象,包括泛型类型信息。
  • getModifiers():返回字段的修饰符整数编码(使用 Modifier 类中的方法可以解码)。

2. 访问和修改字段值的方法

  • get(Object obj):从指定对象中获取该字段的值。
  • getByte(Object obj):从指定对象中获取该字段的值(byte类型)。
  • set(Object obj, Object value):将指定对象的该字段设置为新的值。

3. 访问控制

  • setAccessible(boolean flag):设置字段的可访问性。即使字段是私有的,通过设置可访问性也可以访问它。

8. 获取Method的四种方式

在Java中,可以通过反射机制获取类的方法(Method)对象。以下是几种常用的方法获取方式:

1. 通过方法名和参数类型获取公共方法

try {
            // 获取类的Class对象
            Class<?> clazz = Class.forName("com.reflectBean.User");
            // 通过方法名和参数类型获取公共方法
            Method method = clazz.getMethod("publicMethod", String.class);
            // 调用方法
            method.invoke(null, "参数");

        } catch (Exception e) {
            e.printStackTrace();
        }

2. 获取所有公共方法

try {
            // 获取类的Class对象
            Class<?> clazz = Class.forName("com.reflectBean.User");

            // 获取所有公共方法
            Method[] methods = clazz.getMethods();

            // 遍历所有方法
            for (Method method : methods) {
                // 获取方法名
                String methodName = method.getName();
                // 判断方法名是否为getName
                if (methodName.equals("getName")) {
                    // 执行getName方法
                    Object result = method.invoke(user);
                    System.out.println(result);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

3. 通过方法名和参数类型获取任意方法(包括私有、保护和默认访问权限的方法)

try {
            // 获取类的Class对象
            Class<?> clazz = Class.forName("com.reflectBean.User");

            // 通过方法名和参数类型获取任意方法
            Method method = clazz.getDeclaredMethod("privateMethod", int.class);
             // 调用方法
            method.invoke(new com.reflectBean.User(), 100);

            // 允许访问私有方法
            method.setAccessible(true);
        } catch (Exception e) {
            e.printStackTrace();
        }

4. 获取所有的任意方法(包括私有、保护和默认访问权限的方法)

try {
            // 获取类的Class对象
            Class<?> clazz = Class.forName("com.example.MyClass");

            // 获取所有任意方法
            Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                // 对每个 method 进行操作
                // ...
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

9. 常用的Method的方法

Method类在Java反射中提供了许多方法,这些方法可以用于获取方法的各类信息、调用方法以及操作注解等。以下是一些常用的Method类方法:

1. 获取方法信息的方法

  • String getName():获取方法的名称。
  • Class<?> getDeclaringClass():获取声明此方法的类或接口的Class对象。
  • Class<?> getReturnType():获取方法的返回类型。
  • Type getGenericReturnType():获取方法的泛型返回类型。
  • Class<?>[] getParameterTypes():获取方法的参数类型数组。
  • Type[] getGenericParameterTypes():获取方法的泛型参数类型数组。
  • int getParameterCount():获取方法的参数数量。
  • Class<?>[] getExceptionTypes():获取方法声明的异常类型数组。
  • Type[] getGenericExceptionTypes():获取方法声明的泛型异常类型数组。
  • int getModifiers():获取方法的修饰符,用于确定方法是public、private、protected、static等。
  • Annotation[][] getParameterAnnotations():获取方法的参数上的注解。
  • String toGenericString():返回描述方法的字符串,包括泛型信息。

2. 调用方法

  • Object invoke(Object obj, Object... args):调用此Method对象表示的底层方法。

3. 注解相关的方法

  • <T extends Annotation> T getAnnotation(Class<T> annotationClass):获取指定类型的注解。
  • Annotation[] getAnnotations():获取此方法上存在的所有注解。
  • Annotation[] getDeclaredAnnotations():获取直接存在于此方法上的所有注解。
  • <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass):获取直接存在于此方法上的指定类型的注解。
  • <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass):获取直接存在于此方法上的指定类型的所有注解。
  • <T extends Annotation> T getAnnotationsByType(Class<T> annotationClass):获取此方法上存在的指定类型的所有注解。
  • boolean isAnnotationPresent(Class<? extends Annotation> annotationClass):判断此方法上是否存在指定类型的注解。

4. 设置和获取访问控制

  • void setAccessible(boolean flag):设置方法的可访问性。如果是 true,则强制使能此方法,即使它是私有的。
  • boolean isAccessible():判断此方法是否可以通过反射执行。

5. 其他常用方法

  • boolean isSynthetic():判断此方法是否是编译器生成的合成方法。
  • boolean isVarArgs():判断此方法是否接受可变数量的参数。

10. 实践出真知

好了,扯了那么久反射的概念和基础使用,接下来,结合反射的内容,我们来简单演示通过反射去实现一些基本业务。

10.1 如何通过反射获取和设置对象私有字段的值?

先捋清楚思路,获取和设置对象私有字段的值,大致可以分为四个步骤实现:

1. 获取对象的 Class 对象。
2. 通过反射获取私有字段 Field 对象。
3. 设置字段的可访问性为 true,以绕过 Java 语言访问检查。
4. 通过反射获取和设置字段的值。

那么接下来演示下代码的实现流程:

假设有一个包含私有字段的类:AccountBalance.class

public class AccountBalance {

    // 设置初始值为100
    private BigDecimal balance = new BigDecimal(100);

    // 默认构造函数
    public AccountBalance() {
    }

    // 打印字段值的方法
    public void printField() {
        System.out.println("当前的账户余额为: " + balance);
    }
}

接下来,我们来演示下怎么通过反射获取账户余额,然后变更私有字段:

public class Test {

    public static void main(String[] args) {
        try {
            // 创建 AccountBalance 对象实例
            AccountBalance account = new AccountBalance();

            // 获取 AccountBalance 的 Class 对象
            Class<?> clazz = account.getClass();

            // 获取私有字段
            Field privateField = clazz.getDeclaredField("balance");

            // 设置字段的可访问性为 true
            privateField.setAccessible(true);

            // 获取私有字段的值
            BigDecimal initBlance = (BigDecimal) privateField.get(account);
            System.out.println("最初的账号余额为: " + initBlance);

            // 设置私有字段的值
            privateField.set(account, new BigDecimal(50));

            // 验证字段值已经更新
            initBlance = (BigDecimal) privateField.get(account);
            System.out.println("本次扣除的账户余额为: " + initBlance);

            // 使用类的方法验证字段被正确修改
            account.printField();
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

控制台输出:

10.2 如何用反射机制创建对象呢?

依旧是先整理下步骤,使用反射机制创建对象,大致可分为3个步骤:

1. 获取类的Class对象。
2. 通过Class对象获取构造方法(构造器)。注意,这里虽然可以通过Class对象的newInstance方法简单地创建一个类的实例,但是这种方式只能调用无参构造函数,故该实例不给予演示。
3. 使用构造方法创建类的实例。

还是假设我们有一个包含无参和有参数构造函数的类AccountBalance.class

public class AccountBalance {
    // 设置初始值为100
    private BigDecimal balance = new BigDecimal(100);

    // 默认构造函数
    public AccountBalance() {
        System.out.println("调用无参构造函数");
    }

    // 有参构造函数
    public AccountBalance(BigDecimal initialBalance) {
        this.balance = initialBalance;
        System.out.println("调用带参数的构造函数:初始化余额为 " + initialBalance);
    }

    // 打印字段值的方法
    public void printField() {
        System.out.println("当前的账户余额为: " + balance);
    }
}

使用Constructor.newInstance()创建对象并访问其方法

public void Test {

     public static void main(String[] args) {
        try {
            // 获取 AccountBalance 的 Class 对象
            Class<?> clazz = Class.forName("com.example.AccountBalance");

            // 获取有参构造函数
            Constructor<?> constructor = clazz.getConstructor(BigDecimal.class);

            // 使用构造函数创建实例并传递参数
            Object obj = constructor.newInstance(new BigDecimal(200));

            // 验证对象创建成功,通过调用方法
            Method printMethod = clazz.getMethod("printField");
            printMethod.invoke(obj);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

10.3 如何反编译一个类的构造方法?

反编译一个类的构造方法,大致可以分为四个步骤实现:

1. 获取需要被反编译的类的Class对象

2. 获取类所有声明的构造方法

3. 循环遍历所有的构造方法

4. 获取每个构造方法的修饰符、参数类型并格式化输出

我们仍然以AccountBalance类为例进行说明。

public class AccountBalance {
    // 设置初始值为100
    private BigDecimal balance = new BigDecimal(100);

    // 默认构造函数
    public AccountBalance() {
        System.out.println("调用无参构造函数");
    }

    // 有参构造函数
    public AccountBalance(BigDecimal initialBalance) {
        this.balance = initialBalance;
        System.out.println("调用带参数的构造函数:初始化余额为 " + initialBalance);
    }

    // 打印字段值的方法
    public void printField() {
        System.out.println("当前的账户余额为: " + balance);
    }
}

进行反编译构造方法流程:

public void Test {

    public static void main(String[] args) {
        try {
            // 获取 AccountBalance 的 Class 对象
            Class<?> clazz = Class.forName("com.example.AccountBalance");

            // 获取所有声明的构造方法(包括私有构造方法)
            Constructor<?>[] constructors = clazz.getDeclaredConstructors();

            for (Constructor<?> constructor : constructors) {
                // 获取构造方法的修饰符
                String modifiers = Modifier.toString(constructor.getModifiers());

                // 获取构造方法的参数类型
                Class<?>[] parameterTypes = constructor.getParameterTypes();
                StringBuilder params = new StringBuilder();
                for (int i = 0; i < parameterTypes.length; i++) {
                    params.append(parameterTypes[i].getSimpleName());
                    if (i < parameterTypes.length - 1) {
                        params.append(", ");
                    }
                }

                // 打印构造方法的详细信息
                System.out.println(modifiers + " " + clazz.getSimpleName() + "(" + params + ") { }");
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    
}

10.4  给定一个类,如何获取这个类的基类以及实现的接口呢?

这种问题的思路,需要考虑两点:
1. 怎么获取该类的父类:这点可以使用Class提供的getSuperClass()方法来获取。

2. 怎么获取类的接口:这点可以使用Class提供的getInterfaces()方法获取实现的接口。

假设定义了以下类和接口:ChildClass.class 和 Parent.class、Car.java。

public class ChildClass extends ParentClass implements Car {

}
public class ParentClass {

}
public interface Car {
}

获取一个类的父类和实现的接口的具体示例:

public static void main(String[] args) throws ClassNotFoundException {
        try {
            // 获取 ChildClass 的 Class 对象
            Class<?> clazz = Class.forName("com.example.ChildClass");

            // 获取父类
            Class<?> superClass = clazz.getSuperclass();
            System.out.println("父类: " + superClass.getName());

            // 获取实现的接口
            Class<?>[] interfaces = clazz.getInterfaces();
            System.out.println("实现的接口:");
            for (Class<?> iface : interfaces) {
                System.out.println(iface.getName());
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
}

11. 总结

反射机制是Java语言中一种强大的功能,它让我们能够在运行时进行一些本应只能在编译时完成的操作。这个功能的特点就是使得程序可以动态地检查和操作类、方法、字段等,从而带来了极大的灵活性。简单来说,反射机制使得开发人员能够编写更加灵活和动态的代码。举个例子,我们可以根据配置文件来动态创建对象、实现依赖注入、在运行时调用方法而不需要提前知道方法的名称。

然而,反射机制虽然给我们带来了好处,但也有一些弊端需要注意。首先,反射通常会比直接调用要慢,因为它会绕过一些编译时的优化。其次,由于反射机制允许操作私有成员,可能会破坏封装性和安全性。最后,使用反射的代码可读性降低,同时也更难以维护和调试。因此,在使用反射时需要谨慎考虑其影响。

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

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

相关文章

亚马逊跟卖ERP的自动调价功能,能够简易地批量设置价格规则。

跟卖的智能调价 跟卖智能调价简单说是可以上调&#xff0c;下调就是怎么说&#xff1f;上调就是它根靠根据市场最低的价格情况进行去上调。 然后添加指定条件&#xff0c;到工具栏找到指定条件&#xff0c;点击添加指定条件。 然后选择店铺&#xff0c;比如选择店铺&#xf…

【C++】认识使用string类

【C】STL中的string类 C语言中的字符串标准库中的string类string类成员变量string类的常用接口说明成员函数string(constructor构造函数)~string(destructor析构函数)默认赋值运算符重载函数 遍历string下标[ ]迭代器范围for反向迭代器 capacitysizelengthmax_sizeresizecapaci…

软件测试之接口自动化测试实战(完整版)

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 自从看到阿里云性能测试 PTS 接口测试开启免费公测&#xff0c;就想着跟大家分享交流一下如何实现…

Vue 前端修改页面标题无需重新打包即可生效

在public文件夹下创建config.js文件 index.html页面修改 其他页面的标题都可以用window.title来引用就可以了&#xff01;

力扣53. 最大子数组和(动态规划)

Problem: 53. 最大子数组和 文章目录 题目描述思路及解法复杂度Code 题目描述 思路及解法 1.定义dp数组&#xff1a;dp[i]表示以nums[i]为结尾的子序列的最大子序列和&#xff1b; 2.状态初始化&#xff1a;dp[0] nums[0],表示以nums[0]为结尾的子序列的最大子序列和为nums[0]…

自己动手实现语音识别

声音的本质是震动,震动的本质是位移关于时间的函数,波形文件(.wav)中记录了不同采样时刻的位移。 通过傅里叶变换,可以将时间域的声音函数分解为一系列不同频率的正弦函数的叠加,通过频率谱线的特殊分布,建立音频内容和文本的对应关系,以此作为模型训练的基础。 语音mfc…

面向对象案例:电影院

TOC 思路 代码 结构 具体代码 Movie.java public class Movie {//一共七个private int id;private String name;private double price;private double score;private String director;private String actors;private String info;//get和setpublic int getId() {return id;…

Nuxt3 的生命周期和钩子函数(十一)

title: Nuxt3 的生命周期和钩子函数&#xff08;十一&#xff09; date: 2024/7/5 updated: 2024/7/5 author: cmdragon excerpt: 摘要&#xff1a;本文详细介绍了Nuxt3中几个关键的生命周期钩子和它们的使用方法&#xff0c;包括webpack:done用于Webpack编译完成后执行操作…

Git-如何修改git项目的远程仓库地址

前言 因为工作需要&#xff0c;现在准备将原来的git项目远程仓库地址修改为另一个&#xff0c;那么需要如何做呢&#xff1f; 第一种 1、首先需要在github中新建一个repository 2、创建之后会有一个对应的远程仓库地址&#xff0c;复制这个新建repository的url备用 3、找…

ython 使用 cx_Freeze 打包,不想要打包文件中能直接看到依赖的代码,如何处理

背景&#xff1a;因为使用 cx_Freeze 打包时&#xff0c;添加需要依赖的文件 cx_Freeze 是一个用于将 Python 程序打包成独立可执行文件的工具&#xff0c;支持多个平台。当你需要打包包含多个 .py 文件的项目时&#xff0c;你可以通过编写一个 setup.py 文件来指定哪些模块应…

物联网平台产品介绍

中服云物联网平台在功能、性能、易用性方面有较大的提升&#xff0c;成为业界领先的工业物联网平台。主要包含8大能力&#xff1a;数据采集与控制、基础物联组件集、快速开发工具集、数据集管理、数据处理与分析、平台配置管理、手机端小程序、二次开发接口。 产品配图&#x…

踩坑:Unity导出WebGL发布到手机上竖屏时强制显示横屏

具体的适配问题 公司的项目需要将游戏导出WebGL 发布到Web平台 本以为是个很简单的事情 谁知道却被个横竖屏适配搞的头晕 毕竟只有大学浅浅的学了下HTML这门语言 出来工作后基本上都是在跟C# Lua打交道 言归正传 看看具体问题吧 游戏如果从横屏进入 基本上不会有什么适配问题…

firewalld(7)NAT、端口转发

简介 在前面的文章中已经介绍了firewalld了zone、rich rule等规则设置&#xff0c;并且在iptables的文章中我们介绍了网络防火墙、还有iptables的target,包括SNAT、DNAT、MASQUERADE、REDIRECT的原理和配置。那么在这篇文章中&#xff0c;将继续介绍在firewalld中的NAT的相关配…

电气-伺服(6)脉冲控制

一、脉冲模式原理&#xff1a; 运动控制器输出脉冲信号给伺服驱动器 伺服驱动器工作于位置模式 伺服驱动器内部要完成三闭环&#xff08;位置闭环 、速度闭环、电流环&#xff09; 脉冲和伺服控制环&#xff1a;脉冲的个数作用于位置环。脉冲的频率作用于速度环 二、脉冲的两…

【论文阅读】LLM+3D (1)

文章目录 1. 【CoRL 2023】SayPlan: Grounding Large Language Models using 3D Scene Graphs for Scalable Robot Task Planning动机摘要和结论引言模型框架3.1 Problem Formulation3.2 Preliminaries 2. ShapeLLM: Universal 3D Object Understanding for Embodied Interacti…

【Unity小知识】UnityEngine.UI程序集丢失的问题

问题表现 先来说一下问题的表现&#xff0c;今天在开发的时候工程突然出现了报错&#xff0c;编辑器提示UnityEngine.UI缺少程序集引用。 问题分析与解决&#xff08;一&#xff09; 既然是程序集缺失&#xff0c;我们首先查看一下工程项目是否引用了程序集。在项目引用中查找一…

解决uni-app中全局设置页面背景颜色只有部分显示颜色的问题

在页面的style标签设置了背景色但是只显示一部分 <style lang="scss"> .content{background-color: #f7f7f7;height: 100vh; } </style>我们在app.vue里设置就行了 注意一定要是**page{}** <style>/*每个页面公共css */page{background-color:

结合数据索引结构看SQL的真实执行过程

引言 关于数据库设计与优化的前几篇文章中&#xff0c;我们提到了数据库设计优化应该遵守的指导原则、数据库底层的索引组织结构、数据库的核心功能组件以及SQL的解析、编译等。这些其实都是在为SQL的优化、执行的理解打基础。 今天这篇文章&#xff0c;我们以MySQL中InnoDB存…

【Cadence18】如何放置定位孔

在菜单的place->manually会出现Placement对话框&#xff0c; 在Advanced settings中勾选database和library 然后点击Placement list&#xff0c;下拉框中选择Mechanical symbols,勾选你要的定位孔 &#xff08;如下图的HOLE_1_6R00D2R70-PTH&#xff0c;注意&#xff1a;…

Windows 11内置一键系统备份与还原 轻松替代Ghost

面对系统崩溃、恶意软件侵袭或其他不可预见因素导致的启动失败&#xff0c;Windows 7~Windows 11内置的系统映像功能能够迅速将您的系统恢复至健康状态&#xff0c;确保工作的连续性和数据的完整性。 Windows内置3种备份策略 U盘备份&#xff1a;便携且安全 打开“创建一个恢…