当前位置: 首页 > news >正文

java 注解和反射

一、什么是注解(Annnotation)

框架(MVC、springboot)的底层就是注解!

注解和注释的不同:注释是写给人看的,注解既是写给人看的也是写给程序(比如编译器、虚拟机)看的。源码有效的注解就是给编译器看的,因为还没运行呢这个注解就“功成身退”了,而运行时有效的注解是给虚拟机看的。

注解的作用:

1)给程序看,通过反射机制实现对元数据的访问

2)检查程序的正确性。比如@Override注解会检查重写的方法名是否写对了。

二、3个内置注解

1. @Override

2. @Deprecated

自己也可以给自己之前写的方法打上@Deprecated注解

3. @SuppressWarnings("参数") 镇压方法中的警告信息

三、4个元注解

元注解:注解的注解,写在注解的上一行,比如

  • @Target:描述注解可以放在哪里(方法的上面还是类的上面还是字段的上面。。。)
  • @Retention:注解的生命周期
    • SOURE(源码时有效) < CLASS(编译成.class时依然有效) <RUNTIME (运行时依然有效,一般写这个)
      • SOURCE是什么意思?
        • 我们的@Data、@Setter、注解都是被@Retention(RetentionPolicy.SOURCE)去修饰的。写源码时,可以看到@Setter注解,但是编译后,.calss文件里多了setter方法,而@Setter注解却功成身退了(用反编译去看)。

        • 还有,@Override在编译的时候就告诉编译器要检查重写的语法是否符合父类规定,生成的.class文件不含这些注解。

      • CLASS是什么意思?

        • 注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期。这个的例子还没理解到位,以后再来填坑

  • @Documnet:注解本身是否包含在 JavaDoc 文档中。默认情况下,注解不会出现在生成的文档里
  • @Inherited:子类可以继承父类中的注解
//Target表明 @MyAnnotation 可以用在方法上、类上、字段上、入参上,注解上 @Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.Type(类上),ElementType.FIELD, ElementType.ANNOTATION_TYPE}) //Retention表明 @MyAnnotation从源码到运行时都有效,也就是一直有效 @Retention(value = RetentionPolicy.RUNTIME) //Documented 表明将注解 @MyAnnotation写入javadoc中 @Documented //Inherited表明注解@MyAnnotation可被子类继承 @Inherited //自定义一个注解 @interface MyAnnotation{ }

四、自定义注解

为什么注解和反射放在一起讲,有什么关系吗?

先放一放这个问题,先问:自定义注解如何用?

用来打tag。比如,你想标记一批方法,用来给程序看,那你就自定义一个注解,遇到带这类标签的方法,就用springAOP的方式执行某一些操作,springAOP是通过反射实现的,这就回答了刚刚提出的问题“为什么注解和反射放在一起讲,有什么关系吗?”。别绕晕了,标签一定是打给程序看的,如果只是单纯的打标签给你自己看的话,那不就是注释嘛??!!

  • 用@interface自定义注解,自动继承java.lang.annotation.Annotation接口
  • 如果自定义注解只有一个参数,建议命名为value。这样使用注解的时候就不用指明参数名了

一个参数时:

//测试注解在类上有效 @MyAnnotation public class DiyAnnotation { //注解只有一个参数,且命名为value时,可以省略 value= @MyAnnotation2("2022 is wonderful enough! kickboxing!") public void test03(){ } } @Target(value = {ElementType.METHOD,ElementType.TYPE}) @Retention(value = RetentionPolicy.RUNTIME) //自定义一个注解 @interface MyAnnotation2{ String value() default ""; //只有一个参数 }

多个参数时:

