Java注解以及自定义注解

Java注解以及自定义注解

要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为

我们提供的元注解和相关定义注解的语法。

1、注解

1.1 注解的官方定义

注解是一种元数据形式。即注解是属于java的一种数据类型,和类、接口、数组、枚举类似。

注解用来修饰,类、方法、变量、参数、包。

注解不会对所修饰的代码产生直接的影响。

1.2 注解的使用范围

注解有许多用法,其中有:为编译器提供信息 - 注解能被编译器检测到错误或抑制警告。编译时和部署时的处理 -

软件工具能处理注解信息从而生成代码,XML文件等等。运行时的处理 - 有些注解在运行时能被检测到。

2、元注解

一个最最基本的注解定义就只包括了两部分内容:1、注解的名字;2、注解包含的类型元素。但是,我们在使用

JDK自带注解的时候发现,有些注解只能写在方法上面(比如@Override);有些却可以写在类的上面(比如

@Deprecated)。当然除此以外还有很多细节性的定义,那么这些定义该如何做呢?接下来就该元注解出场了!

元注解:专门修饰注解的注解。它们都是为了更好的设计自定义注解的细节而专门设计的。Java5.0定义了4个标准

的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。

Java5.0 定义的元注解:

1、@Target

2、@Retention

3、@Documented

4、@Inherited

这些类型和它们所支持的类在java.lang.annotation包中可以找到。下面我们看一下每个元注解的作用和相应

分参数的使用说明。

2.1 @Target

@Target注解,是专门用来限定某个自定义注解能够被应用在哪些Java元素上面的。

@Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、

Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、

catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

作用:用于描述注解的使用范围(即被描述的注解可以用在什么地方)

取值(ElementType)有:

1、CONSTRUCTOR:用于描述构造器

2、FIELD:用于描述域

3、LOCAL_VARIABLE:用于描述局部变量

4、METHOD:用于描述方法

5、PACKAGE:用于描述包

6、PARAMETER:用于描述参数

7、TYPE:用于描述类、接口(包括注解类型) 或enum声明

它使用一个枚举类型定义如下:

public enum ElementType {/** 类,接口(包括注解类型)或枚举的声明 */TYPE,/** 属性的声明 */FIELD,/** 方法的声明 */METHOD,/** 方法形式参数声明 */PARAMETER,/** 构造方法的声明 */CONSTRUCTOR,/** 局部变量声明 */LOCAL_VARIABLE,/** 注解类型声明 */ANNOTATION_TYPE,/** 包的声明 */PACKAGE,TYPE_PARAMETER,TYPE_USE
}

使用实例:

package com.test3;import java.lang.annotation.ElementType;
import java.lang.annotation.Target;@Target(ElementType.TYPE)
public @interface Table {/*** 数据表名称注解,默认值为类名称* @return*/public String tableName() default "className";
}
package com.test3;import java.lang.annotation.ElementType;
import java.lang.annotation.Target;@Target(ElementType.FIELD)
public @interface NoDBColumn {
}
package com.test3;import java.lang.annotation.ElementType;
import java.lang.annotation.Target;//@CherryAnnotation被限定只能使用在类、接口或方法上面
@Target(value = {ElementType.TYPE, ElementType.METHOD})
public @interface CherryAnnotation {String name();int age() default 18;int[] array();
}

注解Table可以用于注解类、接口(包括注解类型) 或enum声明,而注解NoDBColumn仅可用于注解类的成员变

量。

2.2 @Retention

@Retention注解,翻译为持久力、保持力。即用来修饰自定义注解的生命力。

注解的生命周期有三个阶段:1、Java源文件阶段;2、编译到class文件阶段;3、运行期阶段。同样使用了

RetentionPolicy 枚举类型定义了三个阶段:

作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即被描述的注解在什么范围内有效)

取值(RetentionPoicy)有:

1、SOURCE:在源文件中有效(即源文件保留)

2、CLASS:在class文件中有效(即class保留)

3、RUNTIME:在运行时有效(即运行时保留)

Retention meta-annotation类型有唯一的value作为成员,它的取值来自

