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

【昕宝爸爸小模块】深入浅出详解之常见的语法糖

在这里插入图片描述

深入浅出详解之常见的语法糖

  • 一、🟢关于语法糖的典型解析
  • 二、🟢如何解语法糖?
    • 2.1🟢糖块一、switch 支持 String 与枚举
    • 2.2📙糖块二、泛型
    • 2.3📝糖块三、自动装箱与拆箱
    • 2.4🍁糖块四、方法变长参数
    • 2.5🖥️糖块五、枚举
    • 2.6⛳ 糖块六、内部内
    • 2.7✅糖块七、条件编译
    • 2.8🎖️糖块八、断言
    • 2.9😊糖块九、数值字面量
    • 2.10💡糖块十、for-each
    • 2.11📑糖块十一、 try-with-resource
    • 2.12🟢糖块十二、Lambda表达式
      • 2.12.1🟢Lambda表达式是如何实现的
  • 三、✅可能遇到的坑
    • 3.1✅泛型
      • 3.1.1 ✅当泛型遇到重载
      • 3.1.2 ✅当泛型遇到catch
      • 3.1.3 ✅当泛型内包含静态变量
    • 3.2 ✅自动装箱与拆箱
      • 3.2.1 ✅对象相等比较
      • 3.2.2 ✅增强for循环
  • 四、📗总结

一、🟢关于语法糖的典型解析


语法糖(Syntactic sugar),指在计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。


虽然Java中有很多语法糖,但是Java虚拟机并不支持这些语法糖,所以这些语法糖在编译阶段就会被还原成简单的基础语法结构,这样才能被虚拟机识别,这个过程就是解语法糖.。


如果看过Java虚拟机的源码,就会发现在编译过程中有一个重要的步骤就是调用desugar(),这个方法就是负责解语法糖的实现。


常见的语法糖有 switch支持枚举及字符里、泛型、条件编译、断言、可变参数、自动装箱/拆箱、枚举、内部类增强for循环、try-with-resources语句、lambda表达式等。


二、🟢如何解语法糖?


语法糖的存在主要是方便开发人员使用。但其实,Java虚拟机并不支持这些语法糖。这些语法糖在编译阶段就会被还原成简单的基础语法结构,这个过程就是解语法糖。


说到编译,大家肯定都知道,Java语言中javac命今可以将后缀名为 .java 的源文件编译为后缀名为 .class 的可以运行Java虚拟机的字节码。如果你去看 com.sun.tools.javac,mainJavaCompiler 的源码,你会发现在compile()中有个步骤就是调用desugar(),这个方法就是负责解 语法糖 的实现的。


2.1🟢糖块一、switch 支持 String 与枚举


前面提到过,从Java 7 开始,Java语言中的语法糖在逐渐富,其中一个比较重要的就是Java 7中 switch 开始支持 String


在开始coding之前先科普下,Java中的 switch 自身原本就支持基本类型。比如 intchar 等。对于 int 类型,直接进行数值的比较。对于 char 类型则是比较其 asckii 码。所以,对于编译器来说, switch 中其实只能使用整型,任何类型的比较都要转换成整型。比如 byteshortchar (asckii码是型)以及 int 。


那么接下来看下 switch 对 string 得支持,有以下代码:


public class SwitchDemostring {public static void main(stringl] args) {String str = "world";case "hello":System.out.println("hello");break;case "world":System.out.printn("world");break;default :break;}
}

反编译后内容如下:


public class SwitchDemoString {public switchDemoString(){}public static void main(String args[]) {String str = "world";String s;switch((s = str).hashCode()) {default:break;case 99162322:if(s.equals("hel1o"))System.out.println("hello") ;break;case 113318802:if(s.equals("world")) System.out.println("world");break;}}
}

看到这个代码,你知道原来字符串的switch是通过 equals() 和 hashCode() 方法来实现的。还好 hashCode()方法返回的是 int ,而不是 long 。


仔细看下可以发现,进行switch 的实际是哈希值,然后通过使用equals 方法比较进行安全检查,这个检查是必要的,因为哈希可能会发生碰撞。因此它的性能是不如使用枚举进行switch或者使用纯整数常量,但这也不是很差。


2.2📙糖块二、泛型


我们都知道,很多语言都是支持泛型的,但是很多人不知道的是,不同的编译器对于泛型的处理方式是不同的,通常情况下,一个编译器处理泛型有两种方式: Code specializationCode sharing 。C++和C#是使用Code specialization 的处理机制,而Java使用的是 Code sharing 的机制。


