String、StringBuilder、StringBuffer区别;String底层详解,实例化、拼接、比较;String为什么不可变

文章目录

  • 0、前言
  • 一、String、StringBuilder、StringBuffer区别
  • 二、String简介
    • 2.1 String类特点
    • 2.2 创建String对象、String实例化
      • 2.2.1 实例化方法
      • 2.2.2 String str1="abc"和String str2=new String("abc")区别
    • 2.3 String的比较
    • 2.4 String类的“加法”
    • 2.5 String与基本数据类型转换
    • 2.6 常用方法
  • 三、String不可变
    • 3.1 可变类型与不可变类型
    • 3.2 String为什么不可变
  • 四、StringBuilder与StringBuffer
    • 4.1 底层原理
    • 4.2 Java中各种池:
  • 五、总结

0、前言

  • 我们在开发中经常用到String对象【一个项目中各个地方都有它的身影,你和同事所写的代码,所使用的框架、库、工具包基本都会用到String】。作为使用率最高的对象,java对String做了不少优化,主要分为两方面,一个是使用方式的优化,一个是性能优化

  • 使用方式的优化 体现在:虽然String是对象,但可以不用new来创建,可以直接用""来创建String对象,这种直接声明的方式称为字面量

  • 字面量:字面值。在java中“数据”被称为“字面值”,如18(整型)、8.12(浮点型)、true/false(布尔型)、‘a’/‘中’(字符型)、“a”/“zhangsan”(字符串型)、等都是 字面量。共有5种字面量——整数型字面量、浮点型字面量、布尔型字面量、字符型字面量、字符串型字面量

String name = "zhangsan"; //name为变量,zhangsan为字面量
int a = 18;               //a为变量,18为字面量
float grade = 88.8;       //grade为变量,88.8为字面量

几个专业名词

Java内存模型:分为栈内存、堆内存、方法区(含字符串常量池)

栈、堆:java将内存分为两种:栈内存、堆内存,区别如下

  • 栈中主要存放一些基本数据类型的变量和对象引用;堆中存放由new创建的对象和数组
  • 栈的存储速度比较快,仅次于寄存器,栈数据可以共享;堆中的对象不可共享
  • 栈中的数据大小和生命周期必须是确定的,当没有引用指向数据时 java会自动释放掉为该变量分配的内存空间;堆中的数据大小和生命周期不需要确定,堆中对象由jvm的垃圾回收器负责回收

==、equals:见2.3 String的比较

java内存模型(JDK7之前、JDK7之后)

JDK7之前

在这里插入图片描述

JDK7之后

在这里插入图片描述

一、String、StringBuilder、StringBuffer区别

类型特点适用场景
String不可变,线程安全;执行速度最慢操作少量数据或不需要操作数据
StringBuilder可变,线程不安全;执行速度最快需要频繁操作数据、且不用考虑线程安全
StringBuffer可变,线程安全;性能较低需要频繁操作数据、且需要考虑线程安全

二、String简介

2.1 String类特点

String是Java中的一个内置类,Immutable不可变,即一旦创建String对象,它的值就不能被更改。对String对象的replace、subString、toLowerCase等操作都会返回一个新String对象,故每次操作String时 性能较低、浪费内存空间

String类实现了Serializable接口和Comparable接口,因此可以进行序列化、在网络上传输和比较操作

2.2 创建String对象、String实例化

2.2.1 实例化方法

有两种方式创建String对象:字面量赋值、new关键字

  • 使用字符串字面值创建String对象,如String str = “abc”:java中有个字符串常量池,当创建一个字面量字符串时,JVM首先检查字符串常量池中是否已经存在该字符串,如果存在 则直接返回字符串对象的引用,否则就创建一个新的字符串对象并放入字符串常量池中,最终将该对象的引用赋值给变量str。引用str指向常量池中字符串"abc"的地址,是在常量池中拿值;【字符串常量池中不会存储相同内容的字符串】
    在这里插入图片描述

  • 使用构造函数构建String对象,如String str = new String(“abc”):通过new关键字创建字符串对象,会先检查字符串常量池中是否有相同的字符串,如果有 则拷贝一份放到堆中,然后返回堆中地址;如果没有 就先在字符串常量池中创建"abc"这个字符串,而后再复制一份放到堆中 并把堆地址返回给str。即最终字符串常量池和堆内存都会有这个对象,最后返回的是堆内存的对象引用