java.lang.annotation.RetentionPolicy的枚举类型值。

public enum RetentionPolicy {// 注解将被编译器忽略掉SOURCE,// 注解将被编译器记录在class文件中,但在运行时不会被虚拟机保留,这是一个默认的行为CLASS,// 注解将被编译器记录在class文件中,而且在运行时会被虚拟机保留,因此它们能通过反射被读取到RUNTIME
}

我们再详解一下:

如果一个注解被定义为RetentionPolicy.SOURCE,则它将被限定在Java源文件中,那么这个注解即不会参与编

译也不会在运行期起任何作用,这个注解就和一个注释是一样的效果,只能被阅读Java文件的人看到;

如果一个注解被定义为RetentionPolicy.CLASS,则它将被编译到Class文件中,那么编译器可以在编译时根据

注解做一些处理动作,但是运行时JVM(Java虚拟机)会忽略它,我们在运行期也不能读取到;

如果一个注解被定义为RetentionPolicy.RUNTIME,那么这个注解可以在运行期的加载阶段被加载到Class对象

中。那么在程序运行阶段,我们可以通过反射得到这个注解,并通过判断是否有这个注解或这个注解中属性的值,

从而执行不同的程序代码段。我们实际开发中的自定义注解几乎都是使用的RetentionPolicy.RUNTIME;在默认

的情况下,自定义注解是使用的RetentionPolicy.CLASS

具体实例如下:

package com.test3;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {public String name() default "fieldName";public String setFuncName() default "setField";public String getFuncName() default "getField";public boolean defaultDBValue() default false;
}

Column注解的的RetentionPolicy的属性值是RUNTIME,这样注解处理器可以通过反射,获取到该注解的属性

值,从而去做一些运行时的逻辑处理。

2.3 @Documented

@Documented注解,是被用来指定自定义注解是否能随着被定义的java文件生成到JavaDoc文档当中,因此可以

被例如javadoc此类的工具文档化。

Documented是一个标记注解,没有成员。

package com.test3;import java.lang.annotation.*;@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Column1 {public String name() default "fieldName";public String setFuncName() default "setField";public String getFuncName() default "getField";public boolean defaultDBValue() default false;
}

2.4 @Inherited

@Inherited注解,是指定某个自定义注解如果写在了父类的声明部分,那么子类的声明部分也能自动拥有该注

解。@Inherited注解只对那些@Target被定义为ElementType.TYPE的自定义注解起作用。

@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了

@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,

方法并不从它所重载的方法继承annotation。

当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这

种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查

将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。

实例代码:

package com.test3;import java.lang.annotation.Inherited;@Inherited
public @interface Greeting {public enum FontColor {BULE, RED, GREEN};String name();FontColor fontColor() default FontColor.GREEN;
}

注解的继承依赖如下一个因素:

1、首先要想Annotation能被继承,需要在注解定义的时候加上@Inherited,并且如果要被反射应用的话,还

需要@Retention(RetentionPolicy.RUNTIME)标识。

2、JDK文档中说明的是:只有在类上应用Annotation才能被继承,而实际应用结果是:除了类上应用的

Annotation能被继承外,没有被重写的方法的Annotation也能被继承。

3、当方法被重写后,Annotation不会被继承。

4、Annotation的继承不能应用在接口上。

3、自定义注解

使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细

节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声

明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、

Class、String、enum)。可以通过default来声明参数的默认值。

3.1 定义注解格式

public @interface 注解名 {定义体}
public @interface CherryAnnotation {
}

根据我们在自定义类的经验,在类的实现部分无非就是书写构造、属性或方法。但是,在自定义注解中,其实现

只能定义一个东西:注解类型元素(annotation type element)。语法:

public @interface CherryAnnotation {public String name();public int age();public int[] array();
}
public @interface CherryAnnotation {public String name();public int age() default 18;public int[] array();
}

3.2 注解参数的可支持数据类型

1、所有基本数据类型(int,float,boolean,byte,double,char,long,short)

2、String类型

3、Class类型

4、enum类型

5、Annotation类型

6、以上所有类型的数组

注解里面定义的是:注解类型元素!

