【Java基础】String详解
文章目录
- String
- 一、String 概述
- 1、基本特性
- 2、不可变性
- 3、String、StringBuilder、StringBuffer
- 二、字符串 创建与内存分配
- 1、字面量 / 双引号
- 2、new关键字
- 3、StringBuilder.toString()
- 4、intern() 方法
- 5、小结
- 三、字符串 拼接
- 1、常量+常量
- 2、变量 拼接
- 3、final变量 拼接
- 4、拼接小结
- 5、+拼接 vs append拼接
- 6、StringBuilder的扩容
- 7、优化小结
- 四、new String() 会创建几个对象
- 1、单独new
- 2、常量 拼接 new
- 3、new 拼接 new
- 五、intern()
- 1、intern() 的作用
- 2、案例分析
- 1)案例1
- 2)案例2
- 3)案例3
- 3、intern() 的效率:空间角度
- 4、运行时内存案例
String
一、String 概述
1、基本特性
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {// jdk1.8及之前private final char value[];public String() {this.value = "".value;}
}
- String 实现了
Serializable
接口:表示字符串是支持序列化的。 - String 实现了
Comparable
接口:表示 String 可以比较大小。 - String 声明为
final
的,不可被继承,一旦被创建就不会改变,对字符串的操作只是产生了一个新的字符串。 - String 在
jdk8及以前
定义了final char[] value
存储字符串数据,jdk9时
改为final byte[] value
2、不可变性
String 声明为 final
的,一旦被创建就不会改变。String的每次操作都是生成一个新的对象,不改变原来的对象。
例1:重新赋值
@Test
public void test1() {String s1 = "abc";String s2 = s1;System.out.println(s1.hashCode()); // 96354System.out.println(s2.hashCode()); // 96354// 不会改变原来的对象("abc"),只是新生成一个对象("hello"),并指向新对象s2 = "hello";System.out.println(s1.hashCode()); // 96354System.out.println(s2.hashCode()); // 99162322System.out.println(s1); // abcSystem.out.println(s2); // hello
}
例2:拼接操作
@Test
public void test2() {String s1 = "abc";String s2 = s1 + "def";System.out.println(s1); // abcSystem.out.println(s2); // abcdef
}
例3:replace() 方法
@Test
public void test3() {String s1 = "abc";String s2 = s1.replace('a', 'm');System.out.println(s1); // abcSystem.out.println(s2); // mbc
}
例4:方法参数传递
@Test
public void test4() {String str = "old";char[] ch = {'t', 'e', 's', 't'};change(str, ch);System.out.println(str); // oldSystem.out.println(ch); // best
}public void change(String str, char ch[]) {// 拼接和replace同理str = "new";ch[0] = 'b';
}
3、String、StringBuilder、StringBuffer
可变性:
-
String
:使用字符数组
private final char value[]
保存字符串,因此String不可变。 -
StringBuilder
与StringBuffer
:继承于 AbstractStringBuilder,使用字符数组
char[] value
保存字符串,因此这两种对象都是可变的。
线程安全性:
String
:String对象是不可变的,一旦创建后其内容不能更改,线程安全。StringBuffer
:加了synchronized
同步锁,线程安全。StringBuilder
:非线程安全。
性能:
String
:每次对 String 类型进行改变的时候,都会生成一个新的String对象。StringBuffer
:每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。StirngBuilder
:没有加锁操作,比StringBuffer
能获得 10%~15% 左右的性能提升。
使用场景:
- 操作少量数据:
String
- 单线程操作大量数据:
StringBuilder
- 多线程操作大量数据:
StringBuffer
二、字符串 创建与内存分配
1、字面量 / 双引号
直接由双引号
""
给出声明的字符串,存储在字符串常量池中(并且相同的字符串只会存在一份)
public static void test() {String str = "ab";
}
0 ldc #2 <ab>
2 astore_0
3 return
使用双引号""
创建字符串时,JVM会先去常量池中查找是否存在这个字符串对象。
- 不存在:在 字符串常量池 创建这个字符串对象,并返回地址。
- 存在:直接返回 字符串常量池 中 字符串对象的地址。
2、new关键字
new
关键字声明的字符串,先在堆内存中创建一个字符串对象(new
),然后在字符串常量池中创建一个字符串常量(ldc
)。
public static void test() {String s1 = new String("ab");String s2 = "ab";
}
0 new #3 <java/lang/String>3 dup4 ldc #2 <ab>6 invokespecial #4 <java/lang/String.<init> : (Ljava/lang/String;)V>9 astore_0
10 ldc #2 <ab>
12 astore_1
13 return
使用 new 创建字符串时,JVM也会先去常量池中查找是否存在这个字符串对象。
- 不存在:先在堆内存中创建一个字符串对象,然后在字符串常量池中创建一个字符串常量。
- 存在:直接在堆内存中创建另一个字符串对象。
注意:最后返回的是堆内存中字符串对象的地址,不是常量池中的字符串对象的地址。
public static void test() {String s1 = new String("ab");String s2 = "ab";System.out.println(s1 == s2); // false
}
3、StringBuilder.toString()
从下面的源码可以看到,StringBuilder
的toString()
其实会new
一个String
对象
public final class StringBuilder extends AbstractStringBuilder implements Serializable, CharSequence {@Overridepublic String toString() {// Create a copy, don't share the arrayreturn new String(value, 0, count);}
}
需要注意的是,StringBuilder.toString()
不会在常量池中创建对象,下面写个例子分析一下。
public static void test() {StringBuilder stringBuilder = new StringBuilder("a");stringBuilder.append("b");String str = stringBuilder.toString();
}
0 new #5 <java/lang/StringBuilder>3 dup4 ldc #6 <a>6 invokespecial #7 <java/lang/StringBuilder.<init> : (Ljava/lang/String;)V>9 astore_0
10 aload_0
11 ldc #8 <b>
13 invokevirtual #9 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>
16 pop
17 aload_0
18 invokevirtual #10 <java/lang/StringBuilder.toString : ()Ljava/lang/String;>
21 astore_1
22 return
可以看到没有出现 ldc #x <ab>
,可见StringBuilder.toString()
只在堆内存创建了一个字符串,并没有放到字符串常量池
4、intern() 方法
intern()
判断常量池中是否存在该字符串,存在,则返回常量池中的地址;不存在,则在常量池中加载一份并返回地址
@Test
public void test() {String s1 = "nb";String s2 = "n";String s3 = s2 + "b";String s4 = s3.intern(); // 常量池中存在,返回常量池中的地址System.out.println(s1 == s3); // falseSystem.out.println(s1 == s4); // true
}
关于intern()
方法下面会详细展开。
5、小结
什么情况下,字符串会被放入 字符串常量池 呢?
- 直接由双引号
""
给出声明的字符串,会直接放在字符串常量池中。 - 使用
new
创建的字符串,也会有一份放在字符串常量池中。 - 调用
intern()
方法的字符串,也会被放到字符串常量池中。
注意:StringBuilder.toString()
生成的字符串,是不会放到字符串常量池中的,只会在堆中创建一份。
三、字符串 拼接
1、常量+常量
场景1:
常量
与常量
拼接,拼接结果在字符串常量池,原理是编译期优化
public class AppendTest {public void test() {String s1 = "a" + "b" + "c";String s2 = "abc";System.out.println(s1 == s2); // true}
}
从 class文件 的 反编译结果 可以看出:编译器做了优化,将 "a" + "b" + "c"
优化成了 "abc"
0 ldc #2 <abc>2 astore_03 ldc #2 <abc>5 astore_16 getstatic #3 <java/lang/System.out : Ljava/io/PrintStream;>9 aload_0
10 aload_1
11 if_acmpne 18 (+7)
14 iconst_1
15 goto 19 (+4)
18 iconst_0
19 invokevirtual #4 <java/io/PrintStream.println : (Z)V>
22 return
从 IDEA 的 AppendTest.class 也可以直接看出来
public class AppendTest {public AppendTest() {}public void test() {String s1 = "abc"; // 显示 String s1 = "abc"; 说明做了代码优化String s2 = "abc";System.out.println(s1 == s2);}
}
2、变量 拼接
场景2:拼接中只要有一个是
变量
,拼接结果就在堆中,原理是StringBuilder
的append
操作。
public void test2() {String s1 = "n";String s2 = "b";String s3 = "nb";String s4 = "n" + "b"; // 编译期优化String s5 = s1 + "b";String s6 = "n" + s2;String s7 = s1 + s2;System.out.println(s3 == s4); // trueSystem.out.println(s3 == s5); // falseSystem.out.println(s3 == s6); // falseSystem.out.println(s3 == s7); // falseSystem.out.println(s5 == s6); // falseSystem.out.println(s5 == s7); // falseSystem.out.println(s6 == s7); // false// 这里使用intern(),会返回常量池中"nb"的地址并赋给s8(这里先了解,具体用法后续会详细展开)String s8 = s7.intern();System.out.println(s3 == s8); // true
}
下面我们从 class文件 的 反编译结果 进行分析
0 ldc #5 <n>2 astore_13 ldc #6 <b>5 astore_26 ldc #7 <nb>8 astore_39 ldc #7 <nb>11 astore 4
s4之前都是【例1】的内容,这里就不赘述了,主要看一下 s5、s6、s7 这三行
可以看出,都是先 new 了一个 StringBuilder 对象,然后使用 append() 拼接,最后调用了 toString() 创建 String对象 并赋值
13 new #8 <java/lang/StringBuilder>16 dup17 invokespecial #9 <java/lang/StringBuilder.<init> : ()V>20 aload_121 invokevirtual #10 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>24 ldc #6 <b>26 invokevirtual #10 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>29 invokevirtual #11 <java/lang/StringBuilder.toString : ()Ljava/lang/String;>32 astore 5
34 new #8 <java/lang/StringBuilder>37 dup38 invokespecial #9 <java/lang/StringBuilder.<init> : ()V>41 ldc #5 <n>43 invokevirtual #10 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>46 aload_247 invokevirtual #10 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>50 invokevirtual #11 <java/lang/StringBuilder.toString : ()Ljava/lang/String;>53 astore 6
55 new #8 <java/lang/StringBuilder>58 dup59 invokespecial #9 <java/lang/StringBuilder.<init> : ()V>62 aload_163 invokevirtual #10 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>66 aload_267 invokevirtual #10 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>70 invokevirtual #11 <java/lang/StringBuilder.toString : ()Ljava/lang/String;>73 astore 7
3、final变量 拼接
场景3:
final
修饰的String变量
,视作String常量
。
public static void test3() {final String s1 = "n";final String s2 = "b";String s3 = "nb";String s4 = "n" + "b"; // 编译期优化String s5 = s1 + "b";String s6 = "n" + s2;String s7 = s1 + s2;System.out.println(s3 == s4); // trueSystem.out.println(s3 == s5); // trueSystem.out.println(s3 == s6); // trueSystem.out.println(s3 == s7); // trueSystem.out.println(s5 == s6); // trueSystem.out.println(s5 == s7); // trueSystem.out.println(s6 == s7); // true
}
可以看到,我们只是在String变量前加上final
,结果就完全不同了。
下面我们看一下 class文件 的 反编译结果
0 ldc #6 <n>2 astore_03 ldc #7 <b>5 astore_16 ldc #8 <nb>8 astore_29 ldc #8 <nb>11 astore_312 ldc #8 <nb>14 astore 416 ldc #8 <nb>18 astore 520 ldc #8 <nb>22 astore 6
可以看出,String变量被final
修饰之后,所有的拼接操作都在编译期优化了,而没有使用StringBuilder
4、拼接小结
常量
与常量
拼接:- 拼接结果在字符串常量池,原理是编译期优化
- 拼接中只要有一个是
变量
:- 拼接结果在堆中,原理是 先
new
一个StringBuilder
,然后用append()
拼接,最后调用toString()
返回结果 - 补充说明:在 jdk5 之前使用的是 StringBuffer,在 jdk5 之后,改为了 StringBuilder,
- 拼接结果在堆中,原理是 先
final
修饰的String变量
拼接:- 拼接结果在字符串常量池,仍然使用编译期优化,而非
StringBuilder
。
- 拼接结果在字符串常量池,仍然使用编译期优化,而非
因此,在开发中能使用上final
的时候还是建议使用
5、+拼接 vs append拼接
public class StringAppendTest {public static void main(String[] args) {long start = System.currentTimeMillis();// String s1 = append1(100000); // 1670msString s2 = append2(100000); // 4mslong end = System.currentTimeMillis();System.out.println("拼接花费的时间为:" + (end - start));}public static String append1(int highLevel) {String str = "";for (int i = 0; i < highLevel; i++) {str = str + "a"; // 每次循环都会创建一个StringBuilder、String}return str;}public static String append2(int highLevel) {StringBuilder strBuilder = new StringBuilder();for (int i = 0; i < highLevel; i++) {strBuilder.append("a"); // 只需要创建一个StringBuilder}return strBuilder.toString();}
}
结论:通过StringBuilder
的append()
的方式拼接字符串的效率,远远高于 +
拼接
原因:
StringBuilder
的append()
的方式:- 自始至终中只创建过一个
StringBuilder
的对象。
- 自始至终中只创建过一个
+
拼接的方式:- 每一次 字符串变量 拼接的过程,都会new一个StringBuilder对象(这从之前的反编译结果中也可以看出来)
因此使用字符串变量+
拼接会占用更大的内存,产生大量垃圾字符串,如果发生了GC,也会花费额外的时间。
6、StringBuilder的扩容
StringBuilder 空参构造器的初始化大小为16,超过该大小会进行扩容,涉及数组的copy操作
public StringBuilder() { super(16);
}
如果提前知道需要拼接 String 的长度,就应该直接使用带参构造器指定capacity,以减少扩容的次数
public StringBuilder(int capacity) { super(capacity);
}
7、优化小结
- 允许的情况下尽量使用
final
。这样拼接操作会在编译期优化,而不会创建StringBuilder对象去append。 - 使用
StringBuilder
的append()
效率要高于使用+
拼接。 - 如果知道最终的字符串长度,应该使用带容量的构造器创建
StringBuilder
,避免频繁扩容。
四、new String() 会创建几个对象
1、单独new
场景1:
new String("ab")
会创建几个对象?(答案是2个)
0: new #2 // class java/lang/String3: dup4: ldc #3 // String ab6: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V9: astore_1
10: return
对象1 new String("ab")
对象2 常量池中的"ab"
2、常量 拼接 new
场景2:
"a" + new String("b")
会创建几个对象?(答案是5个)
0: new #2 // class java/lang/StringBuilder3: dup4: invokespecial #3 // Method java/lang/StringBuilder."<init>":()V7: ldc #4 // String a9: invokevirtual #5 // Method java/lang/StringBuilder.append:
12: new #6 // class java/lang/String
15: dup
16: ldc #7 // String b
18: invokespecial #8 // Method java/lang/String."<init>":(Ljava/lang/String;)V
21: invokevirtual #5 // Method java/lang/StringBuilder.append:
24: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
27: astore_1
28: return
对象1 new StringBuilder()
对象2 常量池中的"a"
对象3 new String("b")
对象4 常量池中的"b"
对象5 StringBuilder.toString() 会 new String("ab")
注意:StringBuilder.toString
不会在 字符串常量池中 生成 "ab"
。
3、new 拼接 new
场景3:
new String("a") + new String("b")
会创建几个对象?(答案是6个)
0: new #2 // class java/lang/StringBuilder3: dup4: invokespecial #3 // Method java/lang/StringBuilder."<init>":()V7: new #4 // class java/lang/String
10: dup
11: ldc #5 // String a
13: invokespecial #6 // Method java/lang/String."<init>":(Ljava/lang/String;)V
16: invokevirtual #7 // Method java/lang/StringBuilder.append:
19: new #4 // class java/lang/String
22: dup
23: ldc #8 // String b
25: invokespecial #6 // Method java/lang/String."<init>":(Ljava/lang/String;)V
28: invokevirtual #7 // Method java/lang/StringBuilder.append:
31: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
34: astore_1
35: return
对象1 new StringBuilder()
对象2 new String("a")
对象3 常量池中的"a"
对象4 new String("b")
对象5 常量池中的"b"
对象6 StringBuilder.toString() 会 new String("ab")
注意:StringBuilder.toString
不会在 字符串常量池中 生成 "ab"
。
五、intern()
intern
是一个native
方法,底层调用的是C的方法
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {public native String intern();
}
1、intern() 的作用
调用intern()
时,会判断 字符串常量池 中 是否已存在当前字符串(通过equals()
方法判断)
- 已存在:返回 字符串常量池 中 已存在的 该字符串对象的地址;
- 不存在:将 该字符串 放入 字符串常量池,并返回 字符串对象的地址(这里jdk7前后略有不同)
JDK1.6中
:会把 调用对象复制一份(新的引用地址),放入常量池
,并返回 新的引用地址。JDK1.7起
:会把 调用对象的引用地址 复制一份(相同的引用地址),放入常量池
,并返回 调用对象的引用地址。
也就是说,任意字符串调用intern()
返回结果所指向的那个类实例,必定和直接以常量形式出现的字符串实例完全相同。
("a"+"b"+"c").intern() == "abc" // true;
intern()
可以确保字符串在内存里只有一份(即字符串常量池中的),可以节约内存空间,加快字符串操作任务的执行速度。
2、案例分析
1)案例1
public void test() {String s1 = new String("a");s1.intern();String s2 = "a";System.out.println(s1 == s2); // jdk6/7/8 false
}
s1
记录的是堆中new String("a")
的地址s2
记录的是字符串常量池中"a"
的地址
2)案例2
public void test() {String s1 = new String("a") + new String("b");s1.intern();String s2 = "ab";System.out.println(s1 == s2); // jdk6 false ; jdk7/8 true
}
s1
记录的是堆中"ab"
的地址(注意,这个"ab"
是StringBuilder.toString()
生成的,没有往常量池里放)s1.intern()
调用这个方法之前,字符串常量池中并不存在"ab"
,所以要把"ab"
放入字符串常量池- jdk6中:字符串常量池中的
"ab"
指向新的地址。 - jdk7起:字符串常量池中的
"ab"
指向的是调用intern()
的s1
的地址
- jdk6中:字符串常量池中的
s2
记录的是字符串常量池中的"ab"
指向的地址
3)案例3
public void test() {String s1 = new String("a") + new String("b");String s2 = s1.intern(); // 常量池没有"ab",会放入System.out.println(s1 == "ab"); // jdk6 false ; jdk7/8 trueSystem.out.println(s2 == "ab"); // jdk6 true ; jdk7/8 true
}
public void test() {String s1 = "ab"; // 常量池中创建一个新的对象"ab"String s2 = new String("a") + new String("b");String s3 = s2.intern(); // 常量池已有"ab",不会再放入System.out.println(s1 == s2); // jdk6/7/8 falseSystem.out.println(s1 == s3); // jdk6/7/8 true
}
3、intern() 的效率:空间角度
public class StringInternTest { static final int MAX_COUNT = 1000 * 10000; static final String[] arr = new String[MAX_COUNT]; public static void main(String[] args) { Integer [] data = new Integer[]{1,2,3,4,5,6,7,8,9,10}; long start = System.currentTimeMillis(); for (int i = 0; i < MAX_COUNT; i++) {
// arr[i] = new String(String.valueOf(data[i%data.length])); // 不用intern 7256ms arr[i] = new String(String.valueOf(data[i%data.length])).intern(); // 使用intern 1395ms} long end = System.currentTimeMillis(); System.out.println("花费的时间为:" + (end - start)); try { Thread.sleep(1000000); } catch (Exception e) { e.getStackTrace(); } System.gc();}
}
- 直接
new
:堆 和 字符串常量池 可能会存在相同的字符串的两个对象。 - 使用
intern()
:保证内存中相同的字符串对象只会有一个。
结论:对于程序中大量使用存在的字符串时,尤其存在很多已经重复的字符串时,使用 intern()
方法能够节省内存空间。
4、运行时内存案例
class Memory {public static void main(String[] args) {int i = 1;Object obj = new Object();Memory mem = new Memory();mem.foo(obj);}private void foo(Object param) {String str = param.toString().intern();System.out.println(str); // java.lang.Object@42a57993}
}
相关文章:

【Java基础】String详解
文章目录 String一、String 概述1、基本特性2、不可变性3、String、StringBuilder、StringBuffer 二、字符串 创建与内存分配1、字面量 / 双引号2、new关键字3、StringBuilder.toString()4、intern() 方法5、小结 三、字符串 拼接1、常量常量2、变量 拼接3、final变量 拼接4、拼…...

cmd命令
常用命令 查看电脑名称: hostname 查看网卡信息: ipconfig 快速打开网络设置界面: control.exe netconnections 或 rundll32.exe shell32.dll,Control_RunDLL ncpa.cpld 打开防火墙设置: wf.msc 指定网卡设置IP地址&#…...

《中文Python穿云箭量化平台二次开发技术11》股票基本信息获取分析及应用示例【前十大股东占股比例提取及分析】
《中文Python穿云箭量化平台二次开发技术11》股票基本信息获取分析及应用示例【前十大股东占股比例提取及分析】 《中文Python穿云箭量化平台》是纯Python开发的量化平台,因此其中很多Python模块,我们可以自己设计新的量化工具,例如自己新的行…...
OSINT技术情报精选·2024年9月第1周
OSINT技术情报精选2024年9月第1周 2024.8.15版权声明:本文为博主chszs的原创文章,未经博主允许不得转载。 1、中国信通院:《大模型落地路线图研究报告(2024年)》 近年来,大模型技术能力不断创出新高,产业应用持续走…...

51单片机应用开发---二进制、十六进制与单片机寄存器之间的关系(跑马灯、流水灯实例)
实现目标 1、掌握二进制与十六进制之间的转换 2、掌握单片机寄存器与二进制、十六进制之间的转换 3、掌握单片机驱动跑马灯、流水灯的原理 一、二进制与十六进制之间的转换 1、二进制 二进制(binary), 是在数学和数字电路中以2为基数的…...

信息安全工程师(6)网络信息安全现状与问题
一、网络信息安全现状 威胁日益多样化:网络攻击手段不断翻新,从传统的病毒、木马、蠕虫等恶意软件,到勒索软件、钓鱼攻击、DDoS攻击、供应链攻击等,威胁形式多种多样。这些攻击不仅针对个人用户,还广泛影响企业、政府等…...

亚数TrustAsia亮相第十四届智慧城市与智能经济博览会,入围“2024数据要素创新应用优秀成果”!
智博会 2024年9月6日至8日,由宁波市人民政府、浙江省经济和信息化厅、中国信息通信研究院、中国电子信息行业联合会、中国电信、中国移动、中国联通主办的2024世界数字经济大会暨第十四届智慧城市与智能经济博览会(以下简称“智博会”)在宁波…...

Linux基础开发环境(git的使用)
1.账号注册 git 只是一个工具,要想实现便捷的代码管理,就需要借助第三方平台进行操作,当然第三平台也是基于git 开发的 github 与 gitee 代码托管平台有很多,这里我们首选 Github ,理由很简单,全球开发者…...

VS Code终端命令执行后老是出现 __vsc_prompt_cmd_original: command not found
VS Code终端命令执行后老是出现 __vsc_prompt_cmd_original: command not found。 如下图(vscode终端中): 解决方案: 1、vim ~/.bashrc 2、在~/.bashrc里面加入命令:unset PROMPT_COMMAND 3、source ~/.bashrc...
春天(Spring Spring Boot)
基本概念 春天 Spring 是用于开发 Java 应用程序的开源框架,为解决企业应用开发的复杂性而创建。 Spring 的基本设计思想是利用 IOC(依赖注入)和 AOP (面向切面)解耦应用组件,降低应用程序各组件之间的耦…...

Oracle EBS AP预付款行分配行剩余预付金额数据修复
系统环境 RDBMS : 12.1.0.2.0 Oracle Applications : 12.2.6 问题情况 AP预付款已验证和自动审批但是未过账已经AP付款但是又撤消付款并且未过账问题症状 AP预付款暂挂: AP预付款行金额(等于发票金额)与分配行金额不相等: 取消AP预付款提示如下:...

【鸿蒙】HarmonyOS NEXT星河入门到实战7-ArkTS语法进阶
目录 1、Class类 1.1 Class类 实例属性 1.2 Class类 构造函数 1.3 Class类 定义方法 1.4 静态属性 和 静态方法 1.5 继承 extends 和 super 关键字 1.6 instanceof 检测是否实例 1.7.修饰符(readonly、private、protected 、public) 1.7.1 readonly 1.7.2 Private …...

Java设计模式—面向对象设计原则(六) ----->合成复用原则(CRP) (完整详解,附有代码+案例)
文章目录 3.6 合成复用原则(CRP)3.6.1 概述3.6.2 案列 3.6 合成复用原则(CRP) 合成复用原则(CRP):Composite Reuse Principle,CRP 又叫: 组合/聚合复用原则(Composition/Aggregate Reuse Principle,CARP)…...

java坏境搭建
目录 安装 步骤1 步骤2 步骤3 步骤4 环境变量 1、在桌面“计算机”或“此电脑”图标上右键,选择“属性”,进入控制面板的计算机系统页面后,点击“高级系统设置”,不同操作系统可能界面不同: 2、点击“环境变量”…...
C#中判断socket是否已断开的方法
代码如下: Socket s new Socket(..); if (s.Poll(-1, SelectMode.SelectRead)) {int nRead s.Receive();if (nRead 0){//socket连接已断开} }参考:C#中判断socket是否已断开的方法...
Python编程 - 异常处理与文件读写
目录 前言 一、异常处理 (一)关键字 (二)捕获多个异常 (三)自定义异常 (四)抛出异常 (五)总结 二、文件读写 (一)打开文件 &…...

【C++】c++ 11
目录 前言 列表初始化 std::initializer_list 右值引用和移动拷贝 左值和右值 左值引用和右值引用的区别 万能引用(引用折叠) 完美转发 默认成员函数控制 列表初始化 在C98中,标准允许使用花括号{}对数组或者结构体元素进行统一的列…...
uni-app 应用名称 跟随系统语言 改变
官方已确认BUG::https://ask.dcloud.net.cn/question/164804 { "name" : "%app.name%",//这里随便写,配置了 locales,name 就不生效了 "appid" : "", "description" : "", "versi…...
【大模型实战篇】高质量数据过滤及一种BoostedBaggingFilter处理方法的介绍
1. 高质量数据过滤 1.1 背景介绍 数据质量对于大模型的训练至关重要,经常会听到一句话:数据决定模型的上限。模型的性能上限通常受到训练数据的质量限制。如果数据集不够好,模型可能无法学习到泛化的特征,导致其在新数据上的表…...

使用Python和Proxy302代理IP高效采集Bing图片
目录 项目背景一、项目准备环境配置 二、爬虫设计与实现爬虫设计思路目标网站分析数据获取流程 代码实现1. 初始化爬虫类(BingImageSpider)2. 创建存储文件夹3. 获取图像链接4. 下载图片5. 使用Proxy302代理IP6. 主运行函数 运行截图 三、总结 项目背景 …...

Python酷库之旅-第三方库Pandas(118)
目录 一、用法精讲 521、pandas.DataFrame.drop_duplicates方法 521-1、语法 521-2、参数 521-3、功能 521-4、返回值 521-5、说明 521-6、用法 521-6-1、数据准备 521-6-2、代码示例 521-6-3、结果输出 522、pandas.DataFrame.duplicated方法 522-1、语法 522-2…...

讨论人机交互研究中大语言模型的整合与伦理问题
概述 论文地址:https://arxiv.org/pdf/2403.19876.pdf 近年来,大规模语言模型发展迅速。它们给研究和教育领域带来了许多变化。这些模型也是对人机交互(HCI)研究过程的有力补充,可以分析定性和定量数据,再…...

OpenCV结构分析与形状描述符(23)确定一个点是否位于多边形内的函数pointPolygonTest()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 进行点在轮廓内的测试。 该函数确定点是在轮廓内、轮廓外,还是位于一条边上(或与顶点重合)。它返回正值&…...

GitLab CI_CD 从入门到实战笔记
第1章 认识GitLab CI/CD 1.3 GitLab CI/CD的几个基本概念 GitLab CI/CD由以下两部分构成。 (1)运行流水线的环境。它是由GitLab Runner提供的,这是一个由GitLab开发的开源软件包,要搭建GitLab CI/CD就必须安装它,因…...

微服务实战系列之玩转Docker(十五)
前言 博主的玩转Docker系列,今天正式开启第十五篇的征程! 在过去的十四篇中,涉及的内容有知识、有原理、有工具、更有实践。当你打开每一篇文章时,均会获得一个特定主题的知识和技巧,助你在云原生的世界里,…...
本地调试spark,访问kerberos鉴权的hdfs、hive
文章目录 准备连接hive的配置申请kerberos tgt在scala项目启动本地spark本地Jupyter Notebook启动pyspark 解决在wsl下进行开发、调试时,需要连接kerberos鉴权的hdfs、hive的问题 准备连接hive的配置 core-site.xml、hdfs-site.xml、yarn-site.xml、hive-site.xml复…...

Ubuntu 安装包下载(以20版本 阿里镜像站为例子)
Ubuntu安装包下载 上一篇文章写了一些国内常用的镜像站,这篇以阿里云镜像站Ubuntu20版本为例。 https://mirrors.aliyun.com/ubuntu-releases/ 1.点击自己想要下载的版本 2.点击以amd64.iso为结尾的文件,这个是安装文件,如果是桌面端&…...

会声会影Corel VideoStudio2025旗舰版最新中文旗舰版新功能讲解及使用会声会影使用教程
会声会影Corel VideoStudio2025旗舰版一款功能丰富的视频编辑软件。具有拖放式标题、转场、覆叠和滤镜,色彩分级、动态分屏视频和新增强的遮罩创建器,超越基本编辑,实现影院级效果。优化分屏剪辑功能,简化多时间轴编辑的工作流程&…...

【人工智能】OpenAI发布GPT-o1模型:推理能力的革命性突破,这将再次刷新编程领域的格局!
在人工智能领域,推理能力的提升一直是研究者们追求的目标。就在两天前,OpenAI正式发布了其首款具有推理能力的大语言模型——o1。这款模型的推出,不仅标志着AI技术的又一次飞跃,也为开发者和用户提供了全新的工具来解决复杂问题。…...

2024年TCGA基因表达数据下载(最新版)
文章目录 前言一、如何使用TCGA数据库获取公共数据?二、使用步骤1.点击Cohort Builder2.数据筛选3. Repository4.数据下载4.1 继续选择筛选条件4.2 添加cart并进入4.3 下载 总结 前言 TCGA 全称 The Cancer Genome Atlas ,即癌症基因组图谱。它是一个大型的癌症研…...