Java表达式的陷阱——关于字符串的陷阱

STM32F103C8T6实战:手把手教你搭建智能火灾报警系统(附MQ-2传感器调试技巧) 本文详细介绍了基于STM32F103C8T6单片机和MQ-2烟雾传感器的智能火灾报警系统搭建过程。从硬件选型、电路设计到软件开发,提供全面的实战指导,特别包含MQ-2传感器调试技巧,帮助开发者快速实现稳定可靠的智能火灾监控系统。 阅读详情

1、关于字符串的陷阱

       字符串是Java程序中使用最广泛的一种对象,虽然它具有简单易用的特征,但是实际使用字符串时也会有一些潜在的陷阱,这些陷阱往往会给实际开发带来潜在的困扰。

1、1 JVM对字符串的处理

     String str = new String("Java对象");
       对于上面常见的Java语句,常见的问题是,上面语句创建了几个字符串?答案是:上面的语句实际上创建了两个字符串对象,其中一个是“Java对象”这个直接量对应的字符串对象,另一个是有new String()构造器返回的字符串对象。
提示:Java程序中创建对象的常见方式有如下四种。
  1. 通过new调用构造器创建Java对象
  2. 通过Class对象的newInstance()方法调用构造器创建Java对象
  3. 通过Java的反序列化机制从IO流中恢复Java对象
  4. 通过Java对象提供的clone()方法复制一个Java对象
       对于java程序中的字符串直接量,JVM会使用一个字符串池来保存它们:当第一次使用某个字符串直接量时,JVM会将它放入字符串池进行缓存。在一般情况下,字符串池中的字符串对象不会被垃圾回收,当程序再次需要使用该字符串时,无须重新创建一个新的字符串,而是直接让引用变量指向字符串池中已有的字符串。
public class StringTest {
	public static void main(String[] args) {
		String str1 = "Java对象";
		String str2 = "Java对象";
		System.out.println(str1 = str2);
	}
}
输出结果:
true
       从输出的结果可以看出,str1和str2都指向JVM字符串池中的"Java对象",同时也可以知道两个变量都是指向同一块内存空间。

       在之前的学习中可以知道,除了通过字符串直接量创建字符串对象之外,还可以通过字符串连接表达式来创建字符串对象。如果这个字符串连接表达式的值可以在编译时确定下来,那么JVM会在编译时计算该字符串变量的值,并让它指向字符串池中对应的字符串。
public class StringJoinTest2 {
	public static void main(String[] args) {
		String str1 = "Java对象的长度:6";
		String str2 = "Java" + "对象" + "的长度:" + 6;
		System.out.println(str1 == str2);
	}
}
输出结果:
true       
       上面程序中的定义的str2是一个字符串连接表达式,但是由于字符串连接表达式可以在编译时就确定下来,因此JVM将在编译时计算str2的值,并让str2指向字符串池中对应的字符串。因此,上面程序最终输出的是true。
注意:在创建str2字符串变量时,它们都是字符串直接量、整数直接量,没有变量参与,没有方法调用。因此,JVM可以在编译时就确定该字符串连接表达式的值,可以让该字符串变量指向字符串池中对应的字符串。但是如果程序使用了变量或者调用了方法,那就只能等到运行时才能确定字符串连接表达式的值,也就无法再编译时就确定该字符串比那辆的值,因此无法利用JVM的字符串池。
public class StringJoinTest3 {
	public static void main(String[] args) {
		String str1 = "Java对象的长度:6";
		String str2 = "Java" + "对象" + "的长度:" + "Java对象".length();
		System.out.println(str1 == str2);
		
		int len = 6;
		String str3 = "Java" + "对象" + "的长度:" + len;
		System.out.println(str1 == str3);
	}
}
输出结果为:
false
false
       上面程序中str2变量对应的连接表达式中包含了一个方法的调用,因此程序无法再编译时确定str2变量的值,也就是不会让str2指向JVM字符串池中对应的字符串。类似地,str3的值也是字符串连接表达式,但由于这个字符串连接表达式中包含了一个len变量,因此str3变量也不会指向JVM字符串池中对应的字符串。
       有一种情况例外,如果字符串连接运算中的所有变量都可以执行“宏替换”,那么JVM一样可以在编译时确定字符串连接表达式的值,一样会让字符串变量指向JVM字符串池中的对应字符串。
