String 常量池问题的几个例子
Java常量字符串String理解
Java常量字符串String理解(2009-10-12 17:11:56)以前关于String的理解仅限于三点:1、String是final类,不可继承;2、String类比较字符串相等时时不能用“ == ”,只能用“equals”;3、String类不可更改。
String使用非常方便,因此一般涉及字符串时都用该类进行字符串处理。
至于String类的类在机制,则极少去探究。
直到读到下面这个例子。
按照我的理解,类X,类Y,类Z中的三个常量字符串属于不同的对象,用== 操作符比较,那么结果必然是false,输出应该为:但实际上输出确是:使我大惑不解。
因此,找了许多资料来看(尤其是C++和Java比较编程,里面解释比较详细),终于逐渐明白了原因。
== 只有在两个比较对象指向同一对象时,其值才为true。
X.strX==Y.strY 与X.strX==Z.strZ 测试结果都为true,说明这三个常量指向的都是同一个对象。
在Java中,String是字符串常量。
由相同序列的字符组成的两个字符串属于同一对象,位于内存中的同一个位置。
每个字符串常量只有一个String对象来表示。
即使这个字符串常量出现在一个程序的不同位置甚至一个程序的不同程序包中。
也就是说,X.strX与Y.strY由于都是同一字符序列,因此指向的肯定是同一对象。
Z.strZ也是如此。
"hell"+"o",两个常量字符串相加后,创建了一个新的字符串常量(这个工作是编译期间完成的),它与X.strX,Y.strY有相同的字符序列,因此指向同一对象。
虽然一个常量表达式将两个字符串常量链接在一起的结果在编译器已完成,但是,这段代码中,s3只能在运行期间创建。
这三条语句所创建的"hello"字符串作为String对象存储在内存中的一个独立位置。
Java提供一个机制,通过String类定义的intern()方法把一个运行时创建的字符串加到字符串常量池(如果它还没有入池)。
String对象真的可以用==比较吗
String对象真的可以⽤==⽐较吗1.⽤==会出现true的情况String str2 = "java";System.out.print(str1==str2);地球上有bai点Java基础的⼈都知道会输出false,因为==⽐较的是引⽤,equals⽐较的是内容值。
不是我忽悠dao⼤家,你们可以在⾃⼰的机⼦上运⾏⼀下,结果是true!原因很简单,String对象被放进常量池⾥了,再次出现“java”字符串的时候,JVM很兴奋地把str2的引⽤也指向了 “java”对象,它认为⾃⼰节省了内存开销。
2.⽤==会出现false的情况不难理解吧呵呵例⼦B:String str1 = new String("java");String str2 = new String("java");System.out.print(str1==str2);看过上例的都学聪明了,这次肯定会输出true!很不幸,JVM并没有这么做,结果是false。
原因很简单,例⼦A中那种声明的⽅式确实是在 String常量池创建“java”对象,但是⼀旦看到new关键字,JVM会在堆中为String分配空间。
两者声明⽅式貌合神离,这也是我把“如何创建字符串对象”放到后⾯来讲的原因。
3.分清楚编译的情况(常量时在初始化对象的时候就编译了)和运⾏时情况(是初始化之后运⾏对象⽰例的时候)⼤家要沉住⽓,还有⼀个例⼦。
例⼦C:String str1 = "java";String str2 = "blog";String s = str1+str2;System.out.print(s=="javablog");再看这个例⼦,很多同志不敢妄⾔是true还是false了吧。
爱玩脑筋急转弯的⼈会说是false吧……恭喜你,你会抢答了!把那个“吧”字去掉你就完全正确。
string 类的intern方法
string 类的intern方法string类的intern方法是Java中非常重要的一个方法,它可以用于字符串的常量池处理。
在本文中,我们将深入探讨这个方法的原理、用法以及它的一些注意事项。
我们来了解一下什么是字符串常量池。
在Java中,字符串常量池是一块特殊的内存区域,用于存储字符串常量。
当我们创建一个字符串常量时,虚拟机会首先在常量池中查找是否存在相同内容的字符串,如果存在,则返回常量池中的引用;如果不存在,则将该字符串添加到常量池中并返回引用。
这种机制可以有效地节省内存空间,提高程序的性能。
而intern方法就是用来实现字符串常量池处理的。
该方法的作用是:如果常量池中已经存在该字符串,则返回常量池中的引用;如果常量池中不存在该字符串,则将该字符串添加到常量池中并返回引用。
简单来说,intern方法可以将一个堆中的字符串对象转移到字符串常量池中,并返回常量池中的引用。
那么,我们该如何使用intern方法呢?在实际开发中,我们可以通过调用字符串对象的intern方法来实现。
例如:```javaString str1 = new String("hello");String str2 = str1.intern();```在上面的代码中,我们首先创建了一个字符串对象"hello",然后通过调用intern方法将该字符串对象转移到了字符串常量池中,并将常量池中的引用赋值给了str2。
这样就可以实现字符串常量池处理了。
需要注意的是,intern方法是一个native方法,它的实现是由Java虚拟机提供的。
在实际使用中,我们应该遵循以下几点注意事项:1. 避免过多使用intern方法:由于字符串常量池是一个全局共享的区域,频繁地调用intern方法可能会导致性能问题。
因此,我们应该在必要的情况下才使用intern方法,避免滥用。
2. 小心字符串对象的创建:由于字符串对象是不可变对象,每次创建都会在堆中产生新的对象。
Java基础-Java中字符串常量详解
Java基础-Java中字符串常量详解--------第⼀个例⼦---------String str1 = "a";String str2 = "b";String str3 = "ab";String str4 = str1 + str2;System.out.println(str3 == str4); //输出结果:false为什么会是false呢?Java中将类似于"Hello"这样的字符串,Jvm在编译期就能确定其值,所以就直接new String("xxx"),并将其存储于常量池中(包括:char、byte、short、int、long、boolean和String类型),所以上⾯的str1、str2、str3 指向的均是常量池中对象;⽽String str4 = str1 + str2就不同了,+号两边(或任意⼀边)是变量,Jvm在编译期是⽆法确定其值的,要等到运⾏期再进⾏处理,处理⽅法为:先⽤str1在堆内存中new⼀个StringBuilder,然后append(str2),然后调⽤toString()将其引⽤赋值给str4,所上⾯的str4指向的是堆内存的⼀个字符串对象,如下图所⽰:--------第⼆个例⼦---------String str1 = "a";String str2 = "b";String str3 = "ab";String str4 = str1 + str2;String str5 = str4.intern();System.out.println(str3 == str5); //输出结果:true这⾥⼜为什么会是true呢?String的intern()⽅法会将该对象的值转到常量池中去,如果字符串池已有同样的值,则直接返回地址,如果没有,则在字符串池中新建⼀个,然后返回地址。
string不可变的原理
string不可变的原理
string不可变的原理:在Java中,String是一个不可变的对象,也就是说,一旦一个字符串被创建,它的值就不能被改变了。
String是通过字符数组实现的,当创建一个String对象时,它的值被存储在一个字符数组中。
这个字符数组在对象创建时被初始化,一旦初始化,它的长度就不能被改变了。
因为String是不可变的,所以每次对字符串进行操作时,都会创建一个新的String对象。
比如,如果我们想把一个字符串中的某个字符替换成另一个字符,那么就需要创建一个新的字符串对象。
这种机制使得String对象更加安全和可靠,因为其他的对象不能修改String对象的值,从而避免了一些潜在的安全问题。
此外,由于String对象是不可变的,所以它们可以被缓存起来以提高性能。
例如,在Java中,字符串常量池中缓存了所有字面量字符串对象。
因此,当创建一个字符串字面量时,它实际上是从字符串常量池中获取的,而不是创建一个新的String对象。
虽然String是不可变的,但是Java中还有一些可变的字符串类,例如StringBuilder和StringBuffer。
这些类提供了修改字符串的方法,并且使用了一些特殊的技术来避免创建过多的中间对象,从而提高了性能。
但是,这些可变的字符串类不适用于多线程环境,因为它们没有同步机制,可能会导致线程安全问题。
string类练习题
string类练习题String类是Java中常用的字符串处理类之一,具有丰富的方法和功能,可以满足各种字符串处理需求。
下面将给出一些关于String类的练习题,帮助读者熟悉和掌握这个类的使用。
1. 字符串长度计算和比较编写一个程序,要求从控制台输入两个字符串,然后分别计算它们的长度并输出。
最后比较这两个字符串的长度,如果相等则输出相等,否则输出不相等。
示例输入:请输入字符串1:Hello请输入字符串2:World示例输出:字符串1的长度为:5字符串2的长度为:5两个字符串长度不相等2. 字符串拼接编写一个程序,要求从控制台输入两个字符串,然后使用String 类提供的方法将这两个字符串拼接在一起,并输出结果。
示例输入:请输入字符串1:Hello请输入字符串2:World示例输出:拼接后的字符串为:HelloWorld3. 字符串查找编写一个程序,要求从控制台输入一个字符串和一个目标子串,然后使用String类提供的方法在输入的字符串中查找目标子串,并输出查找结果(找到返回位置索引,找不到返回-1)。
示例输入:请输入字符串:Hello World请输入目标子串:World示例输出:目标子串在字符串中的位置索引为:64. 字符串切割编写一个程序,要求从控制台输入一个字符串和一个分隔符,然后使用String类提供的方法将输入的字符串按照分隔符进行切割,并输出切割结果。
示例输入:请输入字符串:Hello,World,Java请输入分隔符:,示例输出:切割结果:HelloWorldJava5. 字符串替换编写一个程序,要求从控制台输入一个字符串、一个目标子串和一个替换子串,然后使用String类提供的方法将目标子串在输入的字符串中全部替换为替换子串,并输出替换后的结果。
示例输入:请输入字符串:Hello Java请输入目标子串:Java请输入替换子串:World示例输出:替换后的字符串为:Hello World通过完成以上练习题,读者可以加深对String类的理解和应用,提高字符串处理的能力,为日后在编写Java程序时处理字符串问题提供帮助。
String的Intern方法详解
String的Intern⽅法详解引⾔ 在 JAVA 语⾔中有8中基本类型和⼀种⽐较特殊的类型String。
这些类型为了使他们在运⾏过程中速度更快,更节省内存,都提供了⼀种常量池的概念。
常量池就类似⼀个JAVA系统级别提供的缓存。
8种基本类型的常量池都是系统协调的,String类型的常量池⽐较特殊。
它的主要使⽤⽅法有两种:直接使⽤双引号声明出来的String对象会直接存储在常量池中。
如果不是⽤双引号声明的String对象,可以使⽤String提供的intern⽅法。
intern ⽅法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放⼊常量池中⼀. intern 的实现原理1.JAVA 代码/*** Returns a canonical representation for the string object.* <p>* A pool of strings, initially empty, is maintained privately by the* class <code>String</code>.* <p>* When the intern method is invoked, if the pool already contains a* string equal to this <code>String</code> object as determined by* the {@link #equals(Object)} method, then the string from the pool is* returned. Otherwise, this <code>String</code> object is added to the* pool and a reference to this <code>String</code> object is returned.* <p>* It follows that for any two strings <code>s</code> and <code>t</code>,* <code>s.intern() == t.intern()</code> is <code>true</code>* if and only if <code>s.equals(t)</code> is <code>true</code>.* <p>* All literal strings and string-valued constant expressions are* interned. String literals are defined in section 3.10.5 of the* <cite>The Java™ Language Specification</cite>.** @return a string that has the same contents as this string, but is* guaranteed to be from a pool of unique strings.*/public native String intern();View Code String#intern⽅法中看到,这个⽅法是⼀个 native 的⽅法,但注释写的⾮常明了。
java中Stringnew和直接赋值的区别
java中Stringnew和直接赋值的区别中String new和直接赋值的区别对于字符串:其对象的引⽤都是存储在栈中的,如果是编译期已经创建好(直接⽤双引号定义的)的就存储在常量池中,如果是运⾏期(new出来的)才能确定的就存储在堆中。
对于equals相等的字符串,在常量池中永远只有⼀份,在堆中有多份。
例如:String str1="ABC";和String str2 = new String("ABC");String str1="ABC" 可能创建⼀个对象或者不创建对象,如果"ABC"这个字符串在String池⾥不存在,会在String池创建这个⼀个String对象("ABC").如果已经存在,str1直接reference to 这个String池⾥的对象。
String str2 = new String("ABC") ⾄少创建⼀个对象,也可能两个。
因为⽤到new 关键字,会在heap创建⼀个 str2 的String 对象,它的value 是 "ABC".同时,如果"ABC"这个字符串在java String池⾥不存在,会在java String池创建这个⼀个String对象("ABC").String 有⼀个intern() ⽅法,native,⽤来检测在String pool是否已经有这个String存在。
public String intern()返回字符串对象的规范化表⽰形式。
⼀个初始时为空的字符串池,它由类 String 私有地维护。
当调⽤ intern ⽅法时,如果池已经包含⼀个等于此 String 对象的字符串(该对象由 equals(Object) ⽅法确定),则返回池中的字符串。
否则,将此 String 对象添加到池中,并且返回此 String 对象的引⽤。
【java】【String】new字符串到底创建了几个对象
【java】【String】new字符串到底创建了⼏个对象别再问我 new 字符串创建了⼏个对象了!我来证明给你看!我想所有 Java 程序员都曾被这个 new String 的问题困扰过,这是⼀道⾼频的 Java ⾯试题,但可惜的是⽹上众说纷纭,竟然找不到标准的答案。
有⼈说创建了 1 个对象,也有⼈说创建了 2 个对象,还有⼈说可能创建了 1 个或 2 个对象,但谁都没有拿出⼲掉对⽅的证据,这就让我们这帮吃⽠群众们陷⼊了两难之中,不知道到底该信谁得。
但是今天就⽃胆和⼤家聊聊这个话题,顺便再拿出点证据。
以⽬前的情况来看,关于 new String("xxx") 创建对象个数的答案有 3 种:有⼈说创建了 1 个对象;有⼈说创建了 2 个对象;有⼈说创建了 1 个或 2 个对象。
⽽出现多个答案的关键争议点在「字符串常量池」上,有的说 new 字符串的⽅式会在常量池创建⼀个字符串对象,有⼈说 new 字符串的时候并不会去字符串常量池创建对象,⽽是在调⽤ intern() ⽅法时,才会去字符串常量池检测并创建字符串。
那我们就先来说说这个「字符串常量池」。
字符串常量池字符串的分配和其他的对象分配⼀样,需要耗费⾼昂的时间和空间为代价,如果需要⼤量频繁的创建字符串,会极⼤程度地影响程序的性能,因此 JVM 为了提⾼性能和减少内存开销引⼊了字符串常量池(Constant Pool Table)的概念。
字符串常量池相当于给字符串开辟⼀个常量池空间类似于缓存区,对于直接赋值的字符串(String s="xxx")来说,在每次创建字符串时优先使⽤已经存在字符串常量池的字符串,如果字符串常量池没有相关的字符串,会先在字符串常量池中创建该字符串,然后将引⽤地址返回变量,如下图所⽰:别再问我 new 字符串创建了⼏个对象了!我来证明给你看!以上说法可以通过如下代码进⾏证明:public class StringExample {public static void main(String[] args) {String s1 = "Java";String s2 = "Java";System.out.println(s1 == s2);}}以上程序的执⾏结果为:true,说明变量 s1 和变量 s2 指向的是同⼀个地址。
string intern 方法作用
string intern 方法作用在Java中,String是一个非常常用的类,用于表示字符串。
而String类中的intern方法是一个非常重要的方法,它的作用是返回一个字符串的规范化表示。
当我们创建一个字符串时,Java会在内存中的字符串常量池中创建一个新的字符串对象。
而当我们使用intern方法时,Java会首先检查字符串常量池中是否已经存在该字符串的副本。
如果存在,就返回常量池中的字符串对象;如果不存在,就将该字符串添加到字符串常量池中,并返回该对象的引用。
那么,为什么要使用intern方法呢?使用intern方法有以下几个优点:1. 节省内存空间:由于字符串是不可变的,当我们创建多个相同的字符串时,实际上会占用多个内存空间。
而使用intern方法后,相同的字符串只会在内存中保存一份,节省了内存空间。
2. 提高性能:由于字符串常量池中的字符串是唯一的,所以在进行字符串比较时,可以直接比较字符串的引用,而不需要比较字符串的内容,从而提高了比较的效率。
3. 保证字符串唯一性:由于字符串的常量池具有唯一性,所以使用intern方法可以保证字符串的唯一性,避免了重复的字符串对象。
下面我们通过一个示例来说明intern方法的使用:```javaString s1 = new String("hello"); // 创建一个新的字符串对象String s2 = "hello"; // 直接从字符串常量池中获取字符串对象System.out.println(s1 == s2); // false,s1和s2引用的对象不同System.out.println(s1.equals(s2)); // true,s1和s2引用的对象内容相同String s3 = s1.intern(); // 将s1字符串对象添加到字符串常量池中,并返回该对象的引用System.out.println(s2 == s3); // true,s2和s3引用的对象相同```从上面的示例中可以看出,通过intern方法将s1字符串对象添加到字符串常量池中后,s2和s3引用的对象就是同一个对象了,它们在内存中的地址是相同的。
string类的intern()方法
string类的intern()方法在Java语言中,String类是极其常用的一个类,它代表字符串类型,它有一个intern()方法,该方法在内存中进行字符串的缓存和重复利用,以提高程序的效率。
String类的intern()方法主要有以下步骤:1. 首先,在字符串常量池中查找是否存在与该字符串对象值相同的字符串。
2. 如果存在,则返回该字符串的引用。
3. 如果不存在,则将该字符串对象添加到字符串常量池中,然后返回该字符串对象的引用。
例如:String s1 = new String("hello"); //创建一个字符串对象s1 String s2 = "hello"; //创建一个字符串对象s2,指向字符串常量池中的"hello"String s3 = s1.intern(); //将s1对象的字符串值添加到字符串常量池中,并返回该字符串在字符串常量池中的引用此时,s2和s3指向的是同一个字符串常量池中的"hello",而s1指向的是堆中的一个字符串对象。
需要注意的是,intern()方法只能将堆中的字符串对象添加到字符串常量池中,对于字符串常量池中的字符串对象调用intern()方法,并不会有任何改变。
例如:String s4 = "world"; //创建一个字符串对象s4,指向字符串常量池中的"world"String s5 = s4.intern(); //对于字符串常量池中的"world"对象调用intern()方法,返回该对象的引用可以看到,s4和s5指向的均是字符串常量池中的"world",intern()方法没有改变任何字符串对象的值。
需要注意的是,由于字符串缓存机制的存在,使用intern()方法进行字符串缓存需要慎重考虑,可能会造成内存泄漏的问题。
string intern 方法作用
string intern 方法作用在Java中,String是一个非常常用的类,用来表示字符串。
在Java中,字符串是不可变的,也就是说一旦创建了一个字符串对象,它的内容就不能再改变了。
由于字符串的不可变性,当我们需要比较两个字符串是否相等时,可以使用equals()方法来进行比较。
然而,对于字符串的频繁比较操作来说,equals()方法的效率并不高。
为了提高字符串的比较效率,Java提供了intern()方法。
string intern()方法的作用是返回字符串对象的规范化表示形式。
具体来说,当调用该方法时,如果字符串常量池中已经包含了一个等于此String对象的字符串(使用equals()方法进行比较),则返回常量池中的字符串;如果字符串常量池中不存在等于此String对象的字符串,则将此String对象添加到字符串常量池中,并返回该字符串对象的引用。
为了更好地理解intern()方法的作用,我们来看一个简单的例子:```javaString s1 = "hello";String s2 = new String("hello");String s3 = s2.intern();System.out.println(s1 == s2); // 输出falseSystem.out.println(s1 == s3); // 输出true```在上面的例子中,首先我们使用字符串字面值创建了一个字符串对象s1,然后使用new关键字创建了一个新的字符串对象s2。
由于字符串的不可变性,s2和s1的内容相同,但它们的引用是不同的,所以s1 == s2的结果是false。
接着,我们调用s2的intern()方法,该方法将s2的内容添加到字符串常量池中,并返回常量池中的字符串对象的引用。
所以,s1 == s3的结果是true。
通过上面的例子,我们可以发现,通过intern()方法可以将字符串对象规范化,减少内存的使用。
String字符串相加的原理
String字符串相加的原理**因为String是⾮常常⽤的类, jvm对其进⾏了优化, jdk7之前jvm维护了很多的字符串常量在⽅法去的常量池中, jdk后常量池迁移到了堆中 **⽅法区是⼀个运⾏时JVM管理的内存区域,是⼀个线程共享的内存区域,它⽤于存储已被虚拟机加载的类信息、常量、静态常量等。
使⽤引号来创建字符串单独(注意是单独)使⽤引号来创建字符串的⽅式,字符串都是常量,在编译期已经确定存储在常量池中了。
⽤引号创建⼀个字符串的时候,⾸先会去常量池中寻找有没有相等的这个常量对象,没有的话就在常量池中创建这个常量对象;有的话就直接返回这个常量对象的引⽤。
所以看这个例⼦:String str1 = "hello";String str2 = "hello";System.out.println(str1 == str2);//truenew的⽅式创建字符串String a = new String("abc");new这个关键字,毫⽆疑问会在堆中分配内存,创建⼀个String类的对象。
因此,a这个在栈中的引⽤指向的是堆中的这个String对象的。
然后,因为"abc"是个常量,所以会去常量池中找,有没有这个常量存在,没的话分配⼀个空间,放这个"abc"常量,并将这个常量对象的空间地址给到堆中String对象⾥⾯;如果常量池中已经有了这个常量,就直接⽤那个常量池中的常量对象的引⽤呗,就只需要创建⼀个堆中的String对象。
new构造⽅法中传⼊字符串常量, 会在堆中创建⼀个String对象, 但是这个对象不会再去新建字符数组(value) 来存储内容了, 会直接使⽤字符串常量对象中字符数组(value)应⽤,具体⽅法参考/*** Initializes a newly created {@code String} object so that it represents* the same sequence of characters as the argument; in other words, the* newly created string is a copy of the argument string. Unless an* explicit copy of {@code original} is needed, use of this constructor is* unnecessary since Strings are immutable.** @param original* A {@code String}*/public String(String original) {this.value = original.value; //只是把传⼊对象的value和引⽤传给新的对象, 两个对象其实是共⽤同⼀个数组this.hash = original.hash;}value 虽然是private修饰的, 但是构造⽅法中通过original.value;还是可以直接获取另外⼀个对象的值. 因为这两个对象是相同的类的对象所以有下⾯的结果public static void main(String[] args) {String s1 = new String("hello");String s2 = "hello";String s3 = new String("hello");System.out.println(s1 == s2);// falseSystem.out.println(s1.equals(s2));// trueSystem.out.println(s1 == s3);//false}关于“+”运算符常量直接相加:String s1 = "hello" + "word";String s2 = "helloword";System.out,println(s1 == s2);//true这⾥的true 是因为编译期直接就把 s1 优化成了 String s1 = "helloword"; 所以后⾯相等⾮常量直接相加public static void main(String[] args) {String s1 = "a";String s2 = "b";String s3 = new String("b");String s4 = s1 + s3;String s5="ab";String s6 = s1 + s2;String s66= s1 + s2;String s7 = "a" + s2;String s8 = s1 + "b";String s9 = "a" + "b";System.out.println(s2 == s3); //falseSystem.out.println(s4 == s5); //false s4 是使⽤了StringBulider来相加了System.out.println(s4 == s6); //false s4和s6 两个都是使⽤了StringBulider来相加了System.out.println(s6 == s66); //false 两个都是使⽤了StringBulider来相加了System.out.println(s5 == s7); //false s7是使⽤了StringBulider来相加了System.out.println(s5 == s8); //false s8是使⽤了StringBulider来相加了System.out.println(s7 == s8); //false 两个都是使⽤了StringBulider来相加了System.out.println(s9 == s8); //false 两个都是使⽤了StringBulider来相加了}总结下就是: 两个或者两个以上的字符串常量直接相加,在预编译的时候“+”会被优化,相当于把两个或者两个以上字符串常量⾃动合成⼀个字符串常量.编译期就会优化, 编译的字节码直接就把加号去掉了, 直接定义⼀个常量 **其他⽅式的字符串相加都会使⽤到 StringBuilder的. **String的intern()⽅法.这是⼀个native的⽅法,书上是这样描述它的作⽤的:如果字符串常量池中已经包含⼀个等于此String对象的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符添加到常量池中,并返回此String对象的引⽤。
解决java转义json出现u0000等乱码的问题
解决java转义json出现u0000等乱码的问题今天遇到了String乱码怎么都去不了的问题,最后的解决⽅法很简单,也不是⽅法的问题,是数据过滤之后进⾏的数据处理,在处理阶段⽣成了乱码,难怪我在过滤阶段怎么去都去不掉- -,不过花时间知道了很多处理乱码的⽅法,在这⾥记录⼀下。
在将中⽂数据转成json格式的时候,碰到了很多char型直接显⽰出来的,⽐如\u0000, \u201d, \u201c⾸先我想到的是我的数据筛选出现了问题,于是去修改了筛选的部分:title = title.replaceAll("\\u0000","");title = title.replaceAll("\u0000","");⾸先是这种,利⽤String的replace和replaceAll⽅法去过滤,这也是⼤部分乱码过滤的⽅法。
在这之后,我使⽤了直接循环处理char的⽅法,将String变成char型,然后⼀个⼀个判断,虽然⽐较笨这个⽅法,但是也算⼀种吧,谁让我菜呢。
之后我猜可能是编码问题导致了乱码,⽽现在不情况是只有个别字符串中出现了乱码,⼤部分还是正确的,所以不存在编码问题。
后来我是在想是不是String转Json的时候出现了问题,于是,将spring⾃带的json换成了阿⾥的fastjson,解决了部分的乱码问题(\u201d, \u201c),但是\u0000这个东西就是去不掉。
google⾥有⼈说string转json最好⽤list也不是string[]我的解决最后,我试着在数据处理完成后再删除\u0000,结果成功,哎,感觉浪费了好⼏个⼩时啊。
补充:Java 中各种空(''、\u0000、null)的区别?在使⽤下⾯的SQL查询时,发现去不掉空格,⽽且把limit 去掉以后空格就没有了,琢磨了很久才发现问题的关键所在。
JavaString对象的问题Strings=a+b+c+d
JavaString对象的问题Strings=a+b+c+d 12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 181, String s="a"+"b"+"c"+"d"创建了⼏个对象(假设之前串池是空的)2,StringBuilder sb = new StringBuilder();String a = "a";String b = "b";String c = "c";String d = "d";String s = a+b+c+d; 这句话创建了⼏个对象StringBuilder sb = new StringBuilder();sb.append("a").append("b").append("c").append("d");这句话创建了⼏个对象-------------------------------------------------------------------------------------------答案是 7 3 0第⼀题:“a”“b”“c”“d” “ab”“abc”“abcd”第⼆题: “ab”“abc”“abcd”第三题:因为a”“b”“c”“d”在串池中已经存在,不会创建对象,并且StringBuilder添加字符串的时候跟String是不⼀样的,StringBuilder是不会创建对象的(所以说我们在增加字符串长度的时候尽量⽤StringBuilder,这样会少创建对象,节省资源,提⾼效率)所以是0个对象在JVM中有⼀个字符串池,它⽤来保存很多可以被共享的String对象,这样如果我们在使⽤同样字⾯字符串时,它就使⽤字符串池中同字⾯的字符串。
JavaInteger常量池
JavaInteger常量池Java Integer常量池在Java中我们知道String有⼀个常量池,维护了所有的String对象。
我们写String temp="test"的时候其实是使⽤String.valueOf("test")从常量池中找了⼀个对象返回,但是如果使⽤String temp=new String("temp")的话就不会从常量池中去找,⽽是直接创建⼀个新的对象。
其实对于Integer来说也有这样⼀个常量池存在,并且我们都知道String常量池⾃从HotSpot1.8之后就从⽅法区移动到堆中了,⽽Integer常量池在哪⾥基本上都没有⼈提到,我个⼈⽐较相信它也是在堆中的。
之所以讨论的少可能是因为它相对不太重要吧Integer i = 10 和 Integer j = new Integer(10) 的区别public class IntegerClassDemo {public static void main(String[] javalatte) {Integer i = 10;Integer j = new Integer(10);Integer k = 145;Integer p = new Integer(145);}}在编译了上⾯这个类之后,我尝试着反编译这个类的 Class ⽂件。
我得到了下⾯这个类public class IntegerClassDemo{public static void main(String[] javalatte){Integer i = Integer.valueOf(10);Integer j = new Integer(10);Integer k = Integer.valueOf(145);Integer p = new Integer(145);}}所以当我们⽤ Integer i = 10 的⽅式创建⼀个 Integer 类时,Java 调⽤了⽅法 Integer.valueOf()。
java的String构造对象的几种方法以及内存运行过程
java的String构造对象的⼏种⽅法以及内存运⾏过程String类创建对象的⽅法可以分为以下三种1.String a = "123";2.String b = new String("123");3.String c = "12" + "3";1程序执⾏时,会先去jvm的常量池(在⽅法区中)中寻找有没有“123” 的String 对象,如果已经存在,则⽆须新建对象,直接把常量池中的对象地址返回给栈中的引⽤ a (此时没有建⽴对象)如果没有存在,则在常量池中新建⼀个“123”的String对象。
然后将其地址返回给栈中的引⽤ a(此时建⽴了⼀个对象)。
2.程序执⾏时,⾸先去jvm的常量池中寻找有没有“123”的String对象,如果有,则在堆中新建⼀个String类型的对象“123”,然后将其地址返回给栈中的引⽤b。
(此时只新建了⼀个对象)。
如果没有,则先在常量池中新建⼀个“123”的String对象。
然后再去堆中新建⼀个值为“123”的对象,并将堆中的对象地址返回给栈中的引⽤b。
(此时建⽴了两个对象)那在这⾥就有⼀个有趣的问题,那就是常量池中的对象和堆中的对象到底是不是同⼀个?可以通过⽐较 a == b 的值可得出结论。
楼主这边得到false。
可知他们并不是⼀个对象。
3.第三种构造⽅式⽐较复杂。
⽹上也是众说纷纭。
楼主在这⾥分为两种⽅式3.1第⼀种⽅式是: String a = "123"; String b = "1" + "2" + "3";如果是这样,由于全是b是由常量拼接起来的。
那么,在编译期间就能确定值,编译器就会在编译期间就帮你进⾏拼接。
那么,编译过后就成为:String b = "123";之后的判断和1⼀样。
JavaString类的intern()方法
JavaString类的intern()⽅法该⽅法的作⽤是把字符串加载到常量池中(jdk1.6常量池位于⽅法区,jdk1.7以后常量池位于堆)在jdk1.6中,该⽅法把字符串的值复制到常量区,然后返回常量区⾥这个字符串的值;在jdk1.7⾥,该⽅法在常量区记录该字符串⾸次出现的实例引⽤,然后返回该地址,常量区可以保存字⾯量也可以保存字符串对象在堆中的引⽤。
String s3 = new String("123") + new String("123");s3.intern();String s4 = "123123";System.out.println(s3 == s4);在jdk6中,输出false,因为intern⽅法将字符串复制到常量区,然后返回⼀个该字符串在常量区中的引⽤。
但是s3并没有接收这个引⽤,因此s3指向的还是堆,但是s4指向的是常量区,因此这两个地址不⼀样。
在jdk7 中,输出true,因为jdk7中intern⽅法是(在常量区找不到该字符串时)将该字符串对象在堆⾥的引⽤注册到常量区,以后使⽤相同字⾯量(双引号形式)声明的字符串对象都指向该地址,也就是该字符串在堆中的地址。
所以,调⽤s3的intern⽅法后返回的引⽤就是s3本⾝的引⽤,⽽使⽤字⾯量声明的s4也是指向这个引⽤的,所以这两个地址相同。
总结:使⽤双引号声明的字符串总是放在常量区,必须显式使⽤双引号,例如String s1="abc",s2="123"+"abc";,两个字⾯量连接只会在常量区保存连接后的⼀个字⾯;如果赋值掺杂了String对象的引⽤,则不符合本条使⽤new String("字符串")形式⽣命的String对象是分配在堆⾥的,例如String s3="hhh"+s1;,但是"hhh"这个字⾯量会放到常量池new String会⽣成两个对象,⼀个是分配在堆⾥的String对象,另⼀个是放在常量区的字⾯量jdk6总是将字⾯值放在常量区(将其字⾯值复制到常量区),常量区位于⽅法区jdk7常量区还能保存String对象在堆⾥的引⽤(将其在堆中的引⽤复制到常量区),常量区位于堆。
Java中判断String字符串是否相等
Java中判断String字符串是否相等⼀定要注意⼀下⼏点:只要使⽤引⽤变量 a 来加⼀个常量池内容"xxx"或者引⽤变量,都是放在堆⾥intern() 返回的是常量池中字符串的引⽤,⽽不是堆中字符串的引⽤⾸先看第⼀个字符串⽐较的例⼦public static void main(String[] args){String a = "a";String b = "b";// 这⾥的a + b应该是放在堆⾥的对象,常量池没有String c = a + b;// 这⾥的a + b应该是放在常量池⾥⾯的String d = "a" + "b";// 经测试,发现只要有使⽤引⽤变量a加上⼀个常量池内容"xxx"或者引⽤变量,都会放在堆⾥String e = a + "b";// 注意intern()返回的是常量池中字符串的引⽤,⽽不是堆中字符串的引⽤String f = c.intern();String g = "ab";String h = new String("ab");System.out.println(a + b == "ab"); // falseSystem.out.println(c == "ab"); // falseSystem.out.println(c == a + b); // falseSystem.out.println(c == h); // falseSystem.out.println(c == f); // falseSystem.out.println(d == e); // falseSystem.out.println(d == f); // trueSystem.out.println(d == g); // trueSystem.out.println(f == g); // true}下⾯看另外⼀个关于创建了⼏个对象的例⼦:public static void main(String[] args){String a = "abc";String b = "abc";String c = new String("abc");/*注意:这个虽然看起来似乎要在常量池新建三个字符串对象:"ab","c",和拼接⽣成的"abc"但是结果是内存中仅有⽣成的,前⾯的两个算是过程变量。
深入理解JavanewString()方法
深⼊理解JavanewString()⽅法问题⼀:这段代码创建了⼏个对象?String str1 = new String("aa");答案是两个“aa”对象和String对象其中有⼀项是常量池常量池在Class⽂件被加载的时候,会被加载进内存中的⽅法区中的运⾏时常量池,⽽运⾏时常量池⾥就包括字符串常量池,Class⽂件中的字符串在类加载时就会加载到字符串常量池中去不过在周志明⽼师在深⼊java虚拟机中有说到,到了JDK1.7时,字符串常量池就被移出了⽅法区,转移到了堆⾥了。
String str1 = new String(“aa”);"aa"就是被加载进去的字符串,我们可以看看Class⽂件这⾥的aa在之后类加载的时候,会在字符串常量池⾥创建⼀个 "aa"对象,这是第⼀个对象类加载完成了之后,那就要开始正式执⾏代码了,执⾏该⾏代码时new⼀个"aa"的String对象存放在Java堆中,这是第⼆个对象创建完第⼆个对象后,虚拟机栈上的str1将会指向第⼆个对象,也就是堆上的对象问题⼆:输出结果是true还是false?String str1 = new String("aa");String str2 = "aa";System.out.println(str1 == str2);答案很明显是false,因为两个变量指向的地址不同,⼀个指向字符串常量池,⼀个指向堆上的对象,⽽==⽐较的就是地址。
问题三:输出结果是true?String str1 = new String("aa");str1.intern();String str2 = "aa";System.out.println(str1 == str2);⾸先我们来了解⼀下intern⽅法intern的处理是先判断字符串常量是否在字符串常量池中,如果存在直接返回该常量,如果没有找到,说明该字符串常量在堆中,则处理是把堆区该对象的引⽤加⼊到字符串常量池中,以后别⼈拿到的是该字符串常量的引⽤,实际存在堆中。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
下面是几个常见例子的比较分析和理解:
final StringBuffer a = new StringBuffer("111");
final StringBuffer b = new StringBuffer("222");
a=b;//此句编译不通过
final StringBuffer a = new StringBuffer("111");
a.append("222");//编译通过
分析:final只对引用的"值"(即内存地址)有效,它迫使引用只能指向初始指向的那个对象,改变它的指向会导致编译期错误。
至于它所指向的对象的变化,final是不负责的。
String a = "ab";
String bb = "b"; String b = "a" + bb;
System.out.println((a == b));
//result = false
分析:JVM对于字符串引用,由于在字符串的"+"连接中,有字符串引用存在,而引用的值在程序编译期是无法确定的,即"a" + bb无法被编译器优化,只有在程序运行期来动态分配并将连接后的新地址赋给b。
所以上面程序的结果也就为false。
String a = "ab";
final String bb = "b";
String b = "a" + bb;
System.out.println((a == b));
//result = true
分析:和[3]中唯一不同的是bb字符串加了final修饰,对于final修饰的变量,它在编译时被解析为常量值的一个本地拷贝存储到自己的常量池中或嵌入到它的字节码流中。
所以此时的"a" + bb和"a" + "b"效果是一样的。
故上面程序的结果为true。
String a = "ab"; final String bb = getBB();
String b = "a" + bb;
System.out.println((a == b));
//result = false private static String getBB() { return "b"; }
分析:JVM对于字符串引用bb,它的值在编译期无法确定,只有在程序运行期调用方法后,将方法的返回值和"a"来动态连接并分配地址为b,故上面程序的结果为false。
通过上面4个例子可以得出得知:
String s = "a" + "b" + "c";
就等价于String s = "abc";
String a = "a"; String b = "b";
String c = "c";
String s = a + b + c;
这个就不一样了,最终结果等于:
StringBuffer temp = new StringBuffer();
temp.append(a).append(b).append(c);
String s = temp.toString();
由上面的分析结果,可就不难推断出String 采用连接运算符(+)效率低下原因分析,形如这样的代码:
public class Test { public static void main(String args[]) {
String s = null;
for(int i = 0; i < 100; i++) { s += "a"; } } }
每做一次 + 就产生个StringBuilder对象,然后append后就扔掉。
下次循环再到达时重新产生个StringBuilder对象,然后 append 字符串,如此循环直至结束。
如果我们直接采用 StringBuilder 对象进行 append 的话,我们可以节省 N - 1 次创建和销毁对象的时间。
所以对于在循环中要进行字符串连接的应用,一般都是用StringBuffer或StringBulider 对象来进行append操作。
String对象的intern方法理解和分析:
public class Test4 {
private static String a = "ab";
public static void main(String[] args){
String s1 = "a";
String s2 = "b";
String s = s1 + s2;
System.out.println(s == a);//false
System.out.println(s.intern() == a);//true
}
}
这里用到Java里面是一个常量池的问题。
对于s1+s2操作,其实是在堆里面重新创建了一个新的对象,s保存的是这个新对象在堆空间的的内容,所以s与a的值是不相等的。
而当调用s.intern()方法,却可以返回s在JVM常量池中的地址值,因为a的值存储在常量池中,故s.intern和a的值相等。
下面编译后的对象数
String s1 = new String("abc");// 2
String s2 = new String("abc");// 3
String s3 = "abc";// 3
String s4 = "abc";// 3
String s5 = "abcd";// 4
String s6 = s3 + "d";//s3 变量 //6
String s7 = "abc"+"d";//"abc"常量 //6
System.out.println(s1.equals(s2));//t
System.out.println(s1==s2);//f
System.out.println(s3.equals(s4));//t
System.out.println(s3==s4);//t
System.out.println(s5==s6);//f
System.out.println(s5==s7);//t。