3.3 定义注解类型元素时需要注意如下几点

1、只能用public或默认(default)这两个访问权修饰,例如String value();这里把方法设为default默认类型。

2、参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,

Enum,Class,annotations等数据类型,以及这一些类型的数组。

3、如果只有一个参数成员,最好把参数名称设为value,后加小括号。

4、()不是定义方法参数的地方,也不能在括号中定义任何参数,仅仅只是一个特殊的语法。

5、default代表默认值,值必须和第2点定义的类型一致。

6、如果没有默认值,代表后续使用注解时必须给该类型元素赋值。

可以看出,注解类型元素的语法非常奇怪,即又有属性的特征(可以赋值),又有方法的特征(打上了一对括

号)。但是这么设计是有道理的,我们在后面的章节中可以看到:注解在定义好了以后,使用的时候操作元素类型

像在操作属性,解析的时候操作元素类型像在操作方法。

3.4 简单的自定义注解和使用注解实例

package com.test;import java.lang.annotation.*;/*** 水果名称注解*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {String value() default "";
}
package com.test;import java.lang.annotation.*;/*** 水果颜色注解*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {/*** 颜色枚举*/public enum Color {BULE, RED, GREEN};/*** 颜色属性** @return*/Color fruitColor() default Color.GREEN;}
package com.test;public class Apple {@FruitName("Apple")private String appleName;@FruitColor(fruitColor = FruitColor.Color.RED)private String appleColor;public void setAppleColor(String appleColor) {this.appleColor = appleColor;}public String getAppleColor() {return appleColor;}public void setAppleName(String appleName) {this.appleName = appleName;}public String getAppleName() {return appleName;}
}

3.5 注解元素的默认值

注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值

不可为null。因此,使用空字符串或0作为默认值是一种常用的做法。这个约束使得处理器很难表现一个元素的存

在或缺失的状态,因为每个注解的声明中,所有元素都存在,并且都具有相应的值,为了绕开这个约束,我们只能

定义一些特殊的值,例如空字符串或者负数,一次表示某个元素不存在,在定义注解时,这已经成为一个习惯用

法。

package com.test;import java.lang.annotation.*;/*** 水果供应者注解*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitProvider {/*** 供应商编号** @return*/public int id() default -1;/*** 供应商名称** @return*/public String name() default "";/*** 供应商地址** @return*/public String address() default "";
}

3.6 特殊语法

特殊语法一

如果注解本身没有注解类型元素,那么在使用注解的时候可以省略(),直接写为:@注解名,它和标准语法

@注解名()等效!

@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
@Documented
public @interface FirstAnnotation {
}
//等效于 @FirstAnnotation()
@FirstAnnotation
public class JavaBean{
}

特殊语法二

如果注解本身只有一个注解类型元素,而且命名为value,那么在使用注解的时候可以直接使用:

@注解名(注解值),其等效于:@注解名(value = 注解值)

@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
@Documented
public @interface SecondAnnotation {String value();
}
//等效于 @SecondAnnotation(value = "this is second annotation")
@SecondAnnotation("this is annotation")
public class JavaBean{
}

特殊用法三

如果注解中的某个注解类型元素是一个数组类型,在使用时又出现只需要填入一个值的情况,那么在使用注解时可

直接写为:@注解名(类型名 = 类型值),它和标准写法:@注解名(类型名 = {类型值})等效!

@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
@Documented
public @interface ThirdAnnotation {String[] name();
}
//等效于 @ThirdAnnotation(name = {"this is third annotation"})
@ ThirdAnnotation(name = "this is third annotation")
public class JavaBean{
}

特殊用法四

如果一个注解的@Target是定义为Element.PACKAGE,那么这个注解是配置在package-info.java中的,而不能

直接在某个类的package代码上面配置。

上面三节定义了注解,并在需要的时候给相关类,类属性加上注解信息,如果没有响应的注解信息处理流程,注解

可以说是没有实用价值。如何让注解真真的发挥作用,主要就在于注解处理方法,下一步我们将学习注解信息的获

取和处理!

4、自定义注解的配置使用