//测试注解在类上有效 @MyAnnotation public class DiyAnnotation { //测试注解在方法上有效 //三个参数都有默认值,注解可以都不写参数 @MyAnnotation public static void main(String[] args) { } //也可以写参数 @MyAnnotation(name = "December",age=27,word = "New Year is around the corner!") public void test01(){ } //也可以写部分参数 @MyAnnotation(word = "New start, must be wonderful!") public void test02(){ } } @Target(value = {ElementType.METHOD,ElementType.TYPE}) @Retention(value = RetentionPolicy.RUNTIME) //自定义一个注解 @interface MyAnnotation{ /* * 注解的参数们 * 必须带括号! * */ String name() default ""; //第一个参数,默认值为空 int age() default 18; //第二个参数,默认值为18 String word() default ""; //第三个参数,默认值为空 }

四、注解是如何生效的*

换个问法

  • 为什么加一个@Data注解,编译后就自动生成了equals等一系列方法?
  • 为什么给BookServiceImpl加一个@Service注解,就自动注入了一个bean?

解析注解的两个阶段/两种方式,刚好对应了上面两种场景

  • javac:编译器读取注解,然后自动生成代码,或者@Override对代码进行语法检查
  • java: java虚拟机运行时基于反射去获取类的属性、执行类的方法。JVM扫描到@Service方法的时候,本质上是执行了BookServiceImpl类的setter方法

五、什么是反射(Reflection)

彻底理解反射机制:就像Linux认为all is file一样,java中一切都是对象,那么类是不是对象呢?是。类能是谁的对象呢?所有的类都是java.lang.Class类的对象,用Class c1 = 类.class的c1去表示,因为类也是对象,对象可以调用成员方法,那么c1就可以用java.lang.Class类定义的成员方法去获得类的各种信息。

此外,反射被称为框架的灵魂,主要是因为它赋予了我们在运行时1)获取类的信息 以及2)执行类中方法的能力。

—— 运行时获取任意一个对象所属的类Class c1【就跟你亲眼见到这个类的.java文件一样

└─—— 获得了Class c1后,就能知道这个类的所有属性

├─ 包括public、protected、private

└─—— 获得了Class c1后,就能知道这个类的所有方法

├─ 方法的参数

└─ 方法的返回值

—— 运行时创建任意一个类的对象、调用类的方法。【就跟你打开其他.java文件,要new一个这个类的对象开始使用一样

java本身是一个静态语言,正是反射让java具有动态性

5.1 静态语言和动态语言

区分动态语言和动态网页技术

静态语言与动态语言:静态类型语言在编译时便已确定变量的类型,而动态类型语言的变量类型要到程序运行的时候,待变量被赋予某个值之后,才会具有某种类型

静态网页技术与动态网页技术:HTML是静态网页技术;JSP是动态网页技术,动态部分就是<% %>括起来的java代码。

5.2 反射的优缺点

优点:灵活性(静态语言->动态语言),利用反射开发出各种框架spring/mybatis/springboot,极大方便了我们的开发。

缺点:慢!(反射也是生成一个对象,和我们直接new一个对象比起来慢了几十几百倍)

5.3 反射相关的API

学习反射就是学习Class对象和java.lang.reflect对应的各种API,听到这里放心了吧!说到底还是和集合一样,学习各种API!而且十分简单!

5.4 获得反射对象

5.5 得到Class类对象的5种方式

1. java.lang.Class类

为了方便讲述,我们假设Person类是当前类

  • Class类是反射的根源,反射前必须找到相应的Class对象。
  • 这个Class对象中存储了Person类对象的真实类、类的属性、方法、实现了哪些接口等一切信息。
  • 对于每个类,JRE都为其保存了一个不变的Class类型的对象,也就是说由系统建立的。
  • Person类的所有对象共享并且记得这个Class类型的对象。
User user1 = new User(); User user2 = new User(); User user3 = new User(); System.out.println(user1.hashCode()); System.out.println(user2.hashCode()); System.out.println(user3.hashCode()); /** * 输出: * 2027961269 * 1586270964 * 1642360923 */ Class c1 = user1.getClass(); Class c2 = user2.getClass(); Class c3 = user3.getClass(); System.out.println(c1.hashCode()); System.out.println(c2.hashCode()); System.out.println(c3.hashCode()); /** * 输出: * 1343441044 * 1343441044 * 1343441044 */