public class StringJoinTest4 {
	public static void main(String[] args) {
		String str1 = "Java对象的长度:6";
		final String s1 = "Java";
		String str2 = s1 + "对象" + "的长度:6";
		System.out.println(str1 == str2);
		
		final int len = 6;
		String str3 = "Java" + "对象" +"的长度:" + len;
		System.out.println(str1 == str3);
	}
}
输出结果为:
true
true
总结:当程序中需要使用该字符串、基本类型包装类实例时,应该尽量使用字符串直接量、基本类型值的直接量,避免通过new String()、new Integer()的形式来创建,这样能保证有更好的性能。

1、2 不可变的字符串

       String类是一个典型的不可变类。当一个String对象创建完成后,该String类包含的字符序列就被固定下来,以后永远不能改变。
public class ImmutableString {
	public static void main(String[] args) {
		String str = "Hello";  //①
		System.out.println(System.identityHashCode(str));
		str = str + "Java对象";  //②
		System.out.println(System.identityHashCode(str));
	}
}
输出结果为:
134683287
174240671

       从上面两幅图中可以看出,str变量原来指向的字符串对象并没有发生任何改变,所包含的字符串序列依然是"Hello",只是str变量不再指向它而已。换句话来说,发生改变的不是String对象,而是str变量本身,它改变了指向,指向了一个新的String对象。
注意:System提供identityHashCode()静态方法用于获取某个对象的唯一的hashCode值,这个identityHashCode()方法返回值与该类是否重写了hashCode()方法无关。只有当两个对象相同时,它们的identityHashCode值才会相等。
       对于String类而言,它代表字符串序列不可改变的字符串,因此如果程序需要一个字符序列会发生改变的字符串,应该考虑使用StringBuilder和StringBuffer。实际上通常应该优先考虑使用StringBuilder。StringBuilder和StringBuffer区别在于,StringBuilder是线程不安全的,但StringBuffer是线程安全的,也就是说,其中大部分方法都增加了synchronized修饰符。对方法增加了synchronized修饰符可以保证该线程安全,但是会降低方法执行效率。
public class MutableString {
	public static void main(String[] args) {
		StringBuilder str = new StringBuilder("Hello");
		System.out.println(str);
		System.out.println(System.identityHashCode(str));
		
		str.append("Java对象");
		System.out.println(str);
		System.out.println(System.identityHashCode(str));
	}
}
输出结果为:
Hello
134683287
HelloJava对象
134683287

1、3 字符串比较

       如果程序需要比较两个字符串是否相同,用==进行判断就可以了;但如果要判断两个字符串所包含的字符序列是否相同,则应该使用String重写过的equals()方法进行比较。
//String源代码
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;
}
       从String类源代码来看,字符串底层实际上采用一个字符数组来保存该字符串所包含的字符序列,如果当前面字符串和被比较字符串底层的字符数组所包含的字符序列完全相同,程序通过equals()方法判断两个字符串是否相等就会返回true。
       除此之外,由于String类还实现了Comparable接口,因此程序还可通过String提供的compareTo()方法来判断两个字符串之间的大小。当两个字符串所包含的字符序列相同时,程序通过compareTo()方法比较,将返回0。
public class StringCompare {
	public static void main(String[] args) {
		String s1 = new String("abc");
		String s2 = new String("def");
		String s3 = new String("abc");
		if ( s1.compareTo(s3) == 0 ) {
			System.out.println("s1和s3包含的字符序列相同");
		}
		if( s1.compareTo(s2) < 0 ) {
			System.out.println("s1小于s2");
		}
		System.out.println("s1和s3包含的字符序列相同:" + s1.equals(s3));
		System.out.println("s1和s3包含的字符序列相同:" + (s1 == s3));
	}
}
输出结果为:
s1和s3包含的字符序列相同
s1小于s2
s1和s3包含的字符序列相同:true
s1和s3包含的字符序列相同:false