在这里插入图片描述

只要使用new方法,不管字符串常量池中是否存在"abc",都会在堆中创建新的对象(注意 和字符串常量池中的"abc"相区分),方式一的效率高于方式二

String str1 = "ab";//产生1个对象放入常量池
String str2 = new String("cd");//创建两个对象,一个在堆,一个在常量池
String str3 = new String("ab");//创建一个对象在堆,由于常量池已经有Hello 不会在常量池中再创建String x = new String("abc");
String y = new String("abc");
System.out.println(x == y);//结果为false

在这里插入图片描述

2.2.2 String str1="abc"和String str2=new String(“abc”)区别

经过上文讲解,我们就知道两者区别在于 创建对象个数不同

  • String str=“abc"创建了几个对象? 0个 或 1个。如果字符串常量池中没有"abc”,则在常量池中创建"abc" 并让str引用指向该对象(1个);如果字符串常量池中有"abc",则一个都不创建 直接返回地址值给str(0个)
  • String str=new String(“abc”)创建了几个对象? 1个 或 2个。如果字符串常量池中没有"abc",则在字符串常量池和堆内存中各创建一个对象,返回堆地址(2个);如果常量池中有"abc",则只在堆中创建对象并返回地址值给str(1个)。【new相当于在堆中新建了value值,每new一个对象就会在堆中新建,地址值也因此不同,堆中的value存储着指向常量池的引用地址】

由于new关键字会在堆中开辟空间,因此开发中一般不建议使用,直接用字面量形式赋值即可。

在这里插入图片描述

2.3 String的比较

基本数据类型 “==” 比较的是数据值;引用类型 “==” 比较的是地址是否相同

String作为引用类型,可通过 == 和 equals 来进行比较。

查看Object源码 发现equals也是调用"==" 判断地址是否相同。即在根类Object中,== 和 equals 时等价的,子类可重写equals方法,若未重写 则默认"equals"和"=="等价

public class Object{//...public boolean equals(Object obj) {return (this == obj);}//...
}

而String中的equals方法是被重写过的,当String调用equals时 会比较字符串内容是否相同。