Code sharing方式为每个泛型类型创建唯一的字节码表示,并目将该泛型类型的实例都映射到这个唯一的字节码表示上。将多种泛型类形实例映射到唯一的字节码表示是通过类型擦除( type erasure )实现的。


也就是说,对于Java虚拟机来说,他根本不认识 MapString,String> map 这样的语法。需要在编译阶段通过类型擦除的方式进行解语法糖


类型擦除的主要过程如下: 1.将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。 2.移除所有的类理参数。


看如下代码:

Map<StringString> map = new HashMap<String,String>();
map.put("name","Java");
map.put("wechat""Java");
map.put("blog""www.Java_xiaoyuan.com");

解语法糖之后会变成:


Map map = new HashMap();
map.put("name","Java");
map.put("wechat""Java");
map.put("blog""www.Java_xiaoyuan.com");

代码如下:

public static <A extends Comparable<A>> A max(Collection<A> xs) {Iterator<A> xi = xs.iterator();A w = xi.next();while (xi .hasNext()) {A x = xi.next(l);if (w.compareTo(x) < 0)w = x;}return w;
}

类型擦除后会变成:


public static Comparable max(Collection xs) {Iterator xi = xs.iterator();Comparable w = (Comparable]xi.next();while(xi.hasMext()) {Comparable x = (Comparable)xi.next();if(w.compareTo(x) < 0)W=X;}return w;
}

虚拟机中没有泛型,只有普通类和普通方法,所有泛型类的类型参数在编译时都会被擦除,泛型类并没有自己独有的 class 类对象。比如并不存在 List< String>.class 或是 List< Integer>.class ,而只有 List.class


2.3📝糖块三、自动装箱与拆箱


自动装箱就是Java自动将原始类型值转换成对应的对象,比如将int的变量转换成Integer对象,这个过程叫做装箱,反之将Integer对象转换成int类型值,这个过程叫做拆箱。因为这里的装箱和拆箱是自动进行的非人为转换所以就称作为自动装箱和拆箱。原始类型byte, short,char, int, long,float, double 和 boolean 对应的封装类为Byte, Short, Character, Integer, Long, Float, Double,Boolean。


先来看个自动装箱的代码:


public static void main(String[] args) {int i = 10;Integer n = i;
}

反编译后代码如下:


public static void main(string args[]) {int i = 10;Integer n = Integer.valueOf(i);
}

再来看个自动拆箱的代码:


public static void main(stringli args) {Integer i = 10;int n = i;
}

反编译后代码如下


public static void main(String args[]) {Integer i = Integer.value0f(1);int n = i.intValue( );
}

队反编译得到内容可以看出,在装箱的时候自动调用的是 Integer 的 valueof(int) 方法。而在拆箱的时候自动调用的是 Integer 的 intValue 方法。


所以,装箱过程是通过调用包装器的valueof方法实现的,而拆箱过程是通过调用包装器的 xxxValue方法实现的。


2.4🍁糖块四、方法变长参数


可变参数( variable arguments )是在Java 1.5中引入的一个特性。它允许一个方法把任意数量的值作为参数。


看下以下可变参数代码,其中print方法接收可变参数:


public static void main(String[] args) {print("Java""公众号:昕宝爸爸爱编程""博客: https://blog.csdn.net/Java_Yangxiaoyuan?spm=1000.2115.3001.5343""QQ: 2439667691");
}public static  void print(string... strs) {for (int i = 0; i < strs.length; i++) {System.out.println(strs[i]);}
}

反编译后代码:


public static void main(string args[]) {print(new String[] ("Java""\u516C\u4F17\u53F7:Java_yangxiaoyuan""https://blog.csdn.net/Java_Yangxiaoyuan?spm=1000.2115.3001.5343""QQ\uFF1A2439667691"
});
}public static transient void print(String strs[]) {for(int i = 0; i < strs.length; i++){System.out.println(strs[i]);}
}

从反编译后代码可以看出,可变参数在被使用的时候,他首先会创建一个数组,数组的长度就是调用该方法是传递的实参的个数,然后再把参数值全部放到这个数组当中,然后再把这个数组作为参数传递到被调用的方法中。


2.5🖥️糖块五、枚举