[终于解决]Ubuntu14.04 32位安装移动网卡(0bda:b711)驱动8188gu tplink-WN726n 大致梳理一下问题解决的流程 首先,在台式机做了双系统,台式机只有一个网线接口,由于项目要求,需要占用网口传输数据,所以用之前买的tplink-WN726n免驱版2.0的移动网卡 【note】免驱版只能在Windows下安装使用,在Ubuntu系统中无法使用,所以,需要另辟蹊径。 找了很多资料,尝试很多方法,有的复杂有的简单,终于解决。 【思路】首先在Ubuntu系统中输入lsusb,查看是否检测到USB网卡设备。然后从Github中复制代码,构建,安装,然后modprobe一下,到前面那步还不行,就再来一步 阅读详情

相关推荐

从FinFET到NanoSheet:一文看懂TSMC制程技术的架构革命与性能飞跃

本文深入解析了TSMC从FinFET到NanoSheet的制程技术架构革命。FinFET通过三维立体结构解决了短沟道效应,而NanoSheet采用环绕栅极设计,实现了更强的静电控制与设计灵活性,结合EUV光刻技术,共同推动了芯片性能与能效的飞跃,为下一代AI与高性能计算奠定基石。

i3j4k5的博客 261

C陷阱与缺陷 第1章 词法“陷阱” 1.5 字符与字符串

C陷阱与缺陷 第1章 词法“陷阱” 1.5 字符与字符串

weixin_客子光阴的博客 167

第5.2章 【自动驾驶行业融合定位核心】:手把手详解ESKF(误差卡尔曼滤波)理论公式及代码

自动驾驶定位中的ESKF(误差卡尔曼滤波)技术是解决IMU累积误差的关键,通过分离名义状态与误差状态实现高精度定位。其核心步骤包括:1)名义状态递推(位置/速度/姿态的基础物理计算);2)误差传播建模(雅可比矩阵F量化误差影响);3)协方差更新(评估定位不确定性)。ESKF在GNSS信号丢失(如隧道场景)、无卫星定位(地下车库)等场景发挥重要作用,通过融合多传感器数据维持定位精度。工程实现需解决零偏校准、协方差投影等关键问题,噪声参数需通过数据标定而非随意设置。掌握ESKF原理与实现是自动驾驶定位工程师的核

行知SLAM 644

【学习笔记】C缺陷与陷阱

优先级比单目运算符要低的,接下来就是双目运算符,在双目运算符中,算术运算符的优先级最高,移位运算符次之,关系运算符再次之,接着是逻辑运算符,赋值运算符,最后是条件运算符;在所有的运算符中,逗号运算符的优先级最低;典型的链接器把编译器或汇编器生成的若干个目标模块,整合成一个被称为载入模块或可执行文件的实体,该实体能够被操作系统直接执行,其中某些目标模块是直接作为输入提供给链接器的;答:一个异常终止的程序可能没有机会来清空其输出缓冲区,因此,该程序生成的输出可能位于内存的某个位置,但却永远不会被写出了,

364

c语言字符串输入的陷阱

scanf函数的陷阱

qq_42279154的博客 626

C陷阱与缺陷(一)词法“陷阱”、语法“陷阱

编译器中负责将程序分解为一个一个符号的部分,一般称为“词法分析器”。

Exp.Joker 498

Fortify代码扫描:Privacy Violation:Heap Inspection漏洞解决方案

漏洞引发情况: 将敏感数据存储在 String 对象中使系统无法从内存中可靠地清除数据。 如果在使用敏感数据(例如密码、社会保障号码、信用卡号等)后不清除内存,则存储在内存中的这些数据可能会泄漏。通常而言,String是所用的存储敏感数据,然而,由于String对象不可改变,因此用户只能使用 JVM 垃圾收集器来从内存中清除String的值。除非 JVM 内存不足,否则系统不要求运...