public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {public boolean equals(Object anObject) {if (this == anObject) {return true;}if (anObject instanceof String) {String anotherString = (String)anObject;int n = value.length;if (n == anotherString.value.length) {char v1[] = value;char v2[] = anotherString.value;int i = 0;while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}return false;}
}

上述也是面试常见的一个问题:“==” 和 “equals” 的区别。很多人会回答 引用类型"==" 比较地址、"equals"比较值,这是错误的说法。Object的equals方法比较的是对象的内存地址、而String的equals方法比较的是对象的值。String的equals比较值 是因为String类重写了equals方法;类可重写equals方法,如果类没有重写equals方法,会使用根类Object的equals方法,此时equals和==等价

2.4 String类的“加法”

C++中是允许开发者重载操作符的,但是Java中并不允许,官方仅提供了对于String类的 “+” 和 “+=” 两个特殊重载,“+” 将两个字符串连接生成一个新的对象,即在内存中新开辟了一块空间。

为什么String对象能使用 “+” 操作符?毕竟String不是Java8大基本数据类型和对应的装箱类型,而是引用类型,它能够使用 “+” 是因为官方做了处理。

@Test
public void testString() {String str1 = "ab";String str2 = "cd";String str3 = "ab" + "cd";String str4 = "abcd";System.out.println("str3==str4:" + (str3==str4));  //true//底层String temp = (new StringBuilder()).append(str1).append("cd").toString();String str5 = str1 + "cd";System.out.println("str5==str4:" + (str5==str4));  //false//底层 String temp1 = (new StringBuilder()).append(str1).append(str2).toString();String str6 = str1 + str2;System.out.println("str6==str4:" + (str6==str4));  //falsestr5 = str5.intern();  //将str5放进常量池,并将引用赋给原来的str5System.out.println("str5==str4:" + (str5==str4));  //true
}
  • 当使用"+“对两个字符串常量拼接时,该结果在编译期就确定了,由于”+“两边都是常量、因此会直接连接放入常量池,注意不会将”+"两边的常量放入常量池
  • 当"+"两边有变量时,其结果无法在编译期间确定,只能在运行时知道,并不会像上面一样连接放入常量池,反而将结果放在堆中。怎么将运行时动态的变量放入常量池呢?可使用String提供的native的intern()方法,将调用它的对象尝试放入常量池,如果常量池已有该字符串 就返回指向常量池中的引用,如果没有就放入常量池 并返回指向常量池中的引用

当进行字符串拼接时 String str = “ab”+“cd”,其底层会创建StringBuilder对象并调用StringBuilder的append方法追加字符串,而后使用toString()方法将对象转为String

在这里插入图片描述

字符串拼接操作的总结

  • String str1 =“ab”+“cd”:常量 与 常量 的拼接结果在 常量池,原理是 编译期 优化;常量池 中不会存在相同内容的常量;
  • String str2 = str1+“ef”, String str6 = str1+str2:只要其中一个是变量,结果就在堆中。
  • 变量拼接的原理 是StringBuilder 。
  • 如果拼接的结果调用 intern() 方法,则主动将常量池中 还没有的字符串对象放入池中,并返回地址。

2.5 String与基本数据类型转换

在这里插入图片描述

UTF-8用三个二进制数据存储汉字,gbk用两个二进制数据存储汉字

在这里插入图片描述

2.6 常用方法

length()、isEmpty()、charAt(int index)、substring(int beginIndex[, int endIndex])、equals(Object obj)、equalsIgnoreCase(String anotherString)、indexOf(String str)、toUpperCase()、toLowerCase()

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

三、String不可变

按照常规方式创建对象时,即使对象属性安全一致、也会创建多个对象,资源浪费 ——》希望资源复用,声明静态常量 public static final xx,但是如果要复用一万个无规律的对象呢 ——》java提出 对象池 的概念,对象池就像一个缓存,池中存放资源

User u1 = new User("zhangsan", 10);
User u2 = new User("zhangsan", 10);
Sout(u1==u2); //false

在这里插入图片描述

JVM提供了字符串常量池,位于堆中

String不可变,指的是 对象本身的属性或数据不会改变,即一个对象创建后,其值不能改变(但可以修改指向),任何修改操作都会创建一个新的对象。将变量重新赋值 是创建了一个新对象、然后将新对象的引用赋值给了变量,之前的对象是没有受到影响的

public static void main(String[] args) {String str1 = "abc";str1 = "xyz";System.out.println(str1);   //xyz
}

再次给s赋值时,并不是对原来堆中实例对象进行重新赋值,而是生成一个新的实例对象,并且指向“def”这个字符串,s则指向最新生成的实例对象,之前的实例对象仍然存在,如果没有被再次引用,则会被垃圾回收。

在谈String不可变之前,我们先了解一下Java中的不可变对象

3.1 可变类型与不可变类型

1)改变一个变量、改变一个变量的值 有何区别

  • 改变一个变量:将该变量指向另一个存储空间 ——修改指向
  • 改变一个变量的值:将该变量当前指向的存储空间中写入一个新的值 ——修改存储内容

2)可变类型与不可变类型

  • 不可变数据类型(immutable):一旦被创建,其值不能改变(但可以修改指向),任何修改操作都会创建一个新的对象。如果想要改变数据的内容,只能改变对地址的引用,即指向其他地址。 不可变类型是线程安全的;但在频繁修改值的时候往往要开辟很多另外的地址,造成大量空间冗余
  • 可变数据类型(mutable):拥有方法可以修改自己的值/引用。 方便值的频繁修改,但程序安全性无法得到保障

