Java中注解与反射的详细介绍
注解和反射
一、注解
什么是注解?Annotation
@Override :表示一个方法声明打算重写超类的另一个方法声明@Deprecated:表示不鼓励程序员使用这样的元素,(此注释可以用于修饰方法,属性,类)@SupperssWarnings():用来抑制编译时的警告信息"all", "unchecked", value={"unchecked","deprecation"})]
元注解
元注解的作用就是负责注解其他注解,Java定义了4个标准的meta-annotation类型,它们被用来对其他annotation类型作说明。
-
@Target:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
表示我们的注解可以用在哪些地方(字段、方法等)
-
@Retention:表示需要什么级别保存该注释信息,用于描述注解的生命周期(source源码 < class < runtime运行)
表示我们的注解在什么地方还有效
-
@Document:说明该注解将被包含在javadoc中
表示是否将我们的注解生成在javadoc中
-
@Inherited:说明子类可以继承父类中的该注解
子类可以继承父类的注解
二、反射机制
动态语言:
-
在运行时可以根据某些条件改变自身结构。如:C、C#、JavaScript、PHP、Python
静态语言:
-
在运行时结构不可改变的语言就是静态语言,如Java、C、C++
Java不是动态语言,但是Java可以称之为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制获得类似动态语言的特性。
Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期间于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
Class c = Class.forName("java.lang.String")
加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息(构造器、方法、字段、包括私有字段等)。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射
-
正常方式:引入需要的“包类”名称 ---> 通过new实例化--->取得实例化对象
-
反射方式:实例化对象--->getClass()--->取得完整的“包类”名称
Java反射机制提供的功能
-
在运行时判断任意一个对象所属的类、判断任意一个类所具有的成员变量和方法。
-
在运行时构造任意一个类的对象
-
在运行时获取泛型信息
-
在运行时调用任意一个对象的成员变量和方法
-
在运行时处理注解
-
生成动态代理
-
.......
Java反射优缺点
-
优点:可以实现动态创建对象和编译,体现出很大的灵活性。
-
缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于直接执行相同的操作。
java.lang.Class; 代表一个类java.lang.reflect.Method; 代表类的方法java.lang.reflect.Field; 代表类的成员变量java.lang.reflect.Constructor; 代表类的构造器
Class类
在Object类中定义了以下的方法,此方法将被所有子类继承
public final Class getClass()
此方法返回值的类型是一个Class类,此类是Java反射的源头,实际上所谓从程序中的运行结果来看也是很好理解,即:可以通过对象反射类的名称。

对象照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口。对于每个类而言,JRE都为其保留了Class类型的对象。一个Class对象包含了特定某个结构(class/interface/enum/annotation/primitive type/void/[])的有关信息。
-
Class本身是一个类
-
Class对象只能由系统建立对象
-
一个加载的类在JVM中只会有一个Class实例
-
一个Class对象对应的是一个加载JVM中的一个class文件
-
每个类的实例都会记得自己是由那个Class实例所生成
-
通过Class可以完整地得到一个类中的所有被加载的结构
-
Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的Class对象
Class类的常用方法