初阶农民工的博客 2万+

java 字符串表达式,等陷阱

1. 关于字符串陷阱 java程序中创建对象的常规方式有如下4种: 通过new()调用构造器创建java对象 通过class对象的newInstance()方法调用构造器创建java对象 通过java的反序列化机制从IO流中恢复java对象 通过java对象提供的clone()方法复制一个新的java对象 除此之外,还允许直接量创建java对象,如 String str="a

yuppies_coldplay的博客 513

Java字符串直接量实参_疯狂Java笔记之表达式中的陷阱

关于字符串陷阱JVM对字符串的处理首先看如下代码:String java=new String("HelloJack");上面创建了两个字符串对象,其中一个是“HelloJack”这个直接量对应的字符串对象,另一个是由new String()构造器返回的字符串对象。对于Java程序中的字符串直接量,JVM会使用一个字符串池来保存它们:当第一次使用某个字符串直接量是,JVM会将它放入字符串池进行缓...

weixin_36146057的博客 166

JAVA面试讲义-表达式中的陷阱

String str1 = "Hello" + "Java" + "长度:" + "Hello Java".length();,当程序再次需要使用的时候,无需重新创建一个新的字符串,而是直接让引用变量指向字符串池中已有的字符串。如果使用final修饰,会进行宏替换,此时在编译时就可以确定下来,也就可以使用JVM字符串池中的值。String str2 = "Hello" + "Java" + "长度:" + len;String str2 = "Hello" + "Java" + "长度:" + len;

weixin_43317933的博客 278

JAVA字符串的split方法有两个陷阱需要注意

JAVA字符串的split方法有两个陷阱需要注意 在开发过程中,我们会碰到一种场景,需要对字符串进行分割,从而得到更具体的信息。 比如下面这个字符串String str = "123455#JAVA编程思想#这是一本JAVA圣经级别的书籍!"; 该字符串包含书籍ID、书籍名称以及简介,三条信息用#号连接在一起。 想要得到这三条信息,我们通常使用split方法: String[] strArray = str.split("#"); for (int i = 0; i < strArray.le

ant0209的博客 4744

java 中的陷阱

java中的陷阱 1.字符串陷阱

Jensen 586

表达式中的陷阱

对于大部分Java程序员来说,总有些难以绕过的错误,也许你第一次犯了这个错误后,第二次还会再犯,因为这些错误具有隐蔽性,我们把这种错误称为陷阱。为了避免错误一犯再犯,我们就需要把这些陷阱记录下来,以免在未来的开发之中踩坑。     表达式Java里最基本的组成单元,但在简单的表达式背后,依然有一些很容易让我们犯错的陷阱

小林同学的daily 489

关于Java表达式中的陷阱

一、字符串陷阱 1.对于对象的创建方式 (1)通过new关键字调用构造器创建Java对象:String a=new String("ltt")->此语句创建了两个Java对象即“ltt”这个直接量对应的字符串对象和new String构造器返回的字符串对象。 (2)通过Class对象的的newInstance方法调用构造器创建Java对象。 (3)通过Java的反序列化机制从IO流中恢复J

NEU_tt的博客 429

No.5 表达式中的陷阱

1. 关于字符串陷阱 JVM对字符串的处理 String java = new String("Java");创建了几个对象? 2个。“Java”直接量对应的字符串对象;new String()构造器返回的字符串对象 java.intern()可以字符串池中的直接量对象。 字符串及基本类型的包装类,Java允许通过直接量的方式来创建对应的Java对象;...

142

表达式陷阱字符串表达式类型,输入法,注释字符,转义字符,正则表达式