一般情况下,java中基本数据类型(int/long/float等)、包装类、String、BigInteger、BigDecimal、Enum枚举类型、LocalDate/LocalTime/LocalDateTime等日期时间类均为不可变类型;

而StringBuilder、StringBuffer、ArrayList、List、Set、Map均为可变类型

String name = new String("Jenny");
Integer age = new Integer(18);
//String、Integer类没有提供修改对象的方法

我们可自定义 不可变类。需遵守如下规则:类声明为final,以防止被继承;将类的所有成员变量被声明为private final,以确保字段在对象创建后不可被修改;仅为成员变量提供getter方法,不提供改变成员变量的方法;不提供字段的公共方法,或者在提供访问方法时,返回字段的拷贝而不是直接返回字段本身

  • 对于基本类型来说,不可变 指 变量当中的数据不可改变;
  • 对于引用类型来说,不可变 指 对象本身的属性或数据不会改变,即一个对象重新创建后,不能对该对象进行任何更改。将变量重新赋值 是创建了一个新对象、然后将新对象的引用赋值给了变量,之前的对象是没有受到影响的。

3)引用的不可变

不可变类型的值已经不可再改变,但可以修改指向。如果我们想进一步让变量恒定成常量,则必须实现变量的引用不可变,即指向地址的指针不可变,我们只需要用final关键字修饰变量即可。final 限定变量的引用指向一个地址,不可修改

final限制了变量的引用不可更改,但没有限制 引用指向的地址中的数据的修改

  • final + 基本数据类型/不可变的引用数据类型:如final int —— 不可修改该变量
  • final + 可变的引用数据类型:final List——只限制了引用不可更改,但并未限制 引用指向的地址中的数据的修改

3.2 String为什么不可变

查看源码,String底层使用的 private final char value[]

public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {/** The value is used for character storage. */private final char value[];//...
}    
  • 因为final关键字? 不对。被final修饰只能表示 它不可指向新的数组,又不能代表数组本身的数据不可被修改
  • 真正不可变的原因时因为private关键字、并且String没有暴露和提供任何修改字符数组的方法,一些字符串操作都是返回新的String对象 不会影响原来数据。获取其底层字符数组时 都是复制一个新数组进行返回。并且String类型被final修饰,代表其不可被继承,从而杜绝子类覆盖父类行为的可能

String不可变的优缺点——保证字符串常量池发挥作用、哈希码不变 可放心使用与hash相关的对象 HashMap HashSet、不可被对象都是线程安全的

四、StringBuilder与StringBuffer

为解决String操作频繁产生临时对象的问题,Java提出StringBuilder与StringBuffer,两者都可变,即append、delete、replace操作 返回的都是源对象。

两者没有本质区别,两个类的构造器、append/delete/replace/toString等方法也基本相同,主要不同点在:

  • StringBuilder线程不安全、执行效率高
  • StringBuffer线程安全、执行效率低。除非有线程安全的需要,不然还是推荐使用StringBuilder

StringBuilder、StringBuffer的“可变”细节

  • append、insert、replace、delete方法本质上都是调用System.arraycopy()方法,返回源字符串
  • substring(int)、substring(int,int)都是通过new String(value, start, end - start)创建一个新字符串。故在执行substring操作时,String、StringBuilder、StringBuffer基本没区别

4.1 底层原理

查看String、StringBuilder、StringBuffer源码

//String
public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {private final char value[];...
}//StringBuilder
public final class StringBuilderextends AbstractStringBuilderimplements Serializable, CharSequence
{@Overridepublic StringBuilder append(Object obj) {}...
}//StringBuffer
public final class StringBufferextends AbstractStringBuilderimplements Serializable, CharSequence
{//方法有synchronized关键字@Overridepublic synchronized StringBuffer append(Object obj){...}...
}
  • StringBuilder、StringBuffer都继承自AbstractStringBuilder,
  • 查看AbstractStringBuilder源码,发现其底层利用可修改的char数组(JDK 9以后是byte数组),该类里面也包含了append、delete、replace、toString基本操作。
  • StringBuilder、StringBuffer继承AbstractStringBuilder,覆盖实现基本方法,区别仅在于最终的方法是否加了synchronized关键字。StringBuffer类中的增删改方法都添加了synchronized,每次操作字符串时都会加锁,所以线程安全、但是性能低