基于上一节,已对注解有了一个基本的认识:注解其实就是一种标记,可以在程序代码中的关键节点(类、方法、

变量、参数、包)上打上这些标记,然后程序在编译时或运行时可以检测到这些标记从而执行一些特殊操作。因此

可以得出自定义注解使用的基本流程:

第一步,定义注解——相当于定义标记;

第二步,配置注解——把标记打在需要用到的程序代码中;

第三步,解析注解——在编译期或运行时检测到标记,并进行特殊操作。

在这里插入图片描述

4.1 在具体的Java类上使用注解

首先,定义一个注解和一个供注解修饰的简单Java类。

package com.test1;import java.lang.annotation.*;@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD})
@Documented
public @interface CherryAnnotation {String name();// 类型元素int age() default 18;int[] score();
}
package com.test1;public class Student {public void study(int times) {for (int i = 0; i < times; i++) {System.out.println("Good Good Study, Day Day Up!");}}
}

简单分析下:

CherryAnnotation的@Target定义为ElementType.METHOD,那么它书写的位置应该在方法定义的上方,即:

public void study(int times)之上。由于我们在CherryAnnotation中定义的有注解类型元素,而且有些元素是没有

默认值的,这要求我们在使用的时候必须在标记名后面打上(),并且在()内以“元素名=元素值“的形式挨个填上所有

没有默认值的注解类型元素(有默认值的也可以填上重新赋值),中间用“,”号分割。

所以最终书写形式如下:

package com.test1;public class Student {@CherryAnnotation(name = "cherry-peng", age = 23, score = {99, 66, 77})public void study(int times) {for (int i = 0; i < times; i++) {System.out.println("Good Good Study, Day Day Up!");}}
}

4.2 自定义注解的运行时解析(反射操作获取注解)

这一节是使用注解的核心,读完此节即可明白,如何在程序运行时检测到注解,并进行一系列特殊操作!

只有当注解的保持力处于运行阶段,即使用@Retention(RetentionPolicy.RUNTIME)修饰注解时,才能在JVM

运行时,检测到注解,并进行一系列特殊操作。

在运行期探究和使用编译期的内容(编译期配置的注解),要用到Java中的灵魂技术——反射!

Java SE5扩展了反射机制的API,以帮助程序员快速的构造自定义注解处理器。