1.    表达式中的陷阱1.1  关于字符串陷阱1. 在创建一个String s = new String("java");的时候,JVM会到常量池中去检查看是否有一个"java"对象了,如果没有则在常量池中创建一个。之后会在堆内存中分配了一个空间,放置这个new出来的String对象,形式如下:java.lang.String@123b, 常量池是在编译期生成的,而new一个对象是在运行时进

BornForIT 2510

java循环里面频繁定义string,不建议在for循环中使用"+"进行字符串拼接

1. 字符串拼接字符串,是 Java 中最常用的一个数据类型了。字符串拼接是我们在Java代码中比较经常要做的事情,就是把多个字符串拼接到一起。我们都知道,StringJava中一个不可变的类,所以他一旦被实例化就无法被修改。但是,既然字符串是不可变的,那么字符串拼接又是怎么回事呢?其实,所有的所谓字符串拼接,都是重新生成了一个新的字符串。下面一段字符串拼接代码:其实最后我们得到的s已经是一个新...

weixin_42501904的博客 1375

new String()和toString避雷

曾经有一段时间我一直认为new String()和toString是一样的, 直到一天我遇到了他… byte[] b 将他转化为String类型,使用上面两种方法差距就来了 String s = new String(b); String s1= b.toString; System.out.println(s+" "+s1); 这两个结果打印出来你会发现还是不一样的 Java对象都继承于Object,Object中提供了toString方法,用于简单返回该类的类签名。在Java中,数组也可以看作是一种

yi_shi_tou的博客 266

[提高总结八]new String()引发的问题

今天上班,无意看到了一个网页,又学了个知识点“基原数据”,这两个小时算没白费。 /* 关于new String()引发的问题 var s1 = new String("s1"); 就这么一句话,引发了将近2个小时的试验,所以不得不记录一下~ 问题来源:ide提示:"primitive type object wrapper used"; 意思是"原始类型对象已经被包装

灵眼儿上方 834

jackson 反序列化string_漏洞预警|Jackson远程代码执行高危漏洞分析(CVE201912384)...

漏洞描述近日,HSCERT监测到,国外安全研究员在分析一个使用Jackson库对JSON进行反序列化的应用程序时,发现了一个反序列化漏洞,可以控制要反序列化的类。我们分析复现如何利用此反序列化漏洞来触发服务器端请求伪造(SSRF)漏洞和远程代码执行漏洞(RCE)。漏洞对应的编号为CVE-2019-12384,RedHat的多个分支受该漏洞影响,如下所示:触发条件触发这个Jackson漏洞...

weixin_35128151的博客 812

Java常见漏洞及防护

https://tttang.com/archive/1243/ 0x01 任意文件下载(路径穿越) 0x02 任意文件上传

公众号shadow sock7 4402

TIA博途Wincc中自定义配方画面的具体方法示例.docx

TIA博途Wincc中自定义配方画面的具体方法示例

5185平米五层框架教学楼(计算书、部分建筑、结构图、计算简图).zip毕业设计参考建筑结构CAD计算书土木工程设计图纸资料库下

5185平米五层框架教学楼(计算书、部分建筑、结构图、计算简图).zip毕业设计参考建筑结构CAD计算书土木工程设计图纸资料库下5185平米五层框架教学楼(计算书、部分建筑、结构图、计算简图).zip毕业设计参考建筑结构CAD计算书土木工程设计图纸资料库下5185平米五层框架教学楼(计算书、部分建筑、结构图、计算简图).zip毕业设计参考建筑结构CAD计算书土木工程设计图纸资料库下5185平米五层框架教学楼(计算书、部分建筑、结构图、计算简图).zip毕业设计参考建筑结构CAD计算书土木工程设计图纸资料库下1.合个人学习技术做项目参考合个人学习技术做项目参考2.适合学生做毕业设计项目参考适合学生做毕业设计项目技术参考 3.适合小团队开发项目技术参考适合小团队开发项目技术参考

上一篇: Java的内存回收——内存管理小技巧
下一篇: Java表达式的陷阱——表达式类型的陷阱
Never_Blue
博客等级 码龄9年 5粉丝 49原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值