java基础之枚举和注解

枚举

简介

枚举:enumeration,jdk1.5中引入的新特性,用于管理和使用常量

入门案例

第一步:定义枚举,这里定义一个动物类,里面枚举了多种动物

public enum AnimalEnum {CAT,  // 猫DOG,  // 狗PIG   // 猪
}

第二步:使用枚举类,这里会打印枚举类中的枚举值

public static void main(String[] args) {// 打印枚举类中的枚举值System.out.println("AnimalEnum.CAT = " + AnimalEnum.CAT);  // CAT// 枚举值的字符串形式,和它的声明是一致的,可以把枚举值当做一个字符串常量来使用System.out.println("AnimalEnum.CAT.toString().equals(\"CAT\") = " + AnimalEnum.CAT.toString().equals("CAT"));   // true
}

总结:可以把枚举类中的枚举值当做字符串常量去使用,入门案例中演示了枚举类最基本的使用方式。

基本使用

语法

枚举类中声明的常量,本质上,是以枚举类为数据类型的实例。

定义枚举类的格式:

[访问修饰符] enum <enum_name> {常量[(构造器参数)] [{  // 抽象方法的实现  }]  [, ....] [;]成员变量;构造方法;自定义方法;抽象方法;
}

从格式上看,枚举类中可以定义构造方法、普通方法、抽象方法,因为枚举类中声明的常量本质上是以枚举类为数据类型的实例,这些实例中可以存储数据,也可以有自己的行为,不过在枚举类中定义方法时在语法上有一些要求。

编写枚举类的语法要求:

  • 先定义枚举值,后定义方法,枚举值和方法之间用分号隔开。
  • 为枚举类定义成员变量和构造方法:构造方法定义了枚举值中可以存储什么数据,构造方法默认被private修饰,所以用户无需为构造方法指明访问修饰符,这是为了防止枚举类被外部实例化。
  • 为枚举类定义普通方法:普通方法可以为枚举值添加一些行为。
  • 为枚举类定义抽象方法:枚举类中可以声明一个抽象方法,然后每个枚举类的实例实现此抽象方法。枚举类还可以实现某个接口,功能上类似于在枚举类中定义抽象方法。

案例1:为枚举类定义构造方法和普通方法

第一步:定义枚举类

public enum ColorEnum {// 枚举类中如果定义了构造方法,声明枚举值时要使用这个构造方法,它表示枚举值中可以存储的数据RED(1, "RED", "红色"),BLUE(2, "BLUE", "蓝色"),BLACK(3, "BLACK", "黑色");public Integer i;public String name;public String desc;// 构造方法ColorEnum(int i, String name, String desc) {this.i = i;this.name = name;this.desc = desc;}// 普通方法public void say() {System.out.println("我的颜色是:" + this.name);}
}

第二步:使用枚举类

public static void main(String[] args) {// 1. 使用枚举值System.out.println("ColorEnum.RED = " + ColorEnum.RED);  // ColorEnum.RED = RED// 2. 枚举值中的普通方法ColorEnum.RED.say();  // 我的颜色是:RED
}

案例2:为枚举类定义抽象方法

第一步:定义枚举类

public enum OperationEnum {PLUS(1, "加法") {@Overridepublic double apply(double x, double y) {return x + y;}},MINUS (2, "减法") {@Overridepublic double apply(double x, double y) {return x - y;}};public final Integer id;public final String name;// 构造方法OperationEnum(Integer id, String name) {this.id = id;this.name = name;}// 声明抽象方法public abstract double apply(double x, double y);
}

第二步:使用枚举类

public static void main(String[] args) {// 枚举类中的抽象方法double apply = OperationEnum.PLUS.apply(1, 2);System.out.println("apply = " + apply);  // 3
}

案例3:枚举类实现接口

// 定义接口
public interface Inter {double apply(double a, double b);
}// 定义枚举类
public enum Operation implements Inter {MINUS{public double apply(double a, double b){return a - b;}},PLUS{public double apply(double a, double b){return a + b;}};
}

使用方式和在枚举类中定义抽象方法基本类型。

枚举类的反编译

枚举类是一种特殊的类,枚举类和普通类一样,也会生成一个类文件,Java编译器会为枚举类添加许多方法。

案例:入门案例中的Animal类,使用javap命令来反编译 javap -v AnimalEnum.class ,这里只展示反编译后的部分结果。

// 枚举类的底层继承了Enum类
public final class org.wyj.enumeration.AnimalEnum extends java.lang.Enum<org.wyj.enumeration.AnimalEnum>
{public static final org.wyj.enumeration.AnimalEnum CAT;   // CATdescriptor: Lorg/wyj/enumeration/AnimalEnum;flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUMpublic static final org.wyj.enumeration.AnimalEnum DOG;   // DOGdescriptor: Lorg/wyj/enumeration/AnimalEnum;flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUMpublic static final org.wyj.enumeration.AnimalEnum PIG;   // PIGdescriptor: Lorg/wyj/enumeration/AnimalEnum;flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM// values方法,返回枚举类中的所有实例public static org.wyj.enumeration.AnimalEnum[] values();descriptor: ()[Lorg/wyj/enumeration/AnimalEnum;flags: ACC_PUBLIC, ACC_STATICCode:stack=1, locals=0, args_size=00: getstatic     #1                  // Field $VALUES:[Lorg/wyj/enumeration/AnimalEnum;3: invokevirtual #2                  // Method "[Lorg/wyj/enumeration/AnimalEnum;".clone:()Ljava/lang/Object;6: checkcast     #3                  // class "[Lorg/wyj/enumeration/AnimalEnum;"9: areturnLineNumberTable:line 3: 0// valueOf方法,根据字符串常量来查找枚举类实例public static org.wyj.enumeration.AnimalEnum valueOf(java.lang.String);descriptor: (Ljava/lang/String;)Lorg/wyj/enumeration/AnimalEnum;flags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=1, args_size=10: ldc           #4                  // class org/wyj/enumeration/AnimalEnum2: aload_03: invokestatic  #5                  // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;6: checkcast     #4                  // class org/wyj/enumeration/AnimalEnum9: areturnLineNumberTable:line 3: 0LocalVariableTable:Start  Length  Slot  Name   Signature0      10     0  name   Ljava/lang/String;
}

案例2:反编译有抽象方法的枚举类,javap -v OperationEnum.class

// 有抽象方法的枚举类,枚举类在底层实际上是一个抽象类
public abstract class org.wyj.enumeration.OperationEnum extends java.lang.Enum<org.wyj.enumeration.OperationEnum>
{public static final org.wyj.enumeration.OperationEnum PLUS;descriptor: Lorg/wyj/enumeration/OperationEnum;flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUMpublic static final org.wyj.enumeration.OperationEnum MINUS;descriptor: Lorg/wyj/enumeration/OperationEnum;flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
}

枚举类中的每个枚举值都会生成一个匿名内部类,javap -v "OperationEnum\$1.class",注意,这里美元符在命令行需要特殊处理

final class org.wyj.enumeration.OperationEnum$1 extends org.wyj.enumeration.OperationEnum
{// 构造方法org.wyj.enumeration.OperationEnum$1(java.lang.String, int, java.lang.Integer, java.lang.String);descriptor: (Ljava/lang/String;ILjava/lang/Integer;Ljava/lang/String;)Vflags:Code:stack=6, locals=5, args_size=50: aload_01: aload_12: iload_23: aload_34: aload         46: aconst_null7: invokespecial #1                  // Method org/wyj/enumeration/OperationEnum."<init>":(Ljava/lang/String;ILjava/lang/Integer;Ljava/lang/String;Lorg/wyj/enumeration/OperationEnum$1;)V10: returnLineNumberTable:line 5: 0LocalVariableTable:Start  Length  Slot  Name   Signature0      11     0  this   Lorg/wyj/enumeration/OperationEnum$1;0      11     3    id   Ljava/lang/Integer;0      11     4  name   Ljava/lang/String;// 实现父类中的抽象方法public double apply(double, double);descriptor: (DD)Dflags: ACC_PUBLICCode:stack=4, locals=5, args_size=30: dload_11: dload_32: dadd   // add命令,证明这是加法3: dreturnLineNumberTable:line 8: 0LocalVariableTable:Start  Length  Slot  Name   Signature0       4     0  this   Lorg/wyj/enumeration/OperationEnum$1;0       4     1     x   D0       4     3     y   D
}

总结:反编译结果中枚举类的成员,可以看到,

  • 枚举类默认继承了Enum类
  • 枚举类中有两个重要的静态方法:
    • values():public static 枚举类[] values();:返回枚举类中所有常量组成的数组
    • valueOf(String):public static 枚举类 valueOf(java.lang.String);:传入枚举类中常量的字符串形式,返回枚举类中的常量
  • 声明了抽象方法的枚举类,枚举类中的每个枚举值都会使用一个匿名内部类来实现

枚举类的默认父类 Enum类

所有的枚举类都默认继承了Enum类。

源码分析:

public abstract class Enum<E extends Enum<E>>implements Comparable<E>, Serializable {// 枚举值的字符串形式private final String name;public final String name() {return name;}// 表示枚举值在枚举类中被声明的顺序,从0开始计数private final int ordinal;public final int ordinal() {return ordinal;}// 构造方法protected Enum(String name, int ordinal) {this.name = name;this.ordinal = ordinal;}// 重写Object类中的方法public String toString() {return name;}public final boolean equals(Object other) {return this==other;}public final int hashCode() {return super.hashCode();}protected final Object clone() throws CloneNotSupportedException {throw new CloneNotSupportedException();}// 两个枚举值的比较public final int compareTo(E o) {Enum<?> other = (Enum<?>)o;Enum<E> self = this;if (self.getClass() != other.getClass() && // optimizationself.getDeclaringClass() != other.getDeclaringClass())throw new ClassCastException();return self.ordinal - other.ordinal;}// 阻止反序列化private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException {throw new InvalidObjectException("can't deserialize enum");}private void readObjectNoData() throws ObjectStreamException {throw new InvalidObjectException("can't deserialize enum");}
}

枚举值的默认父类几乎不会被使用到,这里只做了解

实战案例

案例1:switch和枚举类

如果switch语句对应的变量是一个枚举类的实例,case语句后必须直接使用枚举类中的常量

案例:

public static void main(String[] args) {AnimalEnum DOG = AnimalEnum.DOG;switch (DOG) {case DOG:System.out.println("狗");  // 狗break;case PIG:System.out.println("猪");break;case CAT:System.out.println("猫");break;default:System.out.println("未知");break;}
}

案例2:生产中定义枚举类的常见方式

public enum ColorEnum {// 枚举类中如果定义了构造方法,声明枚举值是要使用这个构造方法,它表示枚举值中可以存储的数据RED(1, "RED", "红色"),BLUE(2, "BLUE", "蓝色"),BLACK(3, "BLACK", "黑色");public final Integer id;public final String name;public final String desc;// 构造方法ColorEnum(int id, String name, String desc) {this.id = id;this.name = name;this.desc = desc;}// 根据id获取枚举值实例public ColorEnum getEnumById(Integer id) {ColorEnum[] values = values();for (ColorEnum value : values) {if (value.id.equals(id)) {return value;}}return null;}// 返回枚举值的集合public List<ColorEnum> getEnumList() {return Arrays.asList(values());}// 普通方法public void say() {System.out.println("我的颜色是:" + this.desc);}
}

这里需要注意的是,每个枚举值都有自己的id和name,id用于数据库的存储,name用于平时使用,同时,定义了根据id来获取枚举值的方法,这是实际开发中用的最多的。

注解

简介

注解:Annotation,Java1.5引入的功能,它可以被标注在类、方法、字段上,用于指明某种特性,也可以用它来存储配置信息。

注解的使用,有两种场景,

  • 一种是在源码中,告诉程序员某个信息,例如@Override注解,告诉程序员当前方法是父类中某个方法的重写,
  • 一种是在运行时,通过反射获取注解信息,此时,注解可以用于存储配置信息。

基本使用

java中的元注解

元注解:负责标注其它的注解,用于指明注解的特性,是用户自定义注解是需要用到的

java中的5个元注解:

1、@Retention:指定注解的生命周期

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {RetentionPolicy value();  // 指定注解的生命周期
}

这里涉及到的两个枚举类:

a. 定义了注解的生命周期常量的枚举类:

// 定义了注解有哪些生命周期
public enum RetentionPolicy {// 注解只存在于源码中,会被编译器丢掉。注解只存在于源码阶段SOURCE,// 注解会被编译器编译到类文件中,但是运行时不会把注解信息加载到虚拟机中,这是默认的生命周期。// 注解只存在于源码阶段和编译阶段CLASS,// 注解会被加载到虚拟机中,此时可以通过反射获取注解中存储的信息,// 注解存在于源码阶段、编译阶段和运行时阶段RUNTIME
}

b. 定义了注解的使用位置常量的枚举类:

// 枚举类中的常量代表代表一个编译单元中的某个位置
public enum ElementType {// 类、接口或枚举TYPE,// 字段,包括枚举常量FIELD,// 方法声明METHOD,// 参数PARAMETER,// 构造器CONSTRUCTOR,// 局部变量LOCAL_VARIABLE,// 注解,一个可以应用于注解上的注解,类似于元注解。ANNOTATION_TYPE,// 包PACKAGE,// 表示注解可以应用于类型参数声明,案例 public class MyClass<@MyAnnotation T> {}TYPE_PARAMETER,// 表示注解可以应用于类型使用的地方,例如变量声明、方法返回类型、方法参数类型等TYPE_USE
}

2、@Documented:被@Documented注解的注解会被javadoc之类的工具处理,它们的信息会被添加到帮助文档中,默认情况下,注解是不会被添加到帮助文档中的。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

3、@Target:指明了注解可以出现在什么位置。默认情况下,枚举可以被应用到除了泛型、包以外的任何地方

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {// 一个ElementType类型的数组,表明注解可以被应用在什么位置ElementType[] value();  
}

4、@Inherited:继承。表示一个注解可以被继承

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

5、@Repeatable:java1.8新增的注解,允许一个类型的注解在同一个程序元素上重复出现。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {// 指定哪个注解可以重复出现Class<? extends Annotation> value();
}

java中自带的注解

1、@Override:只能用于方法,只存在于源码阶段,表明当前方法重写了父类的方法。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

2、@Deprecated:这个注解会被添加到文档中,存在于运行阶段,可以注解类、方法等。一个程序元素被@Deprecated注解,表明开发者不推荐用户使用这个程序元素

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}

3、@SuppressWarnings:告诉编译器忽略指定类型的告警,可以标注在类、字段、方法、局部变量等位置。

使用方式:

  • 告诉编译器忽略类型转换警告信息:@SuppressWarnings(“unchecked”)
  • 告诉编译器忽略被过时告警:@SuppressWarnings(“deprecation”),使用了被@Deprecated标注的元素,编译器会发出过时告警
  • 告诉编译器同时忽略多个告警信息:
    • 第一种写法:@SuppressWarnings(“unchecked”, “deprecation”)
    • 第二种写法:@SuppressWarnings(value={“unchecked”, “deprecation”})
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {// 指定告警类型String[] value();
}

4、@FunctionalInterface:这个注解会被添加到文档中,存在于运行阶段,可以注解接口,表明被它注解的接口是一个函数式接口,也就是接口中只有一个方法的接口。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}

5、@SafeVarargs:这个注解会被添加到文档中,存在于运行阶段,可以注解构造器、方法。参数安全类型注解,它的目的是提醒开发者不要用参数做一些不安全的操作,它的存在会阻止编译器产生 unchecked 这样的警告。它是在 Java 1.7 的版本中加入的。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface SafeVarargs {}

自定义注解

自定义注解的语法:

[public] @interface 注解名 { 参数类型 成员变量名() [default];....
}

语法讲解:

  • 注解只有成员变量,没有成员方法。
  • 声明成员变量的格式:数据类型 成员变量名() [default 值]。成员变量可以有默认值,通过default关键字来指定。
  • 如果注解中只有一个属性,那么属性名称应该为value,这是一个默认的约定。

注解的使用:把注解放在合适的位置,@注解名(属性=值 [,...])

  • 如果注解中没有属性,那么括号可以省略不写。
  • 如果属性有默认值,那么在使用时就不需要为属性赋值了如果想要覆盖原有的属性也可以赋值。
  • 如果属性名是value,value可以省略不写

注解的获取:在运行阶段,需要通过反射,获取注解中的信息,如果想要让注解被反射获取,注解必须要被@Retention(RetentionPolicy.RUNTIME)注解,它表示注解的生命周期策略是运行时存在。

标记注解:不包含任何成员变量的注解

使用案例

案例1:自定义一个普通注解,指定一个类的初始化方法

第一步:定义注解

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface InitMethod {// 注解中存储的数据,这里没有什么意义,仅仅演示如何操作注解的属性String value();String name() default "im";
}

第二步:使用注解,注解如果没有指定使用范围,默认可以使用在类上、方法上

public class InitDemo {public InitDemo() { }@InitMethod(value = "1", name = "2")public void test1(int b) {int a = 1;System.out.println("执行test1方法");}
}

第三步:通过反射获取注解

public static void main(String[] args) {try {Class<?> aClass = Class.forName("org.wyj.anno.InitDemo");// 获取类上的注解Annotation[] declaredAnnotations = aClass.getDeclaredAnnotations();for (Annotation declaredAnnotation : declaredAnnotations) {System.out.println("declaredAnnotation = " + declaredAnnotation);}// 获取方法上的指定注解Method[] methods = aClass.getMethods();for (Method method : methods) {if (method.isAnnotationPresent(InitMethod.class)) {InitMethod annotation = method.getAnnotation(InitMethod.class);System.out.println(annotation);System.out.println(annotation.value() + ":" + annotation.name());}}} catch (ClassNotFoundException e) {throw new RuntimeException(e);}
}

总结:这个案例演示了注解的基本使用,实际开发中,这是使用最多的方式

案例2:可重复出现的注解

第一步:定义注解

// 可以重复使用的注解
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Persons.class)   // 使用@Repeatable注解把当前注解定义为可重复注解时,要指定它的容器注解
public @interface Person {String role();
}// 注解的容器注解
@Retention(RetentionPolicy.RUNTIME)
public @interface Persons {Person[] value();
}

第二步:注解的使用

@Person(role = "艺术家")
@Person(role = "士兵")
@Person(role = "厨师")
public class Man {
}

第三步:通过反射获取注解

// 测试容器注解
public static void main(String[] args) {try {Class<?> aClass = Class.forName("org.wyj.anno.Man");Person[] annotationsByType = aClass.getAnnotationsByType(Person.class);for (Person person : annotationsByType) {System.out.println(person.role());}} catch (ClassNotFoundException e) {e.printStackTrace();}
}

总结:

  • 在使用@Repeatable来注解一个可重复注解的时候,需要提供一个容器注解,容器注解用于装载可重复注解。
  • 容器注解:@Repeatable注解需要使用到的工具注解,注解中的属性是一个数组,数组中元素的数据类型是被@Repeatable注解的注解。

案例3:测试注解的继承

第一步:定义注解,一个可以被继承的注解

@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface InheritedTest {
}

第二步:注解的使用

// 父类
@InheritedTest
public class InheritedDemo {@InitMethod("aaa")public void init() { }
}// 子类
public class InheritedDemoSon extends InheritedDemo { }

第三步:通过反射获取注解

public static void main(String[] args) {try {Class<?> aClass = Class.forName("org.wyj.anno.InheritedDemoSon");// 类上的注解System.out.println(aClass.isAnnotationPresent(InheritedTest.class)); // true// 方法上的注解for (Method method : aClass.getMethods()) {if (method.getName().equals("init")) {System.out.println("method.isAnnotationPresent(InitMethod.class) = "+ method.isAnnotationPresent(InitMethod.class));  // true}}} catch (ClassNotFoundException e) {throw new RuntimeException(e);}
}

总结:

  • 注解的继承:在继承关系中,
    • 对于方法上的注解,子类会继承父类的方法,同时也会方法上的注解,无论该注解有没有被@Inherited修饰,
    • 对于类上的注解,如果它被@Inherited注解修饰,它才可以被子类继承,但也仅限于子类,不包括子类的子类

查看一个注解反编译后的字节码

案例:以@InitMethod为例,javap -v InitMethod.class

public interface org.wyj.anno.InitMethod extends java.lang.annotation.Annotation
{public abstract java.lang.String value();descriptor: ()Ljava/lang/String;flags: ACC_PUBLIC, ACC_ABSTRACTpublic abstract java.lang.String name();descriptor: ()Ljava/lang/String;flags: ACC_PUBLIC, ACC_ABSTRACT
}

总结:可以看到,注解实际上是一个接口,并且每个注解都默认继承Annotation接口,

注解的公共父接口 Annotation接口

所有的注解默认都会继承Annotation接口,这个动作由编译器来完成

源码:

public interface Annotation {boolean equals(Object obj);int hashCode();String toString();Class<? extends Annotation> annotationType();
}

总结

这里介绍了注解的基本特性,演示了注解的基本使用。如果有补充,欢迎评论。

Q&A

1、枚举类的构造方法,为什么不可以是public?

由于枚举实例是固定的,开发者不能在运行时创建新的枚举实例。因此,构造方法不能是public的,Java编译器自动将枚举的构造方法设为private,以确保枚举实例只能在枚举类内部定义。这是为了确保枚举实例的唯一性和安全性。

2、枚举类可以同时是泛型类吗?

不可以,枚举类不可以是泛型类,但是枚举类中可以定义泛型方法,因为枚举类不可以从外部实例化,所以在枚举类上声明泛型没有意义。

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

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

相关文章

2.3java运算符

运算符 1. 算术运算符 算术运算符用于执行基本的数学运算&#xff0c;像加、减、乘、除等。 运算符描述示例加法int a 5 3; // a 的值为 8-减法int b 5 - 3; // b 的值为 2*乘法int c 5 * 3; // c 的值为 15/除法int d 6 / 3; // d 的值为 2%取模&#xff08;取余&…

升级 Spring Boot CLI

&#x1f31f; 升级 Spring Boot CLI 1️⃣ &#x1f504; 通过包管理器升级 使用对应包管理器命令&#xff08;如 brew upgrade&#xff09; 2️⃣ &#x1f4e5; 手动安装升级 遵循 标准安装说明 注意更新 PATH 环境变量移除旧版本路径 &#x1f517; 链接原文&#xff1a…

如何轻松将RS232转为Profibus DP,提升PLC效率?

如何轻松将RS232转为Profibus DP&#xff0c;提升PLC效率&#xff1f; 今天&#xff0c;我们就来聊聊一个工业自动化中常见的应用场景&#xff1a;如何通过兴达易控RS232转Profibus DP网关&#xff0c;实现流量泵与PLC&#xff08;可编程逻辑控制器&#xff09;的通信。这个话…

QT 连接数据库操作(15)

文章目录 一、本章说明二、QT连接云端数据库实现2.1 ODBC软件安装及参数设置2.2 软件代码实现三、项目源码文件一、本章说明 注:本节为【基于STM的环境监测系统(节点+云服务器存储+QT界面设计)】项目第15篇文章,前面已经创建了监测软件的登录窗口,接下来我们将在主窗口实…

linux系统之----命令行参数和环境变量

一、命令行参数 1.main()函数的参数 在C语言中&#xff0c;main函数可以接收命令行参数&#xff0c;其标准形式为&#xff1a; int main(int argc, char *argv[]) {// 程序代码return 0; } 这里我们解释一下&#xff1a; argc&#xff1a;参数个数计数器&#xff08;Argum…

解析excel中的图片

解析excel中的图片 前言一、pom依赖二、使用步骤1.示例数据2.代码如下&#xff08;示例&#xff09;&#xff1a; 总结 前言 初始化数据是&#xff0c;需要将excel中的数据解析并插入数据库。 但是某几列存放的是图片&#xff0c;这时候怎么办呢。 主要解决的是&#xff1a;获…

Unity任务系统笔记

数据结构设计 任务基类包括的字段&#xff1a; string 任务内容&#xff1b; Transform 任务目的地&#xff1b; MyCharacter 任务开启后要更新对话的NPC&#xff1b; MyTalkData 任务开启后相关NPC要说的对话数据&#xff1b; 共同方法&#xff1a;开启任务、完成任务。…

STM32的开发环境介绍

目录 STM32软件环境 Keil软件在线安装 其他软件环境安装 STM32开发的几种方式 STM32寄存器版本和库函数版本 标准外设库的作用&#xff1a; STM32软件环境 STM32 的集成开发环境&#xff08;IDE&#xff09;&#xff1a;编辑编译软件 常见的环境&#xff1a; (1)KEIL&a…

【特殊场景应对9】视频简历的适用场景与风险分析

写在最前 作为一个中古程序猿,我有很多自己想做的事情,比如埋头苦干手搓一个低代码数据库设计平台(目前只针对写java的朋友),比如很喜欢帮身边的朋友看看简历,讲讲面试技巧,毕竟工作这么多年,也做到过高管,有很多面人经历,意见还算有用,大家基本都能拿到想要的offe…

Linux系统性能调优技巧分享

在数字化时代,Linux 系统以其开源、稳定、高效的特性,成为服务器、云计算、物联网等领域的核心支撑。然而,随着业务规模的扩大和负载的增加,系统性能问题逐渐凸显。掌握 Linux 系统性能调优技巧,不仅能提升系统运行效率,还能降低运维成本。下面从多个方面介绍实用的性能调…

关于Code_流苏:商务合作、产品开发、计算机科普、自媒体运营,一起见证科技与艺术的交融!

Code_流苏 &#x1f33f; 名人说&#xff1a;路漫漫其修远兮&#xff0c;吾将上下而求索。—— 屈原《离骚》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; &#x1f31f; 欢迎来到Code_流苏的CSDN主页 —— 与我一起&…

系统架构设计(三):质量属性

常见分类 一般来说&#xff0c;质量属性可以分为以下几类&#xff1a; 类别常见质量属性性能相关响应时间、吞吐量、资源利用率、实时性、可扩展性可用性相关可用性、高可用性&#xff08;HA&#xff09;、可靠性、容错性、恢复性可维护性相关可维护性、可测试性、可扩展性、…

【锂电池剩余寿命预测】GRU门控循环单元锂电池剩余寿命预测(Matlab完整源码)

目录 效果一览程序获取程序内容代码分享研究内容GRU门控循环单元在锂电池剩余寿命预测中的应用摘要关键词1. 引言1.1 研究背景1.2 研究现状与问题1.3 研究目的与意义2. 文献综述2.1 锂电池剩余寿命预测传统方法2.2 深度学习在锂电池寿命预测中的应用2.3 研究空白与本文切入点3.…

SpringCloud原理和机制

Spring Cloud 是一套基于Spring Boot的微服务开发工具集&#xff0c;它提供了在分布式系统环境下构建应用程序所需的一系列工具和服务。Spring Cloud旨在帮助开发人员快速构建一些常见的微服务模式&#xff0c;如服务发现、配置管理、智能路由、熔断器、微代理、控制总线等。 …

LeetCode -- Flora -- edit 2025-04-25

1.盛最多水的容器 11. 盛最多水的容器 已解答 中等 相关标签 相关企业 提示 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最…

有关图的类型的题目以及知识点(2)

1、具有5个顶点的有向完全图有20条弧。 2、若一个有向图用邻接矩阵表示&#xff0c;则第个结点的入度就是&#xff1a;第i列的非零元素的个数。 3、有向图的邻接矩阵可以是对称的&#xff0c;也可以是不对称的。 4、设N个顶点E条边的图用邻接表存储&#xff0c;则求每个顶点…

正则表达式的捕获组

是正则表达式中的一个重要概念&#xff0c;用于提取字符串中的特定部分 捕获组是通过正则表达式中的圆括号 () 定义的&#xff0c;它的作用是&#xff1a; 划分和标记&#xff1a;将正则表达式的一部分划分为逻辑单元。 提取数据&#xff1a;从字符串中提取符合组内模式的内容…

deepseek-cli开源的强大命令行界面,用于与 DeepSeek 的 AI 模型进行交互

一、软件介绍 文末提供程序和源码下载 deepseek-cli一个强大的命令行界面&#xff0c;用于与 DeepSeek 的 AI 模型进行交互。 二、Features 特征 Multiple Model Support 多模型支持 DeepSeek-V3 (deepseek-chat) DeepSeek-R1 &#xff08;deepseek-reasoner&#xff09;Dee…

Java—— 五道算法水题

第一题 需求&#xff1a; 包装类&#xff1a;键盘录入一些1~100之间的整数&#xff0c;并添加到集合中。直到集合中所有数据和超过200为止 代码实现&#xff1a; import java.util.ArrayList; import java.util.Scanner;public class Test1 {public static void main(String[]…

安全编排自动化与响应(SOAR):从事件响应到智能编排的技术实践

安全编排自动化与响应&#xff08;SOAR&#xff09;&#xff1a;从事件响应到智能编排的技术实践 在网络安全威胁复杂度指数级增长的今天&#xff0c;人工处理安全事件的效率已难以应对高频攻击&#xff08;如日均万级的恶意IP扫描&#xff09;。安全编排自动化与响应&#xf…