package com.test1;import java.lang.reflect.Method;/*** @author zhangshixing* @date 2021年11月01日 9:32*/
public class TestAnnotation {public static void main(String[] args){try {//获取Student的Class对象Class stuClass = Class.forName("com.test1.Student");//说明一下,这里形参不能写成Integer.class,应写为int.classMethod stuMethod = stuClass.getMethod("study",int.class);if(stuMethod.isAnnotationPresent(CherryAnnotation.class)){System.out.println("Student类上配置了CherryAnnotation注解!");//获取该元素上指定类型的注解CherryAnnotation cherryAnnotation = stuMethod.getAnnotation(CherryAnnotation.class);System.out.println("name: " + cherryAnnotation.name() + ", age: " + cherryAnnotation.age()+ ", score: " + cherryAnnotation.score()[0]);}else{System.out.println("Student类上没有配置CherryAnnotation注解!");}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();}}
}
# 程序输出
Student类上配置了CherryAnnotation注解!
name: cherry-peng, age: 23, score: 99

4.3 注解处理器类库(java.lang.reflect.AnnotatedElement)

Java使用Annotation接口来代表程序元素前面的注解,该接口是所有Annotation类型的父接口。除此之外,Java

java.lang.reflect 包下新增了AnnotatedElement接口,该接口代表程序中可以接受注解的程序元素,该接

口主要有如下几个实现类:

Class:类定义

Constructor:构造器定义

Field:类的成员变量定义

Method:类的方法定义

Package:类的包定义

java.lang.reflect包下主要包含一些实现反射功能的工具类,实际上,java.lang.reflect 包所有提供的反射API

扩充了读取运行时Annotation信息的能力。当一个Annotation类型被定义为运行时的Annotation后,该注解才能

是运行时可见,当class文件被装载时被保存在class文件中的Annotation才会被虚拟机读取。

AnnotatedElement 接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通过反射获取了

某个类的AnnotatedElement对象之后,程序就可以调用该对象的如下四个个方法来访问Annotation信息:

isAnnotationPresent(Class<? extends Annotation> annotationClass)方法是专门判断该元素上是否配

置有某个指定的注解;

getAnnotation(Class<A> annotationClass)方法是获取该元素上指定的注解。之后再调用该注解的注解类型

元素方法就可以获得配置时的值数据;如果该类型注解不存在,则返回null。

反射对象上还有一个方法getAnnotations(),该方法可以获得该对象身上配置的所有的注解。它会返回给我们

一个注解数组,需要注意的是该数组的类型是Annotation类型,这个Annotation是一个来自于

java.lang.annotation包的接口。

Annotation[] getDeclaredAnnotations():返回直接存在于此元素上的所有注解。与此接口中的其他方法不

同,该方法将忽略继承的注解。(如果没有注解直接存在于此元素上,则返回长度为零的一个数组)。该方法的调

用者可以随意修改返回的数组;这不会对其它调用者返回的数组产生任何影响。

如果我们要获得的注解是配置在方法上的,那么我们要从Method对象上获取;如果是配置在属性上,就需要从该

属性对应的Field对象上去获取,如果是配置在类型上,需要从Class对象上去获取。总之在谁身上,就从谁身上去

获取!

一个简单的注解处理器

/***********注解声明***************/package com.test2;import java.lang.annotation.*;/*** 水果名称注解*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {String value() default "";
}
package com.test2;import java.lang.annotation.*;/*** 水果颜色注解*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {/*** 颜色枚举** @author peida*/public enum Color {BULE, RED, GREEN};/*** 颜色属性** @return*/Color fruitColor() default Color.GREEN;}
package com.test2;import java.lang.annotation.*;/*** 水果供应者注解*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitProvider {/*** 供应商编号** @return*/public int id() default -1;/*** 供应商名称** @return*/public String name() default "";/*** 供应商地址** @return*/public String address() default "";
}
/***********注解使用***************/package com.test2;public class Apple {@FruitName("Apple")private String appleName;@FruitColor(fruitColor = FruitColor.Color.RED)private String appleColor;@FruitProvider(id = 1, name = "陕西红富士集团", address = "陕西省西安市延安路89号红富士大厦")private String appleProvider;public void setAppleColor(String appleColor) {this.appleColor = appleColor;}public String getAppleColor() {return appleColor;}public void setAppleName(String appleName) {this.appleName = appleName;}public String getAppleName() {return appleName;}public void setAppleProvider(String appleProvider) {this.appleProvider = appleProvider;}public String getAppleProvider() {return appleProvider;}public void displayName() {System.out.println("水果的名字是:苹果");}
}
/***********注解处理器***************/package com.test2;import java.lang.reflect.Field;public class FruitInfoUtil {public static void getFruitInfo(Class<?> clazz) {String strFruitName = " 水果名称:";String strFruitColor = " 水果颜色:";String strFruitProvicer = "供应商信息:";Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {if (field.isAnnotationPresent(FruitName.class)) {FruitName fruitName = (FruitName) field.getAnnotation(FruitName.class);strFruitName = strFruitName + fruitName.value();System.out.println(strFruitName);} else if (field.isAnnotationPresent(FruitColor.class)) {FruitColor fruitColor = (FruitColor) field.getAnnotation(FruitColor.class);strFruitColor = strFruitColor + fruitColor.fruitColor().toString();System.out.println(strFruitColor);} else if (field.isAnnotationPresent(FruitProvider.class)) {FruitProvider fruitProvider = (FruitProvider) field.getAnnotation(FruitProvider.class);strFruitProvicer = " 供应商编号:" + fruitProvider.id() + " 供应商名称:" + fruitProvider.name() + " 供应商地址:" + fruitProvider.address();System.out.println(strFruitProvicer);}}}
}
/***********输出结果***************/package com.test2;public class FruitRun {/*** @param args*/public static void main(String[] args) {FruitInfoUtil.getFruitInfo(Apple.class);}}
 # 程序输出水果名称:Apple水果颜色:RED供应商编号:1 供应商名称:陕西红富士集团 供应商地址:陕西省西安市延安路89号红富士大厦

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

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