在这里插入图片描述

abstract class AbstractStringBuilder implements Appendable, CharSequence {char[] value;public AbstractStringBuilder append(Object obj) {return append(String.valueOf(obj));}...
}

4.2 Java中各种池:

池相当于一个共享资源,是对资源的整合和调配,节省存储空间,当需要的时候可以直接在池中取,用完之后再还回去。比如,如果你喝水,你可以拿杯子去水龙头接。如果很多人喝水,那就只能排队去接。现在有了池,每个人到池里舀一杯就好,省去了等着水龙头出水的时间。

Java中常用的池都有:常量池、线程池、数据库连接池

  • 常量池:常量池在java用于保存编译期已确定的,已编译的class文件中的一份数据。它包括了关于类、方法、接口中的常量,也包括字符串常量。常量在编译器赋值时,会先在常量池中检测是否有这个值,若存在直接返回该值的地址值给常量,若不存在则先在常量池中创建该值,再返回该值的地址给常量。因此常量池中不可能出现相等的数据。

常量池的好处:常量池是为了避免频繁的创建和销毁对象而影响系统性能,实现了常量池中的内容由对象共享。例如字符串常量池,在编译阶段就把所有的字符串文字放到一个常量池中。节省内存空间:常量池中所有相同的字符串常量被合并,只占用一个空间。节省运行时间:比较字符串时,双等比equals()快。对于两个引用变量,只用==判断引用是否相等,也就可以判断实际值是否相等。

整数常量池 [-128,127]:将[-128, 127]之间256个整数所有的包装对象提前创建好。如果一个整数范围在[-128, 127]里面的整数进行包装,包装时不需要再new对象了,直接从“整数常量池”中取出来

字符串常量池

  • 线程池:ThreadLocal。

先判断线程池中的核心线程们是否空闲,如果空闲,就把这个新的任务指派给某一个空闲线程去执行。如果没有空闲,并且当前线程池中的核心线程数还小于 corePoolSize,那就再创建一个核心线程。

如果线程池的线程数已经达到核心线程数,并且这些线程都繁忙,就把这个新来的任务放到等待队列中去。如果等待队列又满了,那么查看一下当前线程数是否到达maximumPoolSize,如果还未到达,就继续创建线程。如果已经到达了,就交给RejectedExecutionHandler来决定怎么处理这个任务。

  • 连接池

五、总结

String、StringBuilder、StringBuffer区别:

  • String为字符串常量,不可变、线程安全
  • StringBuilder、StringBuffer均为字符串变量、可变,其中StringBuilder线程不安全、StringBuffer线程安全。StringBuffer和StringBuilder可通过toString()方法转换成String类型。执行速度:StringBuilder > StringBuffer > String
  • 操作少量的字符串 用String; 单线程下需要操作大量数据 用StringBuilder;多线程下需要操作大量数据 用StringBuffer

字符串拼接操作:

  • 常量 与 常量 的拼接结果在 常量池,原理是 编译期 优化;常量池 中不会存在相同内容的常量
  • 只要其中一个是变量,结果就在堆中
  • 变量拼接的原理 是StringBuilder
  • 如果拼接的结果调用 intern() 方法,则主动将常量池中 还没有的字符串对象放入池中,并返回地址

String有两种实例化方法:字面量赋值、new关键字