2. 得到Class类对象的5种方式

public class GetClassInstanceTest { public static void main(String[] args) throws ClassNotFoundException { Person person = new Student(); //法(一):通过继承object类的getClass方法 Class c1 = person.getClass(); System.out.println(c1); System.out.println(c1.hashCode()); //法(二):通过Class类的静态方法forName(类的路径),需要抛出异常 Class c2 = Class.forName("Student"); //应该是【包名.类名】,例如com.company.reflection.Student System.out.println(c2); System.out.println(c2.hashCode()); //法(三)类名.class属性 Class c3 = Student.class; System.out.println(c3); System.out.println(c3.hashCode()); //法(四):基本数据类型包装类的TYPE属性 Class c4 = Integer.TYPE; System.out.println(c4); System.out.println(c4.hashCode()); //法(五):已知子类型,获取父类型 Class c5 = c1.getSuperclass(); System.out.println(c5); System.out.println(c5.hashCode()); } } class Person{ String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } class Student extends Person{ public Student() { this.name = "学生"; } } class Teacher extends Person{ public Teacher(){ this.name="老师"; } }

对应结果:

class Student
356573597


class Student
356573597


class Student
356573597


int
1735600054


class Person
21685669

这5种方式中,只有forName是动态加载(运行时才加载,其他只要出现new了就是在编译时加载),其他都是静态加载。

5.5 哪些类可以有Class对象?

几乎所有

Class c1 = Object.class; //类 Class c2 = Comparable.class; //接口 Class c3 = String[].class; //一维数组 Class c4 = int[][].class; //二维数组 Class c5 = Override.class; //注解 Class c6 = ElementType.class; //枚举 Class c7 = Integer.class; //基本数据类型包装类 Class c8 = void.class; //void Class c9 = Class.class; //Class类本身 //------类型 getName() System.out.println(c1); // class java.lang.Object System.out.println(c2); // interface java.lang.Comparable System.out.println(c3); // class [Ljava.lang.String; System.out.println(c4); // class [[I System.out.println(c5); // interface java.lang.Override System.out.println(c6); // class java.lang.annotation.ElementType System.out.println(c7); // class java.lang.Integer System.out.println(c8); // void System.out.println(c9); // class java.lang.Class

5.6 获取类的运行时结构

在module的src文件夹下新建包:com.company.empolyee,新建User.java文件。

public class User{ //私有 private String name; private int age; //共有 public int id; public User(String name, int age, int id) { this.name = name; this.age = age; this.id = id; } 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 void laugh(){ } }
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class ClassLoaderTest { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException { Class c1 = Class.forName("com.company.empolyee.User"); //1.获取类的名字 System.out.println(c1.getName()); //包名+类型 System.out.println(c1.getSimpleName()); //只有类名 /** * 输出: * com.company.empolyee.User * User */ System.out.println("=========================="); //2.获取类所有的成员变量 //2-1.getFields只能获取public成员变量 Field[] fields = c1.getFields(); for (Field field : fields) { System.out.println(field); } /** * 输出: * public int com.company.empolyee.User.id */ //2-2.getDeclaredFields可以获取所有访问权限的成员变量 Field[] declaredFields = c1.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println(declaredField); } /** * 输出: * private java.lang.String com.company.empolyee.User.name * private int com.company.empolyee.User.age * public int com.company.empolyee.User.id */ System.out.println("========================="); //3.获取类指定的成员变量 //3-1.getField只能获取public Field id = c1.getField("id"); System.out.println(id); /** * 输出: * public int com.company.empolyee.User.id */ //3-2.getDeclaredField获取所有权限 Field name = c1.getDeclaredField("name"); System.out.println(name); /** * 输出: * private java.lang.String com.company.empolyee.User.name */ System.out.println("========================="); //4.获取类所有的成员方法 //4-1.public Method[] methods = c1.getMethods(); for (Method method : methods) { System.out.println(method); } /** * 输出:不仅输出了当前类自己定义的public成员方法,还有继承下来的所有public方法 * public java.lang.String com.company.empolyee.User.getName() * public void com.company.empolyee.User.setName(java.lang.String) * public int com.company.empolyee.User.getAge() * public void com.company.empolyee.User.setAge(int) * public final void java.lang.Object.wait() throws java.lang.InterruptedException * public final void java.lang.Object.wait(long,int) 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 java.lang.String java.lang.Object.toString() * 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() */ System.out.println("==========================="); //4-2.获取本类的所有权限的所有方法(不包括继承来的 Method[] declaredMethods = c1.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println(declaredMethod); } /** * 输出: * public java.lang.String com.company.empolyee.User.getName() * public void com.company.empolyee.User.setName(java.lang.String) * public int com.company.empolyee.User.getAge() * private void com.company.empolyee.User.haha() //私有的!! * public void com.company.empolyee.User.setAge(int) */ System.out.println("=========================="); //5.获取指定的类方法 //5-1.获取指定的public方法 一定要指定方法的参数,因为重载!! Method method = c1.getMethod("setAge", int.class); System.out.println(method); /** * public void com.company.empolyee.User.setAge(int) */ //5-2.获取指定的不限权限方法 Method laugh = c1.getDeclaredMethod("laugh", null); System.out.println(laugh); /** * private void com.company.empolyee.User.laugh() */ System.out.println("===========构造器=========="); //6.获取所有的构造器 //6-1.获取所有public构造器 Constructor[] constructors = c1.getConstructors(); for (Constructor constructor : constructors) { System.out.println(constructor); } /** * public com.company.empolyee.User(java.lang.String,int,int) */ //6-2.获取所有不限权限的构造器 Constructor[] declaredConstructors = c1.getDeclaredConstructors(); for (Constructor declaredConstructor : declaredConstructors) { System.out.println(declaredConstructors); } /** * [Ljava.lang.reflect.Constructor;@45ee12a7 */ System.out.println("==========单个的构造器========"); //7.获取指定的构造器 //7-1.获取指定的public构造器 Constructor constructor = c1.getConstructor(String.class, int.class,int.class); System.out.println(constructor); /** * public com.company.empolyee.User(java.lang.String,int,int) */ //7-2.获取指定的不限制权限的构造器 Constructor declaredConstructor = c1.getDeclaredConstructor(参数) System.out.println(declaredConstructor); } }

说明:getMethod和getDeclaredMethod方法指定方法的参数时:

  • 无参函数:null
  • int:int.class
  • String:String.class
  • ....

5.7 通过上述API获得类的信息后,怎么用呢?—— 动态创建对象、动态执行方法、动态修改属性甚至操作private成员

注意01:User类必须有显式的无参构造方法,才能用

c1.newInstance()

动态创建对象(在java中,定义有参构造器后,不会自动生成无参构造器!!!C++会自动生成)。 否则:

注意02:动态调用方法的时候,注意使用invoke(对象,方法的参数)方法激活

注意03:动态操作属性的时候,用set(对象,值)方法

注意04:操作private构造器、属性、方法的时候,由于在类外不能操作private成员。我们需要调用setAccessable(true)方法关掉安全检测。

that is to say,反射可以操作private成员!

import com.company.empolyee.User; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class ReflectCoreOperation { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException { //通过反射获取Class对象 Class c1 = Class.forName("com.company.empolyee.User"); //动态创建User对象法(一):反射出的class对象直接调用newInstance() //User user1 = (User) c1.newInstance(); //动态创建User对象法(二):利用反射出的构造器 Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class); User user2 = (User)constructor.newInstance("December", 28, 28); //动态调用User类方法 Method setName = c1.getDeclaredMethod("setName", String.class); setName.invoke(user2,"please, hang in there!"); //激活 System.out.println(user2.getName()); //动态设置属性 Field name = c1.getDeclaredField("name"); name.setAccessible(true); name.set(user2,"stick it out!"); System.out.println(user2.getName()); } }

5.8 性能测试

测试3种情况的时间长短:普通方法进行方法调用、反射方式进行方法调用、关掉安全检测的反射方式进行方法调用

import com.company.empolyee.User; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class PerformTest { //普通方式 public static void test01(){ User user = new User("December", 28, 28); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { user.getName(); } long endTime = System.currentTimeMillis(); System.out.println("普通方式10亿次:"+ (endTime-startTime)+"ms"); } //反射方式 public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { User user = new User("December", 28, 28); Class c1 = user.getClass(); Method getName = c1.getDeclaredMethod("getName", null); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { getName.invoke(user,null); } long endTime = System.currentTimeMillis(); System.out.println("反射方式10亿次:"+ (endTime-startTime)+"ms"); } //反射方式+关掉安全检测 public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { User user = new User("December", 28, 28); Class c1 = user.getClass(); Method getName = c1.getDeclaredMethod("getName", null); getName.setAccessible(true); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { getName.invoke(user,null); } long endTime = System.currentTimeMillis(); System.out.println("反射方式10亿次:"+ (endTime-startTime)+"ms"); } public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { test01(); test02(); test03(); } }

普通方式10亿次:3ms
反射方式10亿次:1530ms
反射方式10亿次:1074ms

由此看出

1)在一开始我们就说了反射的缺点是慢! 牺牲时间增加程序的灵活性!

2)对比第二个和第三个结果可以看出,关掉安全检测可以节省不少时间。如果程序频繁用到反射,可以关掉安全监测来提升效率,现在又是牺牲安全增加效率!

5.9 还能干什么?获取泛型的信息

一旦编译完成后,所有和泛型有关的信息将会被擦除。那如何获取一个类中泛型的信息呢?

因为类最初被加载的时候所有信息都存储在Class对象里,或许Class对象里保存了泛型的信息!

import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Map; public class GetGenericInfo { //成员方法的参数是泛型 public void test01(Map<String,Integer> map, List<Integer> list){ System.out.println("test01"); } //成员方法的返回值是泛型 public Map<String,Integer> test02(){ System.out.println("test02"); return null; } public static void main(String[] args) throws NoSuchMethodException { Class c1 = GetGenericInfo.class; Method method01 = c1.getDeclaredMethod("test01", Map.class, List.class); //获取泛型参数的信息 System.out.println("获取泛型参数的信息"); Type[] genericParameterTypes = method01.getGenericParameterTypes(); for (Type genericParameterType : genericParameterTypes) { System.out.println(genericParameterType); } //进一步获取泛型规定的类型 System.out.println("进一步获取泛型规定的类型"); for (Type genericParameterType : genericParameterTypes) { if(genericParameterType instanceof ParameterizedType){ //ParameterizedType:参数化类型 Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } } Method method02 = c1.getDeclaredMethod("test02", null); //获取泛型返回值的信息 System.out.println("获取泛型返回值的信息"); Type genericReturnType = method02.getGenericReturnType(); System.out.println(genericReturnType); //进一步获取泛型返回值规定的类型 System.out.println("进一步获取泛型返回值规定的类型"); if(genericReturnType instanceof ParameterizedType){ //ParameterizedType:参数化类型 Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } } }

获取泛型参数的信息
java.util.Map<java.lang.String, java.lang.Integer>
java.util.List<java.lang.Integer>
进一步获取泛型规定的类型
class java.lang.String
class java.lang.Integer
class java.lang.Integer
获取泛型返回值的信息
java.util.Map<java.lang.String, java.lang.Integer>
进一步获取泛型返回值规定的类型
class java.lang.String
class java.lang.Integer

5.10 还能干什么?获取注解信息

import java.lang.annotation.*; import java.lang.reflect.Field; public class GetAnnotationInfo { public static void main(String[] args) throws NoSuchFieldException { Class c1 = Student_Table.class; //1.获取类的注解 Annotation[] annotations = c1.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); } /** * 输出: * @TableName(value=db_stu) */ //2.获取注解value的值 TableName annotation = (TableName)c1.getAnnotation(TableName.class); System.out.println(annotation.value()); /** * 输出: * db_stu */ //3.获取字段的注解 Field name = c1.getDeclaredField("name"); TableField annotation1 = name.getAnnotation(TableField.class); //说明是哪个注解,因为一个字段可能被多个注解修饰 System.out.println(annotation1.name()); System.out.println(annotation1.type()); System.out.println(annotation1.length()); /** * 输出: * name * varchar * 3 */ } } @TableName("db_stu") class Student_Table{ @TableField(name = "name",type = "varchar",length = 3) String name; @TableField(name = "age",type = "int",length = 1) int age; @TableField(name = "age",type = "int",length = 1) int id; } /** * 数据库表名注解 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface TableName{ String value(); } /** * */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface TableField{ String name(); String type(); int length(); }
http://www.rkmt.cn/news/1509011.html

相关文章:

  • Linux用户终极指南:在Linux系统上享受完整哔哩哔哩体验的完整解决方案
  • MLflow生产级部署:Tracking Server+PostgreSQL+MinIO实战
  • 中兴Axon 9(grus)专用杜比全景声增强模块,安卓9一键刷入即用
  • 大型语言模型在学术研究中的应用与优化
  • 圆通上门取件怎么约?手把手教你省钱寄件 - 快递物流资讯
  • 聊聊专业处理股权纠纷律师事务所哪家好,靠谱推荐几家 - myqiye
  • 2026Q2兰州白铁皮风管加工厂家核心维度实地评测:甘肃排烟通风管道、甘肃消防通风设备公司、甘肃空气源热泵公司选择指南 - 优质品牌商家
  • 从Notebook到生产:机器学习模型部署实战指南
  • 2026年青砖青瓦厂家哪家靠谱?四川、陕西、新疆等地权威厂家实地对比与案例解析 - 优质品牌商家
  • 告别卡顿!详解CesiumJS 114版本中dynamicScreenSpaceError等性能优化新特性
  • n8n实现Google Forms到MongoDB端到端自动化工作流
  • 终极指南:如何免费解锁B站大会员4K画质下载完整教程
  • 2026年成都不锈钢钣金加工行业分析:如何选择质量可靠的合作供应商? - 优质品牌商家
  • Web代理安全挑战:间接提示注入攻击与MUZZLE防御框架
  • 【C语言】第5站-运算符
  • 2026年新型SMC汽车件模具行业观察:技术迭代与供应商能力深度解析 - 优质品牌商家
  • 2026年热门的上海合同纠纷律师代理有哪些 - myqiye
  • 2026年泰州GEO优化服务商选择指南:从技术落地到本地化运维的全面评估 - 优质品牌商家
  • Token Merging for Fast Stable Diffusion:一篇读懂 Stable Diffusion 的免训练加速机制
  • openclaw数字员工解决方案哪个机构专业
  • MLOps模型上线四层灰度发布与可观测性实战
  • 块状因果掩码加速LLM上下文压缩:原理与工程实践
  • 2026年,口碑好的沙盘大灯靠谱吗? - myqiye
  • TVA视觉智能体工业落地进阶实战(二十四):TVA多机视觉协同联动方案|多相机拼接视野、分布式工位时序同步、统一调度管控
  • 别再瞎调了!手把手教你用CUDA Occupancy API精准计算grid和block大小
  • UniApp小程序可动态换图、变色、响应状态的底部导航栏组件包
  • 南京AI硬件企业做GEO应该怎么选服务商?2026靠谱GEO服务商选型指南 - 企业新闻快传
  • PDF转PPTX终极指南:一键将LaTeX学术幻灯片转换为PowerPoint演示文稿
  • 南京家电企业做GEO应该怎么选服务商?2026本地靠谱GEO服务商推荐与选型指南 - 企业新闻快传
  • 北京研学机构排名:包含鸟巢水立方路线的研学机构推荐 - 品牌2026