相关文章

【Git】Git的基本操作

前言 Git是当前最主流的版本管理器&#xff0c;它可以控制电脑上的所有格式的文件。 它对于开发人员&#xff0c;可以管理项目中的源代码文档。&#xff08;可以记录不同提交的修改细节&#xff0c;并且任意跳转版本&#xff09; 本篇博客基于最近对Git的学习&#xff0c;简单介…

2023年03月15日_GPT4的发布会简单介绍

文章目录 各种考试长度限制图像输入功能开发者API定价评估框架1 - 基准测试表现2 - 文本和图像提示3 - 系统消息功能4 - 真实性、稳定性、可靠性 2023年3月15日 今天凌晨呢 万众瞩目的大型多模态模型 GPT-4正式发布 我们先总结一下发布会的重点 首先 这个模型能够接受图像和…

【Leetcode 39】组合总和 —— 回溯法

39. 组合总和 给你一个无重复元素的整数数组candidates和一个目标整数target &#xff0c;找出candidates中可以使数字和为目标数target的 所有不同组合&#xff0c;并以列表形式返回。你可以按**任意顺序 **返回这些组合。 candidates中的同一个数字可以 无限制重复被选取 。…

Vue3-29-路由-编程式导航的基本使用

补充一个知识点 路由配置中的 name 属性 &#xff1a; 可以给你的 路由 指定 name属性&#xff0c;称之为 命名路由。 这个 name 属性 在 编程式导航 传参时有重要的作用。 命名路由的写法如下 &#xff1a; 像指定 path 一样&#xff0c;直接指定一个 name 属性即可。{path:/d…

GBASE南大通用-小内存单机安装GBase 8c分布式数据库实践

* 这种小内存部署方式仅用于分布式数据库个人学习使用&#xff0c;不建议用于其他用途。 随着数据高并发复杂场景业务需求不断增多&#xff0c;信息数据呈现出爆炸式增长、多源多维、数据类型繁复等特征。在这一趋势下&#xff0c;目前分布式数据库因其架构的天然优势&#xf…

开放网络+私有云=?星融元的私有云承载网络解决方案实例

在全世界范围内的云服务市场上&#xff0c;开放网络一直是一个备受关注的话题。相比于传统供应商的网络设备&#xff0c;开放网络具备软硬件解耦、云原生、可选组件丰富等优势&#xff0c;对云服务商和超大型企业有足够的吸引力。 SONiC作为开源的网络操作系统&#xff0c;使得…

2047过滤空格(C语言)

目录 一&#xff1a;题目 二&#xff1a;思路分析 三&#xff1a;代码 一&#xff1a;题目 二&#xff1a;思路分析 1.首先&#xff0c;这道题是一个字符串的问题&#xff0c;我们要先知道字符串存放在char类型的数组中的&#xff0c;并不是一个变量就可直接存放的下一个完整…

了解 NSA 关于管理 OSS 和 SBOM 的最新指南

开源软件很容易受到恶意行为者的攻击&#xff0c;但软件材料清单可以帮助减轻威胁。美国国家安全局的指导为管理生态系统奠定了坚实的基础。 软件供应链安全仍然是网络安全和软件行业的一个关键话题&#xff0c;并且有充分的理由&#xff0c;从针对大型软件供应商的持续攻击到…

vlc 查看音频有没有声音

播放文件或者实时流 播放文件 选择音频文件 打开网络流 输入实时流地址 查看音频是否有声音

[LitCTF 2023]Vim yyds

[LitCTF 2023]Vim yyds wp 题目页面如下&#xff1a; 搜索一番&#xff0c;没有发现任何信息。题目描述中说到了源码泄露&#xff0c;那么先进行目录扫描。 dirsearch 目录扫描 命令&#xff1a; dirsearch -u "http://node4.anna.nssctf.cn:28588/"返回结果&…

Go 1.22新特性前瞻