String str1="abc"和String str2=new String(“abc”)区别:创建对象不同

  • String str=“abc"创建 **0个 或 1个 **对象?。如果字符串常量池中没有"abc”,则在常量池中创建"abc" 并让str引用指向该对象(1个);如果字符串常量池中有"abc",则一个都不创建 直接返回地址值给str(0个)
  • String str=new String(“abc”)创建 1个 或 2个 对象。如果字符串常量池中没有"abc",则在字符串常量池和堆内存中各创建一个对象,返回堆地址(2个);如果常量池中有"abc",则只在堆中创建对象并返回地址值给str。【new相当于在堆中新建了value值,每new一个对象就会在堆中新建,地址值也因此不同,堆中的value存储着指向常量池的引用地址】

参考 尚硅谷, https://zhuanlan.zhihu.com/p/374043874, https://blog.csdn.net/xiaojin21cen/article/details/106404531, https://blog.csdn.net/weixin_51611639/article/details/124673007, https://blog.csdn.net/qq_44614137/article/details/120046675

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

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

相关文章

【youcans电力电子仿真 03】Boost变换电路

【youcans电力电子仿真 03】Boost变换电路 Boost变换电路是Buck变换电路的对偶拓扑&#xff0c;也属于非隔离型直流变换器&#xff0c;其输出电压大于输入电压。Boost变换电路具有效率高、输出稳定、控制简单和成本低的优点&#xff0c;广泛应用于电子设备、光伏发电、无线通信…

了解MySQL InnoDB多版本MVCC(Multi-Version Concurrency Control)

了解MySQL InnoDB多版本MVCC&#xff08;Multi-Version Concurrency Control&#xff09; 在数据库管理系统中&#xff0c;多版本并发控制&#xff08;MVCC&#xff09;是一种用于实现高并发和事务隔离的技术。MySQL的InnoDB存储引擎支持MVCC&#xff0c;这使得它可以在提供高…

伪分布Hadoop下安装Hive

一、下载并安装Mysql &#xff08;1&#xff09;下载mysql安装包&#xff08;mysql-8.0.26-1.el7.x86_64.rpm-bundle.tar&#xff09; 下载官网&#xff1a;MySQL :: Download MySQL Community Server (Archived Versions)https://downloads.mysql.com/archives/community/ &…

Linux-用户管理类命令实训

掌握Linux各类命令的使用方法。熟悉Linux操作环境。掌握常用文件目录类命令掌握常用系统信息类命令了解其他常用命令 一、文件与目录管理 &#xff08;1&#xff09;查看根目录下有哪些内容 &#xff08;2&#xff09;进入/tmp目录&#xff0c;以自己的学号建一个目录&#x…

HTML部分常用标签补充

table&#xff08;布局方面不建议使用&#xff0c;而是使用CSS来完成&#xff09;: 标签解释&#xff1a; ~table标签顾名思义&#xff0c;是表格的意思 ~table其中可以使用boder属性来显示表格的线&#xff0c;最好使用CSS来配合HTML的使用 ~table内的内容可以使用colspan来定…

Vue2slot插槽(理解与应用)

1、插槽的概念 插槽&#xff08;Slot)是vue为组件的封装者提供的能力。允许开发者在封装组件时&#xff0c;把不确定的、希望由用户指定的部分定义为插槽。 举个例子&#xff1a;组件好比小霸王游戏机&#xff0c;插槽就是游戏机的插口&#xff0c;看用户插什么卡&#xff0c;就…

【论文精读】Attention is all you need

摘要 主要的序列转换模型是基于复杂的循环或卷积神经网络&#xff0c;其中包括一个编码器和一个解码器。性能最好的模型还通过一种注意力机制将编码器和解码器连接起来。我们提出了一种新的简单的网络架构&#xff0c;Transformer&#xff0c;完全基于注意机制&#xff0c;完全…

24五一杯资料汇总!!!!

以下内容为23年五一杯内容&#xff0c;24年也将会按时更新资料&#xff01;&#xff01;&#xff01; 问题1&#xff1a;给定建筑物数据&#xff0c;假设该建筑物内温度需要一直保持在18-26度&#xff0c;在温度不适宜的时候要通过电来调节温度&#xff0c;消耗一度电相当于0.…

gazebo中vins-fusion在仿真小车上的部署