Class类中部分源码
public class Class<T> {/*** 根据类的全限定名称获取 Class 对象** @param className 类的全限定名称* @return Class 对象* @throws ClassNotFoundException 如果找不到指定名称的类*/public static Class<?> forName(String className)throws ClassNotFoundException {return Class.forNameImpl(className, false);}// 实现细节private static Class<?> forNameImpl(String name, boolean initialize)throws ClassNotFoundException {ClassLoader cl = null;try {if (cl == null) {cl = Thread.currentThread().getContextClassLoader();}return cl.loadClass(name);} catch (ClassNotFoundException e) {// 尝试使用当前类加载器cl = ClassLoader.getSystemClassLoader();return cl.loadClass(name);}}// 构造器是私有的,不允许外部直接创建 Class 对象private Class() {}// 返回类的全限定名称public native String getName();// 返回类的规范名称public String getCanonicalName() {return null; // 实际实现可能返回具体的规范名称}// 返回类的简单名称public String getSimpleName() {int lastDot = name.lastIndexOf('.');return (lastDot < 0) ? name : name.substring(lastDot + 1);}// 创建并返回此 Class 对象所表示的类的一个新实例@Deprecated(since = "9")public T newInstance() throws InstantiationException, IllegalAccessException {return getDeclaredConstructor().newInstance();}// 获取此 Class 对象所表示的类声明的所有方法public Method[] getDeclaredMethods() {Method[] result = declaredMethods;if (result == null) {// 实际实现会从类信息中获取方法// 这里简化处理result = new Method[0];}return result;}// 获取此 Class 对象所表示的类声明的所有字段public Field[] getDeclaredFields() {Field[] result = declaredFields;if (result == null) {// 实际实现会从类信息中获取字段// 这里简化处理result = new Field[0];}return result;}// 测试指定对象是否分配了此 Class 对象所表示的类或接口public boolean isInstance(Object obj) {return this.equals(obj.getClass());}// 获取此 Class 对象所表示的类的直接超类public native Class<?> getSuperclass();}
获取Class类的实例
-
若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高。
Class c1 = Person.class; -
已知某个类的实例,调用该实例的getClass()方法获取Class对象
Class c2 = person.getClass(); -
已知一个类的全类名,且该类在类路径下,可以通过Class类的静态方法forName()获取,可能会抛出ClassNotFoundException
Class c3 = Class.forName("Deom1.Student"); -
基本内置数据类型的包装类都有一个Type属性
Class c4 = Integer.Type; -
还可以利用ClassLoader
哪些类型可以有Class对象
-
class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类。
-
Interface:接口
-
[]:数组
-
enum:枚举
-
annotation:注解@interface
-
primitive type:基本数据类型
-
void
package com.briup.chap13;import java.lang.annotation.ElementType;/*** @author 35329*/public class Test04 {public static void main(String[] args) {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;// voidClass c9 = Class.class;// ClassSystem.out.println("c1 = " + c1);System.out.println("c2 = " + c2);System.out.println("c3 = " + c3);System.out.println("c4 = " + c4);System.out.println("c5 = " + c5);System.out.println("c6 = " + c6);System.out.println("c7 = " + c7);System.out.println("c8 = " + c8);System.out.println("c9 = " + c9);// 只要元素类型与维度一样,就是同一个Classint[] a = new int[10];int[] b = new int[100];System.out.println("a.getClass().hashCode() = " + a.getClass().hashCode());System.out.println("b.getClass().hashCode() = " + b.getClass().hashCode());// 运行结果://c1 = class java.lang.Object//c2 = interface java.lang.Comparable//c3 = class [Ljava.lang.String;//c4 = class [[I//c5 = interface java.lang.Override//c6 = class java.lang.annotation.ElementType//c7 = class java.lang.Integer//c8 = void//c9 = class java.lang.Class//a.getClass().hashCode() = 21685669//b.getClass().hashCode() = 21685669}}
类加载内存分析:

类的加载过程:

-
加载:将class文件字节码内容加载到内存中,并将这些静态数据转化成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象。
-
链接:将Java类的二进制代码合并到JVM的运行状态之中的过程。
-
验证:确保加载的类信息符合JVM规范,没有安全方面的问题。
-
准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法去中进行分配。
-
解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。
-
-
初始化:
-
执行类构造器<clinit>()方法的过程,类构造器<clinit>()方法是由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造该类对象的构造器)。
-
当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化。
-
虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确加锁和同步。
-
package com.briup.chap13;/*** @author 35329*/public class Test05 {public static void main(String[] args) {A a = new A();System.out.println(A.m);/*** 1、加载到内存,会产生一个类对应Class对象* 2、链接,链接结束后 m = 0;* 3、初始化* <clinit>(){* System.out.println("A类静态代码块初始化");* m = 300;* m = 100;* }* m = 100;*/}}class A{static {System.out.println("A类静态代码块初始化");m = 300;}static int m = 100;/** m = 300* m = 100* 后面的会覆盖前面的* */public A(){System.out.println("A类的无参构造初始化");}}// 运行结果://A类静态代码块初始化//A类的无参构造初始化//100
什么时候会发生类初始化
-
类的主动引用(一定会发生类的初始化)重点
-
当虚拟机启动,先初始化main方法所在的类
-
new一个类的对象
-
调用类的静态成员(除了final常量)和静态方法
-
使用java.lang.reflect包的方法对类进行反射调用
-
当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类
-
-
类的被动引用(不会发生类的初始化)
-
当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化。
-
通过数组定义类引用,不会触发此类的初始化
-
引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)
-
package com.briup.chap13;/*** @author 35329*/// 测试类什么时候会初始化public class Test06 {static {System.out.println("mian类被加载");}public static void main(String[] args) throws ClassNotFoundException {// 1、主动被加载// Son son = new Son();// 反射也会产生主动引用// Class.forName("com.briup.chap13.Son");// 不会产生类的引用的方法// System.out.println("Son.b = " + Son.b);// Son[] arr = new Son[5];System.out.println("Son.M = " + Son.M);}}class Father{static int b = 2;static {System.out.println("父类被加载");}}class Son extends Father{static {System.out.println("子类被加载");m = 300;}static int m = 100;static final int M = 1;}
类加载器的作用:
类加载器的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。
类缓存:标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象。

类加载器作用是用来把类(class)装载进内存的。JVM规范定义了如下类型的类的加载器。
-
引导类加载器:用C++编写,是JVM自带的类加载器,负责Java平台核心库,用来装载核心类库。该加载器无法直接获取。
-
扩展类加载器:负责
jre/lib/ext目录下的jar包或-D java.ext.dirs指定目录下的jar包装入工作库 -
系统类加载器:负责
java -classpath 或 -D java.class.path所指的目录下的类与jar包装入工作,是最常用的加载器。
package com.briup.chap13;import com.briup.chap07.test.bean.Cat;/*** @author 35329*/public class Test07 {public static void main(String[] args) throws ClassNotFoundException {// 获取系统类的加载器ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();System.out.println("systemClassLoader = " + systemClassLoader);// 获取系统类加载器的父类加载器 --> 扩展类加载器ClassLoader parent = systemClassLoader.getParent();System.out.println("parent = " + parent);// 获取扩展类加载器 --> 根加载器(C/c++)ClassLoader parent1 = parent.getParent();System.out.println("parent1 = " + parent1);// 运行结果://systemClassLoader = sun.misc.Launcher$AppClassLoader@18b4aac2//parent = sun.misc.Launcher$ExtClassLoader@14ae5a5//parent1 = null// 测试当前类是那个加载器加载的ClassLoader classLoader = Class.forName("com.briup.chap13.Test07").getClassLoader();System.out.println("classLoader = " + classLoader);// 测试JDK内置的类是谁加载的System.out.println("Class.forName(\"java.lang.Object\").getClassLoader() = " + Class.forName("java.lang.Object").getClassLoader());// 运行结果://classLoader = sun.misc.Launcher$AppClassLoader@18b4aac2//Class.forName("java.lang.Object").getClassLoader() = null// 如何获得系统类加载器可以加载的路径System.out.println(System.getProperty("java.class.path"));// 运行结果:/** C:\Program Files\Java\jdk1.8.0_144\jre\lib\charsets.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\deploy.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\access-bridge-64.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\cldrdata.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\dnsns.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\jaccess.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\jfxrt.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\localedata.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\nashorn.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunec.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunjce_provider.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunmscapi.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunpkcs11.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\zipfs.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\javaws.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\jce.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\jfr.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\jfxswt.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\jsse.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\management-agent.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\plugin.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\resources.jar;* C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar;* D:\JDProject\corejava\out\production\corejava;* C:\Users\35329\.m2\repository\junit\junit\4.12\junit-4.12.jar;* C:\Users\35329\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;* D:\idea\ideaIU-2020\lib\idea_rt.jar* */}}
获取运行时类的完整结构
通过反射获取运行时类的完整结构
Field、Method、Constructor、Superclass、Interface、Annotation
package com.briup.chap13;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;/*** 通过反射获得类的信息* @author 35329*/public class Test08 {public static void main(String[] args) throws Exception {Class c1 = Class.forName("com.briup.chap13.user");// 获得类的名字System.out.println("c1.getName() = " + c1.getName()); // 获得包名 + 类名System.out.println("c1.getSimpleName() = " + c1.getSimpleName()); // 获得类名System.out.println("-----------------------------------");// 获得类的属性Field[] fields = c1.getFields(); // 只能找到public属性fields = c1.getDeclaredFields(); // 可以找到全部属性for (Field field : fields) {System.out.println(field);}// 获得指定属性的值Field name = c1.getDeclaredField("name");System.out.println("name = " + name);System.out.println("-----------------------------------------");// 获得类的方法Method[] methods = c1.getMethods(); // 获得本类及其父类的全部public方法for (Method method : methods) {System.out.println("正常的:" + method);}Method[] declaredMethods = c1.getDeclaredMethods(); // 获得本类的所有方法(包括私有的)for (Method declaredMethod : declaredMethods) {System.out.println(declaredMethod);}// 获得指定方法// 重载Method getName = c1.getMethod("getName", null);Method setName = c1.getMethod("setName", String.class);System.out.println("getName = " + getName);System.out.println("setName = " + setName);System.out.println("--------------------------------");// 获得类的构造器Constructor[] constructors = c1.getConstructors(); // 获得public修饰的构造方法for (Constructor constructor : constructors) {System.out.println(constructor);}constructors = c1.getDeclaredConstructors();// 获得全部构造方法for (Constructor constructor : constructors) {System.out.println("#" + constructor);}//获得指定的构造器Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);System.out.println("指定构造器:" + declaredConstructor);}}
小结:
-
在实际操作中,取得类的信息的操作代码,不会经常开发。
-
一定要熟悉java.lang.reflect包的作用,反射机制。
-
如何取得属性、方法、构造器的名称,修饰符等。
有了Class对象,能做什么?
创建一个类的对象:调用Class对象的newInstance()方法
-
类必须有一个无参数的构造器
-
类的构造器的访问权限需要足够
思考?难道没有无参的构造器就不能创建对象了吗?只要在操作的时候明确的调用类中的构造器,并将参数传递进去之后,才可以实例化操作。
步骤如下:
-
通过Class类的getDeclaredConstructor(Class ... parameterTypes)取得本类的指定形参类型的构造器。
-
向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。
-
通过Constructor实例化对象。
通过指定的方法
通过反射,调用类中的方法,通过Method类完成
-
通过Class类的getMethod(String name, Class ... parameter Types)方法取得一个Method对象,并设置此方法操作时所需要的参数类型。
-
之后使用Object invoke(Object obj, Object[] args)进行调用,并向方法中传递要设置的obj对象的参数信息。
Object invoke(Object obj, Object ...args)
-
Object对应原方法的返回值,若原方法无返回值,此时返回null
-
若原方法为静态方法,此时形参Object obj可为null
-
若原方法形参列表为空,则Object[] args为null
-
若原方法声明为private,则需要在调用此invoke()方法前,显示调用方法对象的setAccessible(true)方法,将可访问private修饰的方法。
setAccessible
-
Method和Field、Constructor对象都有setAccessible()方法
-
setAccessible()作用是启示和禁用访问安全检查的开关
-
参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。
-
提高反射的效率,如果代码中必须用反射,而该句代码需要频繁的被调用,那么请设置为true
-
使得原本无法访问的私有成员也可以访问
-
-
参数值为false则指示反射的对象应该实施Java语言访问检查。
package com.briup.chap13;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.Map;/*** 分析性能问题* @author 35329*/public class Test10 {// 通过普通方法调用public static void test01(){user user = new user();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();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();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();}}
反射操作泛型(了解即可)
-
Java采用泛型擦除的机制来引入泛型,Java中的泛型仅仅是给编译器javac使用的确保数据的安全性和免去强制类型转换问题,但是,一旦编译完成,所有和泛型有关的类型全部擦除。
-
为了通过反射操作这些类型,Java新增了
ParameterizedType、GenericArrayType、TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型。 -
ParameterizedType:表示一种参数化类型,比如Collection<String> -
GenericArrayType:表示一种元素类型的参数化类型或者类型变量的数组类型 -
TypeVariable:是各种类型变量的公共接口 -
WildcardType:代表一种通配符类型表达式
反射操作注解
练习:什么是ORM?
-
Object relationship Mapping -->对象关系映射
类和表结构的映射关系
-
类和表结构对应
-
属性和字段对应
-
对象和记录对应
package com.briup.chap13;import java.lang.annotation.*;import java.lang.reflect.Field;/*** 练习反射操作注解* @author 35329*/public class Test12 {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {Class<?> c1 = Class.forName("com.briup.chap13.Student2");// 通过反射获取注解Annotation[] annotations = c1.getAnnotations();for (Annotation annotation : annotations) {System.out.println(annotation);}// 获得注解的Value值TableBriup tableBriup = c1.getAnnotation(TableBriup.class);String value = tableBriup.value();System.out.println(value);// 获得类指定的注解Field f = c1.getDeclaredField("name");FieldBriup annotation = f.getAnnotation(FieldBriup.class);System.out.println(annotation.columnName());System.out.println(annotation.type());System.out.println(annotation.length());}}@TableBriup("db_student")class Student2{@FieldBriup(columnName = "db_id", type = "int", length = 10)private int id;@FieldBriup(columnName = "db_age", type = "int", length = 10)private int age;@FieldBriup(columnName = "db_name", type = "varchar", length = 3)private String name;public Student2() {}public Student2(int id, int age, String name) {this.id = id;this.age = age;this.name = name;}@Overridepublic String toString() {return "Test12{" +"id=" + id +", age=" + age +", name='" + name + '\'' +'}';}public int getId() {return id;}public void setId(int id) {this.id = id;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}}// 类名注解@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@interface TableBriup{String value();}// 属性的注解@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@interface FieldBriup{String columnName();String type();int length();}
相关文章:
Java中注解与反射的详细介绍
注解和反射 一、注解 什么是注解?Annotation Override :表示一个方法声明打算重写超类的另一个方法声明Deprecated:表示不鼓励程序员使用这样的元素,(此注释可以用于修饰方法,属性,类…...
Redis 过期时间删除策略详解
在使用 Redis 时,设置键的过期时间是一项非常有用的功能。它可以帮助我们自动清理不再需要的数据,节省内存空间。那么,Redis 是如何处理这些带有过期时间的键呢?这就涉及到 Redis 的过期时间删除策略。 一、Redis 过期键的判定 R…...
C语言_内存函数
内存函数是 C 标准库中的一组函数,用于管理和操作内存。使用时需要包含头文件<string.h>。 1. memcpy的使用和模拟实现 函数形式如下: void* memcpy(void* destination, const void* source, size_tnum);函数解析和注意事项: memcp…...
基于s32ds平台指定变量储存位置
开启一段ram空间 打开ld文件 配置一段ram空间 开辟一个段 .shareable_data1 : {. ALIGN(4);KEEP(*(.mcal_shared_data1)) . ALIGN(4);} > int_sram_shareable1定义一个变量并将变量指定在段中 volatile uint32 u32SbcmGenState __attribute__((section (".mcal_s…...
什么是快充协议、支持多协议的USB Type-C受电端取电芯片
随着快充技术的不断发展,传统的慢充模式已经满足不了消费者对充电效率的要求。有了快充技术的支持很大程度的缩短了我们的充电时间,给我们的生活带来了很多便利。 什么是快充协议 快充协议是快充技术的核心,现如今市面上已经有很多种快充协议…...
在Vue CLI项目中使用ECharts:详细指南
在Vue CLI项目中使用ECharts:详细指南 ECharts 是一款由百度开源的数据可视化图表库,它提供了丰富的图表类型和高度的可定制性。在Vue CLI项目中集成ECharts,可以帮助我们快速地将数据以图形的方式展示给用户。以下是在Vue CLI项目中使用ECh…...
第二阶段:mysql(学完就隐藏版)
第一章:部署数据库系统(注意关闭防火墙,selinux安装) 安装mysql配置的相关文件:yum install https://dev.mysql.com/get/mysql80-community-release-el7-5.noarch.rpm(centos9:yum install http…...
Spring Cloud微服务
引言 在过去的几十年中,软件架构的发展经历了从单体应用到微服务的演变。微服务架构是一种将应用程序分解为小的、独立的服务的方法,每个服务可以独立地部署和扩展。Spring Cloud为开发和部署基于Spring的微服务提供了一系列的工具和框架,使…...
后端复习资料
后端面试资料 语雀-图灵面试题 语雀-javaGuide 小林coding:https://www.xiaolincoding.com/ 面试鸭: https://www.mianshiya.com/ codehot香菜哥:https://codehot.cn/markdown/welfare 面试题: vizard自行整理 牛客Golang社招面…...
C++和OpenGL实现3D游戏编程【连载14】——VBO、VAO和EBO应用
🔥C和OpenGL实现3D游戏编程【目录】 1、本节实现的内容 我们从一开始学OpenGL到现在,OpenGL的图形绘图必须在glBegin()和glEnd()函数之间完成,在此基础之上,才能进行后续操作功能。但是我们今天要讨论一下OpenGL图形绘制的模式&a…...
AI + 智能互助平台(一点杂想)
随着人工智能的火爆,各种AI产品的兴起,我发现在解决人们日常需求的AI工具还是比较少的,还是比较依赖上一代的搜索功能。 是不是可以有这样的一款产品,需求方在平台上发布需求,提供方在平台上发布能力,AI自动…...
其他浏览器可以联网,但edge不能联网
问题描述: 今早edge无法上网,检测网络连接正常,而且其他chrome,Firefox和360浏览器都可以上网。 解决方案: 注意:为防止是代理问题,可以在扩展中禁用后再试试 如果没有代理或者禁用代理也不…...
Redis 缓存淘汰策略:LRU 和 LFU 的缺点及解决方案详解
引言 Redis 是一款高性能的内存数据库,它的缓存淘汰机制是保障内存使用效率和应用性能的关键。为了在内存有限的情况下保证缓存数据的有效性,Redis 提供了多种缓存淘汰策略,其中 LRU(Least Recently Used,最近最少使用…...
软件工程pipeline梳理
文章目录 软件工程pipeline梳理为什么需要梳理软件工程的pipeline软件工程pipeline的概念与注意点软件工程pipeline中的最大挑战rethink相关资料 软件工程pipeline梳理 为什么需要梳理软件工程的pipeline 反思自己日常工作中的认知和行为。以算法/软件工程师为代表的技术工种往…...
npm运行时出现npm ERR! builtins is not a function报错!
项目场景: 项目运行时什么都没动都没改突然运行不起来了,报错 TypeError: builtins is not a function 代码什么都没动,不是代码问题,排查后只有可能是node和npm的问题,所以卸载掉node重装重启 解决方案: …...
2024年软件设计师中级(软考中级)详细笔记【5】软件工程基础知识上(分值10+)
第5章软件工程 目录 前言第5章 软件工程基础知识(上)(分值10)5.1 软件工程概述5.1.4 软件过程 5.2 软件过程模型5.2.1 瀑布模型 (Waterfall Model)5.2.2 增量模型5.2.3 演化模型5.2.4 喷泉模型(Water Fountain Model&a…...
C++:vector(题目篇)
文章目录 前言一、只出现一次的数字二、只出现一次的数字 II三、只出现一次的数字 III四、杨辉三角五、删除有序数组中的重复项六、数组中出现次数超过一半的数字七、电话号码的字母组合总结 前言 今天我们一起来看vector相关的题目~ 一、只出现一次的数字 只出现一次的数字…...
JS 怎么监听复制事件 并获取复制内容 并修改复制文本内容
需求背景: 需要禁用部分文本内容的复制事件,并且在复制事件发生时,将复制的文本内容通过接口传给后端。 上代码: // 使用Dom获取需要操作禁用时间的元素let element: any document.getElementById(test1);// 为该元素添加 copy 事…...
安卓使用.9图实现阴影效果box-shadow: 0 2px 6px 1px rgba(0,0,0,0.08);
1.安卓实现阴影效果有很多种,一般UX设计会给以H5参数box-shadow: 0 2px 6px 1px rgba(0,0,0,0.08);这种方式提供背景阴影效果,这里记录一下实现过程 2.界面xml源码 <?xml version"1.0" encoding"utf-8"?> <layout xmlns…...
CSS3-Day1
CSS3圆角 border-radius CSS3盒阴影 box-shadow CSS3边界图片 border-image CSS3 background-clip属性 padding-box 沿着边框填充 content-box 在边框外面 CSS3 线性渐变 线性渐变 - 从上到下(默认情况下)#grad { background-image: linear…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...