美国时间2023年12月20日&#xff0c;Go官方宣布Go 1.22rc1发布&#xff0c;开启了为期2个多月的、常规的公测之旅&#xff0c;Go 1.22预计将于2024.2月份正式发布&#xff01; 除了在官网下载Go 1.22rc1版本进行新特性体验之外&#xff0c;我们还可以通过在线的Go Playground选…

黑马程序员SSM框架-Maven进阶

分模块开发与设计 分模块开发意义 分模块开发 依赖管理 依赖传递 依赖传递冲突问题 可以点击红框按钮查看依赖情况。 可选依赖和排除依赖 继承和聚合 聚合 聚合工程开发 继承 聚合和继承的区别 属性 属性的配置与使用 资源文件引用属性 其他属性&#xff08;了解&#xff0…

基于虚拟机ubuntu的linux和shell脚本的学习,以及SSH远程登陆实战

简介 特点 是一款操作系统,跟windows,macos一样,有下面的特点 简单和高效,一切皆文件,所有配置都通过修改文件解决,不需要繁琐的权限和设置 权限高,把所有细节都交给用户,可完全自定义 安全,所有程序只有自己执行才会启动 分类 1、debian系主要有Debian&#xff0c;Ubun…

【设计模式】组合模式

文章目录 前言一、组合模式1.案例2.组合模式分类3.优点4.使用场景 总结 前言 【设计模式】组合模式 一、组合模式 ​ 对于这个图片肯定会非常熟悉&#xff0c;上图我们可以看做是一个文件系统&#xff0c;对于这样的结构我们称之为树形结构。在树形结构中可以通过调用某个方法…

一款超酷的一体化网站测试工具:Web-Check

Web-Check 是一款功能强大的一体化工具&#xff0c;用于发现网站/主机的相关信息。用于检查网页的工具&#xff0c;用于确保网页的正确性和可访问性。它可以帮助开发人员和网站管理员检测网页中的错误和问题&#xff0c;并提供修复建议。 它只需要输入一个网站就可以查看一个网…

数据库系统原理例题之——SQL 与关系数据库基本操作

SQL 与关系数据库基本操作 第四章 SQL 与关系数据库基本操作【例题】一 、单选题二 、填空题三 、简答题四 、设计题 【答案&解析】一、单选题二、填空题三、简答题四、设计题 【延伸知识点】【延伸知识点答案&解析】 第四章 SQL 与关系数据库基本操作 【例题】 一 、…

【23.12.30期--Spring篇】Spring的AOP介绍(详解)

Spring的AOP介绍 ✔️简述✔️扩展知识✔️AOP是如何实现的 ✔️简述 AOP(Aspect-Oriented Programming)&#xff0c;即面向切面编程&#xff0c;用人话说就是把公共的逻辑抽出来&#xff0c;让开发者可以更专注于业务逻辑开发。 和IOC-样&#xff0c;AOP也指的是一种思想。AOP…

字符串函数的实现以及大小写转换、字符统计等------(C每日一编程)

--基本算法&#xff1a; --字符串求长度、拷贝、比较、连接 --大小写转换、字符统计 -其他&#xff1a; --判断回文、逆序、删字符、字符定位 --输入&#xff08;gets&#xff09;、输出&#xff08;puts&#xff09; 正文解读&#xff1a; 大小写转换&#xff1a;就是加减32…

Shell三剑客:awk(awk编辑编程)六

一、AWK 的函数前言 awk的函数有许多&#xff0c;除了系统自带的内建函数还有就是用户自定义的函数。 二、AWK 常用的函数 rand() # 返回0 和1 之间一个随机数srand() # 生成随机数种子int() # 取整数length([s]) # 返回指定字符串的长度sub(r,s,[t]) # 对t字符串进行搜索&am…

【C++杂货铺】C++11新特性——lambda

文章目录 一、C98中的排序二、先来看看 lambda 表达式长什么样三、lambda表达式语法3.1 捕捉列表的使用细节 四、lambda 的底层原理五、结语 一、C98中的排序 在 C98 中&#xff0c;如果要对一个数据集合中的元素进行排序&#xff0c;可以使用 std::sort 方法&#xff0c;下面…