在Java中,枚举是一种特殊的数据类型,用于表示有限的一组常量。枚举常量是在枚举类型中定义的,每人常量都是该类型的一个实例。Java中的枚举类型是一种安全而优雅的方式来表示有限的一组值。


要想看源码,首先得有一个类吧,那么枚举类型到底是什么类呢? 是 enum 吗? 答案很明显不是,enum class 一样,只是一个关键字,他并不是一个类,那么枚举是由什么类维护的呢,我们简单的写一个枚举:


public enum t {SPRING,SUMMER}

然后我们使用反编译,看看这段代码到底是怎么实现的,反编译后代码内容如下:


public final class T extends Enum {private T(String s, int i) {super(s, i);}public static T[] values() {T at[];int i;T at1[];System.arraycopy(at = ENUMSVALUES, 0, at1 = new T[i = at.length], 0, i);return at1;}public static T valueOf(String s) {return (T)Enum.valueOf(demo/T,s);}public static final T SPRING;public static final T SUMMER;private static final T ENUMSVALUES[];//静态代码块static {SPRING = new T("SPRING"0);SUMMER = new T("SUMMER"1);ENUM$VALUES = (new TI] {SPRINGSUMMER});}
}

通过反编译后代码我们可以看到, public final class T extends Enum,说明,该类是然承了 Enum 类的,同时 final 关键字告诉我们,这个类也是不能被继承的。


当我们使用 enum 来定义一个枚举类型的时候.编译器会自动帮我们创建一个 final 类型的类继承 Enum 类,所以枚举类型不能被继承。


2.6⛳ 糖块六、内部内


内部类又称为嵌套类,可以把内部类理解为外部类的一个普通成员。


内部类之所以也是语法糖,是因为它仅仅是一个编译时的概念, outer.java 里面定义了一个内部类 inner。
一旦编译成功,就会生成两个完全不同的 .class 文件了,分别是 outer.class 和 outer$inner.class 。


public class OutterClass {private String userName;public String getUserName()  {return userName ;}public void setUserName(String userName) {this .userName = userName;}public static void main(String[] args) {}class InnerClass {private String name;public String getName() {return name;}public void setName(String name) {this .name = name ;}}
}

以上代码编译后会生成两个class文件: outterClass$InnerClass.class、OutterClass.class 。


当我们尝试对 outterClass.class 文件进行反编译的时候,命今行会打印以下内容:



Parsing 0utterClass.class…Parsing inner class outterClass$InnerClass.class… Generating 0utterClass.jad 。


他会两个文件全部进行反编译,然后 起生成一个 utterclass.jad 文件。文件内容如下:


public class OutterClass {class InnerClass {public String getName() {return name ;}public void setName(String name) {this .name = name ;}private String name;final OutterClass this$0;InnerClass() {this.this$0 = OutterClass.this;super();}}public OutterClass() {}public String getUserName( ) {return userName;}public void setUserName(String userName) {this .userName = userName;}public static void main(String args1[]) {}private String userName ;
}

2.7✅糖块七、条件编译


解析:
一般情况下,程序中的每一行代码都要参加编译。但有时候出于对程序代码优化的考虑,希望只对其中一部分内容进行编译,此时就需要在程序中加上条件,让编译器只对满足条件的代码进行编译,将不满足条件的代码舍弃,这就是条件编译。


如在C或CPP中,可以通过预处理语句来实现条件编译。其实在Java中也可实现条件编译。我们先来看一段代码:
public class ConditionalCompilation {public static void main(String[] args) {final boolean DEBUG = true;if(DEBUG)System.out.println("Hello,DEBUG!");final boolean ONLINE = false;if (ONLINE) System.out.printIn("Hello,ONLINE!");}
}

反编译后代码如下:


public class ConditionalCompilation {public ConditionalCompilation() {}public static void main(String args[]) {boolean DEBUG = true;System.out.println("Hello,DEBUG!");boolean ONLINE = false;}
}

首先,我们发现,在反编译后的代码中没有 System.out.println(“Hello,ONLINE!”);,这其实就是条件编译。当 if(ONLINE) 为false的时候,编译器就没有对其内的代码进行编译。


所以,Java语法的条件编译,是通过判断条件为常量的i语句实现的。其原理也是Java语言的语法糖。根据if判断条件的真假,编译器直接把分支为false的代码块消除。通过该方式实现的条件编译,必须在方法体内实现,而无法在正整个Java类的结构或者类的属性上进行条件编译,这与C/C++的条件编译相比,确实更有局限性。在Java语言设计之初并没有引入条件编译的功能,虽有局限,但是总比没有更强。