软件要求&#xff1a;Ubuntu 20.04 ros的noetic版本&#xff0c;我是在虚拟机vitrualbox上运行的 这几天在学ROS&#xff0c;跟着赵虚左老师过了一遍之后&#xff0c;感觉还是有很多不懂的地方&#xff0c;xtdrone上仿真跟着文档走了一遍&#xff0c;好像没学到什么东西&#…

java解决常见递归问题

最基本的&#xff0c;斐波那契数列&#xff0c;阶乘&#xff08;0&#xff0c;1的阶乘均为1&#xff09; 返回字母“x”第一次出现的位置 使用递归编写一个函数&#xff0c;读取一个字符串&#xff0c;返回字母“x”第一次出现的位置。例如&#xff0c;字符串 "abcdefgh…

Nature Climate Change 高引文章 | 朴世龙院士团队等揭示全球变绿及其驱动因子

植被是生物圈的关键组成部分&#xff0c;对调节地球气候和提供生态系统服务具有重要作用。陆地植被生长对全球变化非常敏感。工业革命以来&#xff0c;大气二氧化碳浓度升高、气候变暖、氮沉降增加和土地利用变化等因子&#xff0c;通过复杂的生物物理化学过程&#xff0c;对陆…

Android开发——Fragment

Demo fragment_blank.xml <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_pare…

如何从零开始创建React应用:简易指南

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

经典目标检测YOLOV1模型的训练及验证

1、前期准备 准备好目录结构、数据集和关于YOLOv1的基础认知 1.1 创建目录结构 自己创建项目目录结构&#xff0c;结构目录如下&#xff1a; network CNN Backbone 存放位置 weights 权重存放的位置 test_images 测试用的图…

Tomcat命令行窗口、IDEA中Tomcat控制台 中文乱码问题解决方案

Tomcat出现中文乱码问题 打开Tomcat文件夹下的conf/logging.properties文件&#xff0c;将下图位置中的编码由UTF-8全部替换成GBK 然后重启Tomcat服务器&#xff0c;问题解决 Intellij IDEA启动Tomcat服务器控制台出现中文乱码 解决方案非常简单&#xff0c;按照下图设置控制…

【MySQL】表的增删改查

目录 前言&#xff1a; 新增&#xff08;Create&#xff09;&#xff1a; 查询&#xff08;Retrieve&#xff09;&#xff1a; 别名&#xff1a; 去重&#xff1a;DISTINCT 排序&#xff1a;ORDER BY &#xff1a; 条件查询&#xff1a;WHERE &#xff1a; 分页查询&am…

c++实数排序

例&#xff1a;数的三次方跟 描述&#xff1a;给定一个浮点数n&#xff0c;求它的三次方根。 输入描述&#xff1a;一个浮点数 输出描述&#xff1a;问题的解 保留6位小数 #include<bits/stdc.h> using namespace std; double n,eps1e-8; bool check (double x){retu…

【新手入门必看】从零开始学指针

我使用VS CODEMSYS2的编译环境进行学习&#xff0c;想使用VS CODE进行C/C代码编写的小伙伴参考这篇文章进行环境配置VS Code 配置 C/C 编程运行环境&#xff08;保姆级教程&#xff09; 一、指针的引入 指针地址 #include <stdio.h>int main() {int a 10;printf(&quo…

Git的操作和使用

一、基本操作 1、创建git本地仓库 &#xff08;1&#xff09;创建目录&#xff1a;mkdir gitcode &#xff08;2&#xff09;进入目录&#xff1a;cd gitcode/ &#xff08;3&#xff09;查询目录内容&#xff1a;ls &#xff08;4&#xff09;在当前目录下创建git本地仓库…

java算法day3

移除链表元素设计链表翻转链表两两交换链表中的结点 移除链表元素 ps&#xff1a;有时候感觉到底要不要写特判&#xff0c;你想到了就写&#xff01;因为一般特判有一劳永逸的作用。 解法有两种&#xff0c;一种是不用虚拟头结点&#xff0c;另一种就是用虚拟头结点。 这里我…