2.8🎖️糖块八、断言


在Java中, assert 关键字是从AVA SE 1.4引入的,为了避免和老版本的Java代码中使用了 assert 关键字导致错误,Java在执行的时候默认是不启动断言检查的 (这个时候,所有的断言语句都将忽略!),如果要开启断言检查,则需要用开关 -enableassertions 或-ea 来开启。

看一段包含断言的代码:


public class AssertTest  {public static void main(String args[]) {int a = 1;int b = 1;assert a == b;System.out.println("公众号: Java");assert a != b :"Java";System.out.printIn("博客: https://blog.csdn.net/Java_Yangxiaoyuan");}
}

反编译之后:


public class AssertTest {public AssertTest() {}public static void main(String args[]) {int a = 1;int b = 1;if(!$assertionsDisabled && a != b)throw new AssertionError();System.out.println(" u516C u4F17\u53F7\UFF1AJava");if(!$assertionsDisabled && a == b){throw new AssertionError("Hollis");}else{System.out.println(" u535A\u5BA2\UFF1Ahttps://blog.csdn.net/Java_Yangxiaoyuan");return;}}static final boolean $assertionsDisabled = !com/hollis/suguar/AssertTest.desiredAssertionStatus();
}

很明显,反编译之后的代码要比我们自己的代码复杂的多。所以,使用了assert这个语法糖我们节省了很多代码.其实断言的底层实现就是if语言,如果断言结果为true,则什么都不做,程序继续执行,如果断言结果为false.则程序抛出AssertError来打断程序的执行。-enableassertions 会设置SassertionsDisabled字段的值。


2.9😊糖块九、数值字面量


在iava 7中,数值字面量,不管是整数还是浮点数,都允许在数字之间插入任意多人下划线。这些下划线不会对字面量的数值产生影响,目的就是方便阅读。


比如:


public class Test  {public static void main(String... args)  {int i = 10_000;System.out.println(i);}
}

反编译后:

public class Test {public static void main(string[] args) {int i = 10000:System.out.println(i);}
}

反编译后就是把 _ 删除了。也就是说 编译器并不认识在数值字面量中的 _ ,需要在编译阶段把它去掉。


2.10💡糖块十、for-each


增强for循环( for-each )相信大家都不陌生,日常开发经常会用到的,他会比for循环要少写很多代码,那么这个语法糖背后是如何实现的呢?


public static void main(string... args)  {String[] strs =["Hollis""公众号: Hollis""博客: www.hollischuang.com"};for (String s : strs) {System.out.println(s);}List<String> strList = Immutablelist.of("Java","公众号: Java","博客: https://blog.csdn.net/Java_Yangxiaoyuan");for (String s : strList) {System.out.println(s);}
}

反编译之后:


public static transient void main(String args[]) {String strs[] = {"Java""\u516C\u4F17\u53F7:Java_yangxiaoyuan""https://blog.csdn.net/Java_Yangxiaoyuan?spm=1000.2115.3001.5343""QQ\uFF1A2439667691"};String args1[] = strs;int i = args1.length;for(int j = 0; j < i; j++) {String s = args1[j];System.out.println(s);}List strList = ImmutableList.of("Java""\u516C\u4F17\u53F7:Java_yangxiaoyuan""https://blog.csdn.net/Java_Yangxiaoyuan?spm=1000.2115.3001.5343""QQ\uFF1A2439667691");String s;for(Iterator iterator = strlist.iterator(); iterator.haslext(); System.out.println(s)) {s = (String)iterator.next();}
}

代码很简单,for-each的实现原理其实就是使用了普通的for循环和迭代器


2.11📑糖块十一、 try-with-resource


Java里,对于文件操作作l0流、数据库连接等开销非常昂贵的资源,用完之后必须及时通过close方法将其关闭,否则资源会一直处于打开状态,可能会导致内存泄露等问题。


关闭资源的常用方式就是在 finally 块里是释放,即调用 close 方法。比如,我们经常会写这样的代码:


public static void main(Stringl] args) {BufferedReader br = nul1;try {String line;br = new BufferedReader(new FileReader("d:  hollischuang.xml"));while ((line = br.readLine()) != nul1) {System.out.println(line);}}catch  (IOException e) {// handle exception} finally {try {if (br != nul1) {br.close();}}catch  (IOException ex)  {// handle exception}}
}

从Java 7开始,jdk提供了一种更好的方式关闭资源,使用 try-with-resources 语句,改写一下上面的代码效果如下:


public static void main(String... args) {try (BufferedReader br = new BufferedReader(new FileReader("d: ) hollischuang.xml"))) {String line;while ((line = br .readLine( )) != nul1) {System.out.println(line);}} catch (IOException e) {// handle exception}
}

看,这简直是一大福音啊,虽然我之前一般使用 IOUtils 去关闭流,并不会使用在 finally 中写很多代码的方式,但是这种新的语法糖看上去好像优雅很多呢。看下他的背后:


public static transient void main(String args[]) {BufferedReader br;Throwable throwable;br = new BufferedReader(new FileReader("d:   xiaoyuan.xml"));throwable = null;String line;try {while((line = br.readline()) != null);System.out.println(line);} catch(Throwable throwable2) {throwable = throwable2 ;throw throwable2;}if(br != null) {if(throwable != nul1) {try {br.close();} catch(Throwable throwable1) {throwable.addSuppressed(throwable1);}}else {br.close();}break MISSING_BLOCK_LABEL_113;Exception exception;exception;if(br != null) if(throwable != null)try {br.close();} catch(Throwable throwable3) {throwable.addSuppressed(throwable3);}else br.close();	throw exception;IOException ioexception;ioexception;}
}

其实背后的原理也很简单,那些我们没有做的关闭资源的操作,编译器都帮我们做了。所以,再次印证了,语法糖的作用就是方便程序员的使用,但最终还是要转成编译器认识的语言。


2.12🟢糖块十二、Lambda表达式


2.12.1🟢Lambda表达式是如何实现的


关于lambda表达式,有人可能会有质疑,因为网上有人说他并不是语法糖。其实我想纠正下这个说法。


Labmda表达式不是匿名内部类的语法糖,但是他也是一个语法糖。实现方式其实是依赖了几个JVM底层提供的lambda相关api。


先来看一个简单的lanbda表达式。遍历一个List:


import java.util.Arrays;  
import java.util.List;  
import java.util.stream.Collectors;  public class LambdaComplexExample {  public static void main(String[] args) {  // 创建一个List集合  List<String> list = Arrays.asList("Apple", "Banana", "Cherry", "Date", "Elderberry");  // 使用Lambda表达式和Stream API处理集合  List<String> filteredList = list.stream()  .filter(s -> s.startsWith("A")) // 过滤以"A"开头的元素  .map(String::toUpperCase) // 将元素转换为大写  .collect(Collectors.toList()); // 收集结果到新的List集合  // 输出结果  filteredList.forEach(System.out::println);  }  
}

使用Stream API来处理集合。首先,我们使用filter方法来过滤出所有以"A"开头的元素。然后,我们使用map方法将每个元素转换为大写形式。最后,我们使用collect方法将结果收集到一个新的List集合中。在最后,我们使用forEach方法来打印出结果集中的每个元素。


总结,Lambda 表达式的实现其实是依赖了一些底层的API,在编译阶段,编译器会把Lambda表达式进行解糖,转换成调用内部api的方式。

三、✅可能遇到的坑

3.1✅泛型

3.1.1 ✅当泛型遇到重载


public class GenericTypes {public static void method(List<String> ist)  {System.out.println("invoke method(List<String> list)");}public static void method(List<Integer> list)  {System.out.println("invoke method(List<Integer> list)");}
}

上面这段代码,有两个重载的函数,因为他们的参数类型不同,一个是List< String> 另一个是List< lnteger>但是,这段代码是编译通不过的。因为我们前面讲过,参数List< String>和List< lnteger>编译之后都被擦除了变成了一样的原生类型List,擦除动作导致这两个方法的特征签名变得一模一样。


3.1.2 ✅当泛型遇到catch


泛型的类型参数不能用在Java是常外理的catch语句中。因为是学外理是电JVM在运行时刻来进行的。由于类型信息被擦除,JVM是无法区分两个异常类型 MyException< String>和 MyException< Integer>的


3.1.3 ✅当泛型内包含静态变量


public class StaticTest {public static void main(stringl] args) {GT<Integer> gti = new GT<Integer>();gti.var=1;GT<String> gts = new GT<String>();gts.var=2;System.out.println(gti.var);}
}class GT<T> {public static int var=0;public void nothing(T x){}
}

以上代码输出结果为: 2! 由于经过类型擦除,所有的泛型类实例都关联到同一份字节码上,泛型类的所有静态变量是共享的。

3.2 ✅自动装箱与拆箱


3.2.1 ✅对象相等比较


public static void main(string[] args) {Integer a = 1000;Integer b = 1000;Integer c = 100;Integer d = 100;System.out.println("a == b is " + (a == b));System.out.println(("c == d is " + (c == d)));
}

输出结果:

在这里插入图片描述

在Java 5中,在Integer的操作上引入了一个新功能来节省内存和提高性能。整型对象通过使用相同的对象引用实现了缓存和重用。


适用于整数值区间-128至+127.




只适用于自动装箱。使用构造函数创建对象不适用。


3.2.2 ✅增强for循环


ConcurrentModificationException


for (Student stu : students) {if (stu.getId() == 2) students.remove( stu) ;
}

会抛出 ConcurrentModificationException 异常。


lterator是工作在一个独立的线程中,并且拥有一个 mutex 锁。lterator被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要跌代的对象,所以按照 fail-fast 原则 lterator 会马上抛出java.util.ConcurrentModificationException 异常。


所以 Iterator 在工作的时候是不允许被跌代的对象被改变的。但你可以使用 iterator 本身的方法 remove()来删除对象,Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。


四、📗总结


本博文介绍了12种Java中常用的语法糖。所冒语法糖就是提供给开发人员便于开发的一种语法而已。但是这种语法只有开发人员认识。要想被执行,需要进行解糖,即转成JVM认识的语法。当我们把语法糖解糖之后,你就会发现其实我们日常使用的这些方便的语法,其实都是一些其他更简单的语法构成的。


有了这些语法糖,我们在日常开发的时候可以大大提升效率,但是同时也要避免过渡使用。使用之前最好了解下原理,避免掉坑。

相关文章:

【昕宝爸爸小模块】深入浅出详解之常见的语法糖

深入浅出详解之常见的语法糖 一、&#x1f7e2;关于语法糖的典型解析二、&#x1f7e2;如何解语法糖&#xff1f;2.1&#x1f7e2;糖块一、switch 支持 String 与枚举2.2&#x1f4d9;糖块二、泛型2.3&#x1f4dd;糖块三、自动装箱与拆箱2.4&#x1f341;糖块四、方法变长参数…...

低代码

腾讯云微搭低代码 WeDa _低代码开发平台_可视化开发平台-腾讯云 首页 - 钉钉宜搭 快速上手多维表格 爱速搭 - 企业应用智能设计平台 | 低代码平台 - 百度智能云 Astro轻应用 Astro Zero_低代码开发平台_软件开发工具_应用开发工具_华为云 低代码是一种软件开发方法&#x…...

2024/1/30 备战蓝桥杯 3-1 栈

目录 小鱼的数字游戏 P1427 小鱼的数字游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 表达式括号匹配 P1739 表达式括号匹配 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 【模板】栈 B3614 【模板】栈 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 小鱼的数字…...

qt setStyleSheet 设置多个属性{}之间用空格间隔

setStyleSheet 设置多个属性时&#xff0c;大属性之间不能用分号&#xff0c;用 空格进行间隔 pbtn1->setStyleSheet("QPushButton {background-color: rgb(4,138,224);font: bold 12pt;color: rgb(255,255,255);} QPushButton:hover,QPushButton:pushed {background-…...

【Node.js基础】Node.js的介绍与安装

文章目录 前言一、什么是Node.js&#xff1f;二、安装Node.js2.1 Windows系统2.2 macOS系统2.3 Linux系统 三、运行js代码总结 前言 随着互联网技术的不断发展&#xff0c;构建高性能、实时应用的需求日益增长。Node.js作为一种服务器端运行时环境&#xff0c;以其事件驱动、非…...

树和二叉树基础

树和二叉树基础 1.1树的概念 树是在数据结构中第一次接触到的非线性结构。 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它 叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&am…...

第十四届蓝桥杯大赛软件赛省赛(C/C++ 大学B组)题解

尝试再做一次&#xff0c;我记得还是有点难&#xff0c;我会尽量多写一点解析&#xff0c;尽量让基础比较弱的友友也能看懂&#xff0c;希望能给你带来帮助 目录 1. 日期统计 题目描述 解题思路 具体代码 2. 01 串的熵 题目描述 解题思路 具体代码 3. 冶炼金属 题目…...

【计算机网络】网络的网络

网络的网络 客户 customer 接入ISP提供商 provider 全球承载ISP多个ISP的层级结构 第一层ISP &#xff08;tier-1 ISP &#xff09; 位于顶部 区域ISP &#xff08;reginal ISP&#xff09;Level 3通信 &#xff0c;AT&T&#xff0c;Sprint &#xff0c;NTT存在点&#x…...

SQL Server 函数参考手册

目录 SQL Server 字符串函数 SQL Server 数值函数 SQL Server 日期函数 SQL Server 高级函数 SQL Server 字符串函数 函数描述ASCII返回特定字符的 ASCII 值CHAR根据ASCII码返回字符CHARINDEX返回子字符串在字符串中的位置CONCAT将两个或多个字符串加在一起Concat with 将…...

NTP时间同步服务器@客户端时钟同步设置

NTP时间同步服务器客户端时钟同步设置 时间同步服务器支持NTP和SNTP网络同步协议&#xff0c;是一款高精度、大容量、高品质的时钟产品。设备采用冗余架构设计&#xff0c;高精度时钟直接来源于北斗、GPS系统中各个卫星的原子钟&#xff0c;通过信号解析驯服本地时钟源&#x…...

flask_django基于python的城市轨道交通公交线路查询系统vue

同时&#xff0c;随着信息社会的快速发展&#xff0c;城市轨道交通线路查询系统面临着越来越多的信息&#xff0c;因此很难获得他们对高效信息的需求&#xff0c;如何使用方便快捷的方式使查询者在广阔的海洋信息中查询&#xff0c;存储&#xff0c;管理和共享信息方面有效&…...

【Spring连载】使用Spring Data访问Redis(四)----RedisTemplate

【Spring连载】使用Spring Data访问Redis&#xff08;四&#xff09;----RedisTemplate通过RedisTemplate处理对象Working with Objects through RedisTemplate 一、专注String的便利类二、Serializers 大多数用户可能使用RedisTemplate及其相应的包org.springframework.data.r…...

WriteFlow写作流GPT应用,激发创意的写作助手

写作是一项充满挑战的任务&#xff0c;有时我们会遇到写作灵感枯竭、思路混乱、语言表达困难等问题。为了帮助人们克服这些困难&#xff0c;我创建了一个名为WriteFlow的写作工具&#xff0c;它是一个基于GPT技术的智能助手&#xff0c;旨在激发创意&#xff0c;提供Prompt提示…...

matlab对负数开立方根得到虚数的解决方案

问题描述&#xff1a;在matlab中&#xff0c;对负数开立方根&#xff0c;不出意外你将得到虚数。 例如 − 27 3 \sqrt[3]{-27} 3−27 ​&#xff0c;我们知道其实数解是-3&#xff0c;但在matlab中的计算结果如下&#xff1a; 问题原因&#xff1a;matlab中的立方根运算是在…...

NFTScan 与 OneID 达成合作伙伴,支持多类型 DID 搜索!

近日&#xff0c;NFT 数据基础设施 NFTScan 与一体化数字身份解决方案 OneID 达成合作伙伴关系&#xff0c;双方将在 NFT 数据层面展开合作。为 Web3 用户带来优质的 NFT 搜索查询交互体验&#xff0c;向更安全和更有效的去中心化生态系统迈出的重要一步。 NFTScan 浏览器现已支…...

c# textbox 提示文字

1. 定义提示文字内容 private readonly string RemarkText "最多输入100字"; // 提示文字 2. 添加textbox 焦点事件&#xff0c; 初始化textbox提示文字和字体颜色 public UserControl(){InitializeComponent();tb_Remark.Text RemarkText;tb_Remark.ForeColor…...

Springfox Swagger3从入门案例

首先&#xff0c;在pom.xml中添加依赖&#xff1a; <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>io…...

HarmonyOS NEXT 星河版项目案例

参考代码&#xff1a;HeimaHealthy: 鸿蒙项目案例练习 (gitee.com) 1.欢迎页面 Entry Component struct WelcomePage {State message: string Hello Worldbuild() {Column({space: 10}) {Row() {// 1.中央slogonImage($r(app.media.home_slogan)).width(260)}.layoutWeight(…...

房屋租赁系统-java

思维导图&#xff1a;业务逻辑 类的存放&#xff1a; 工具类 Utility package study.houserent.util; import java.util.*; /***/ public class Utility {//静态属性。。。private static Scanner scanner new Scanner(System.in);/*** 功能&#xff1a;读取键盘输入的一个菜单…...

docker环境搭建及其安装常用软件

centos安装docker Install Docker Engine on CentOS | Docker Docs 下载docker sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install -y docker-ce docker-ce-cli containerd.io…...

【Spring连载】使用Spring Data访问Redis(三)----连接模式

【Spring连载】使用Spring Data访问Redis&#xff08;三&#xff09;----连接模式Connection Modes 一、Redis Standalone二、向Master写入&#xff0c;从Replica读取三、Redis Sentinel四、Redis Cluster Redis可以在各种设置中运行。每种操作模式都需要特定的配置&#xff0c…...

ppt背景图片怎么设置?让你的演示更加出彩!

PowerPoint是一款广泛应用于演示文稿制作的软件&#xff0c;而背景图片是演示文稿中不可或缺的一部分。一个好的背景图片能够提升演示文稿的整体效果&#xff0c;使观众更加关注你的演示内容。可是ppt背景图片怎么设置呢&#xff1f;本文将介绍ppt背景图片设置的三个方法&#…...

SQL 关键字参考手册(一)

目录 SQL 关键字 SQL ADD 关键字 ADD SQL ADD CONSTRAINT 关键字 ADD CONSTRAINT SQL ALTER 关键字 ALTER TABLE ALTER COLUMN SQL ALTER COLUMN 关键字 ALTER COLUMN SQL ALTER TABLE 关键字 ALTER TABLE SQL ALL 关键字 ALL SQL AND 关键字 AND SQL ANY 关键…...

快速排序|超详细讲解|入门深入学习排序算法

快速排序介绍 快速排序(Quick Sort)使用分治法策略。 它的基本思想是&#xff1a;选择一个基准数&#xff0c;通过一趟排序将要排序的数据分割成独立的两部分&#xff1b;其中一部分的所有数据都比另外一部分的所有数据都要小。然后&#xff0c;再按此方法对这两部分数据分别进…...

指针+一维整型数组的基本运用 和 指针+一维整型数组的初步学习

一&#xff0c;调式程序的技巧&#xff1a; 1.明确问题 2.定位问题 3.加打印&#xff08;打印核心数据0&#xff09; 二&#xff0c;指针的回顾 1.指针的概念&#xff1a;指针就是地址&#xff08;内存单元的编号&#xff09;&#xff0c;是一个数据类型&#xff08;指针类型…...

APP测试基本流程以及APP测试要点总结

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 APP测试实际上依然属于软件测试的范畴&#xff0c;是软件测试的一个真子集&#xff0c;所以经典软…...

GPT-4 Vision调试任何应用,即使缺少文本日志 升级Streamlit七

GPT-4 Vision 系列: 翻译: GPT-4 with Vision 升级 Streamlit 应用程序的 7 种方式一翻译: GPT-4 with Vision 升级 Streamlit 应用程序的 7 种方式二翻译: GPT-4 Vision静态图表转换为动态数据可视化 升级Streamlit 三翻译: GPT-4 Vision从图像转换为完全可编辑的表格 升级St…...

ppt形状导入draw.io

draw.io里面的形状还是有点少&#xff0c;我有时想找一个形状&#xff0c;发现PPT里有&#xff0c;但draw.io里有&#xff0c;比如 也就是这个形状 最简单的想法就是我直接把这个形状在PPT里存成图片&#xff08;png)&#xff0c;然后再导入到draw.io里&#xff0c;但是结果是…...

GoLang和GoLand的安装和配置

1. GoLang 1.1 特点介绍 Go 语言保证了既能达到静态编译语言的安全和性能&#xff0c;又达到了动态语言开发维护的高效率&#xff0c;使用一个表达式来形容 Go 语言&#xff1a;Go C Python , 说明 Go 语言既有 C 静态语言程序的运行速度&#xff0c;又能达到 Python 动态语…...

BGAD文章复现笔记-1

文章名&#xff1a;《Explicit Boundary Guided Semi-Push-Pull Contrastive Learning for Supervised Anomaly Detection》 原作者代码&#xff1a;https://github.com/xcyao00/BGAD 复现过程&#xff1a; 系统Ubuntu22.04, PyTorch1.12.1&#xff0c;python3.9 下载原作者…...