在java中,说String是不可变的,可是为什么

作者&投稿:贠齿 (若有异议请与网页底部的电邮联系)
为什么 java 中的 string 是不可变的~

个人理解:因为string在java的编程当中比较普遍,以下的回答比较全面一些:
Java中String为什么是不可变的
1、在Java中,String类是不可变类,一个不可变类是一个简单的类,并且这个的实例也不能被修改,
这个类的实例创建的时候初始化所有的信息,并且这些信息不能够被修改
2、字符串常量池
字符串常量池是方法区中一块特殊的存储区域,当创建一个字符串常量的时候,判断该字符串字在符串字符串常量池中是否已经存在
如果存在,返回已经存在的字符串的引用;如果不存在,则创建一个新的字符串常量,并返回其引用
String string1 = "abcd";
String string2 = "abcd";
变量string1,string2指向常量池中的同一个字符串常量对象;如果String是可变的,给一个变量重新赋值一个引用,将会指向错误的值
3、缓存哈希值
在Java中字符串的哈希值会经常被使用到。例如在HashMap中,String的不可变总能保证哈希值总是相等的,并且缓存起来,不用担心会改变,
那意味着不需要每次都计算哈希值,这样会提高效率。在String类中有以下的代码:
private int hash; //用来缓存哈希值
3、促进其他对象的使用
HahSet set = new HashSet();
set.add(new String("a"));
set.add(new String("b"));
set.add(new String("c"));

a只是字符串的引用,并不是对象本身,所以可以被修改。a=“age”只是将a的引用指向了字符串age,原先的字符串name并没有被改变。
Java中String类是不可变的意思是当String对象被创建后,这个对象的状态就不能被改变,包括对象内的成员变量等都不能被改变。
Java把String设计为不可变,有以下优点:
当创建一个字符串常量时,判断该字符串是否在常量池中,如果存在,返回已经存在的字符串引用,如果不存在,新建一个字符串返回其引用。例如String a=“abc”;String b=“abc”;。变量a和b其实引用的是同一个字符串对象abc,如果String是可变的,有需要再创建一个新的变量。
在Java中常常要用到Hash值,String不可变总能保值Hash值不变,并缓存起来,不用每次都计算Hash值。
正因为String是不可变的,他们可以在多个线程中共享,是线程安全的。

ng对象的数据类型

1. 首先String不属于8种基本数据类型,String是一个对象。

因为对象的默认值是null,所以String的默认值也是null;但它又是一种特殊的对象,有其它对象没有的一些特性。

2. new String()和new String(“”)都是申明一个新的空字符串,是空串不是null;

3. String str=”kvill”;

String str=new String (“kvill”);的区别:

在这里,我们不谈堆,也不谈栈,只先简单引入常量池这个简单的概念。

常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。

看例1:

String s0=”kvill”;

String s1=”kvill”;

String s2=”kv” + “ill”;

System.out.println( s0==s1 );

System.out.println( s0==s2 );

结果为:

true

true

首先,我们要知结果为道Java会确保一个字符串常量只有一个拷贝。

因为例子中的s0和s1中的”kvill”都是字符串常量,它们在编译期就被确定了,所以s0==s1为true;而”kv”和”ill”也都是字符串常量,当一个字符串由多个字符串常量连接而成时,它自己肯定也是字符串常量,所以s2也同样在编译期就被解析为一个字符串常量,所以s2也是常量池中”kvill”的一个引用。

所以我们得出s0==s1==s2;

用new String() 创建的字符串不是常量,不能在编译期就确定,所以new String() 创建的字符串不放入常量池中,它们有自己的地址空间。

看例2:

String s0=”kvill”;

String s1=new String(”kvill”);

String s2=”kv” + new String(“ill”);

System.out.println( s0==s1 );

System.out.println( s0==s2 );

System.out.println( s1==s2 );

结果为:

false

false

false

例2中s0还是常量池中”kvill”的应用,s1因为无法在编译期确定,所以是运行时创建的新对象”kvill”的引用,s2因为有后半部分new String(“ill”)所以也无法在编译期确定,所以也是一个新创建对象”kvill”的应用;明白了这些也就知道为何得出此结果了。

4. String.intern():

再补充介绍一点:存在于.class文件中的常量池,在运行期被JVM装载,并且可以扩充。String的intern()方法就是扩充常量池的一个方法;当一个String实例str调用intern()方法时,Java查找常量池中是否有相同Unicode的字符串常量,如果有,则返回其的引用,如果没有,则在常量池中增加一个Unicode等于str的字符串并返回它的引用;看例3就清楚了

例3:

String s0= “kvill”;

String s1=new String(”kvill”);

String s2=new String(“kvill”);

System.out.println( s0==s1 );

System.out.println( “**********” );

s1.intern();

s2=s2.intern(); //把常量池中“kvill”的引用赋给s2

System.out.println( s0==s1);

System.out.println( s0==s1.intern() );

System.out.println( s0==s2 );

结果为:

false

**********

false //虽然执行了s1.intern(),但它的返回值没有赋给s1

true //说明s1.intern()返回的是常量池中”kvill”的引用

true

最后我再破除一个错误的理解:

有人说,“使用String.intern()方法则可以将一个String类的保存到一个全局String表中,如果具有相同值的 Unicode字符串已经在这个表中,那么该方法返回表中已有字符串的地址,如果在表中没有相同值的字符串,则将自己的地址注册到表中“如果我把他说的这个全局的String表理解为常量池的话,他的最后一句话,“如果在表中没有相同值的字符串,则将自己的地址注册到表中”是错的:

看例4:

String s1=new String("kvill");

String s2=s1.intern();

System.out.println( s1==s1.intern() );

System.out.println( s1+" "+s2 );

System.out.println( s2==s1.intern() );

结果:

false

kvill kvill

true

在这个类中我们没有声名一个”kvill”常量,所以常量池中一开始是没有”kvill”的,当我们调用s1.intern()后就在常量池中新添加了一个”kvill”常量,原来的不在常量池中的”kvill”仍然存在,也就不是“将自己的地址注册到常量池中”了。

s1==s1.intern()为false说明原来的“kvill”仍然存在;

s2现在为常量池中“kvill”的地址,所以有s2==s1.intern()为true。

5. 关于equals()和==:

这个对于String简单来说就是比较两字符串的Unicode序列是否相当,如果相等返回true;而==是比较两字符串的地址是否相同,也就是是否是同一个字符串的引用。

6. 关于String是不可变的

这一说又要说很多,大家只要知道String的实例一旦生成就不会再改变了,比如说:String str=”kv”+”ill”+” “+”ans”;

就是有4个字符串常量,首先”kv”和”ill”生成了”kvill”存在内存中,然后”kvill”又和” “ 生成 ”kvill “存在内存中,最后又和生成了”kvill ans”;并把这个字符串的地址赋给了str,就是因为String的“不可变”产生了很多临时变量,这也就是为什么建议用StringBuffer的原因了,因为StringBuffer是可改变的。
另外,团IDC网上有许多产品团购,便宜有口碑

首先在栈中有个"s"变量指向堆中的"wo"对象...
栈中"s1"变量指向堆中的"de"对象
当执行到s = s + s1;
系统重新在堆中new一个更大的数组出来,然后将"wo"和"de"都复制进去,然后栈中的"s"指向这个新new出来的数组...
所谓的不可变是指:它没有在原数组“wo”上进行修改,而是新建了个更大数组进行扩展,也就是说,这时候堆里还是有“wo”这个对象数组存在的,只不过这个时候"s"变量不在指向"wo"这个数组了,而是指向了新new出来的数组,这就是和StringBuffered的区别,后者是在原数组上进行修改,改变了原数组的值,StringBuffered不是通过新new一个数组去复制,而是在原数组基础上进行扩展...再让变量指向原数组....
你看的懂不?不懂再问...
希望能对你有所帮助...

a只是字符串的引用,并不是对象本身,所以可以被修改。a=“age”只是将a的引用指向了字符串age,原先的字符串name并没有被改变。

Java中String类是不可变的意思是当String对象被创建后,这个对象的状态就不能被改变,包括对象内的成员变量等都不能被改变。

Java把String设计为不可变,有以下优点:

  1. 当创建一个字符串常量时,判断该字符串是否在常量池中,如果存在,返回已经存在的字符串引用,如果不存在,新建一个字符串返回其引用。例如String a=“abc”;String b=“abc”;。变量a和b其实引用的是同一个字符串对象abc,如果String是可变的,有需要再创建一个新的变量。

  2. 在Java中常常要用到Hash值,String不可变总能保值Hash值不变,并缓存起来,不用每次都计算Hash值。

  3. 正因为String是不可变的,他们可以在多个线程中共享,是线程安全的。



你试一下,这个就是wode

有个串池的概念

String str1=”java”; //指向字符串池
String str2=”blog”; //指向字符串池

String s=str1+str2; //s是指向堆中值为"javablog"的对象,+运算符会在堆中建立来两个String对象,这两个对象的值分别是"java" "blog". 也就是说从字符串池中复制这两个值,然后在堆中创建两个对象,然后再建立对象s,然后将"javablog"的堆地址赋给s. 这句共创建了?个String 对象!

System.out.println(s==”javablog”); //结果是false。
Jvm确实对型如String str1=”java”;的String对象放在常量池里,但是它是在编译时那么做的,而String s=str1+str2;是在运行时刻才能知道,也就是说str1+str2是在堆里创建的,所以结果为false了。

如果改成一下两种方式:

String s="java" + "blog"; //直接将"javablog"放入字符串池中,System.out.println(s==”javablog”); 的结果为true, 这个句子创建了?个String对象

String s=str1+ "blog"; //不放入字符串池,而是在堆中分配,System.out.println(s==”javablog”); 的结果为False, 这个句子创建了?个String对象

s=s+s1,相当于一个赋值。
s+s1就形成了字符串“wode”
再把“wode”赋给s
java中的对象相当于C中的指针,此处就相当于一个s指针指向”wo“,然后通过赋值,s指针重新指向”wode“字符串。
"wo"并没有消失,只是s已经没有指向它了~


java中public static int age=24 Student st1=new Student() st1.ag...
不为什么,有加号:st1.age+=24表示,st1.age=st1.age+24.

java接口,抽象类,ststic关键字,修饰符得运用。求全解。
Final和abstract永远不会同时出现。Abstract和static不能放在一起,否则便会出现错误。(这是因为static不可被覆盖,而abstract为了生效必须被覆盖。)当abstract用于修饰方法时,此时该方法为抽象方法,此时方法不需要实现,实现留给子类覆盖,子类覆盖该方法之后方法才能够生效。JAVA的核心概念:接口(interface)...

java中静态变量和静态方法分别有什么特点
如果我们要改变这块区域,需调用其中的方法,如 s.raiseSalary(25);\/\/raiseSalary(double)为Employee 中的方法 这样,我们通过方法(类方法)改变了类中的变量(类数据或类变量).所谓静态方法,就是通过类名来调用(当然通过类对象来调用一样是可以的,就像core java里说的一样,容易让人混淆!)的方法,而静态...

java编程定义一个学生类Student,成员变量有学号,姓名,性别,身高,体重...
{vs.add(new Student(i,"张三"+i,"男",+1.72,65.03));}java.util.Iterator<Student> it = vs.iterator();while(it.hasNext()){System.out.println("---");Student st = it.next();System.out.println("序号:" + st.num);System....

在java中,要是一个方法的返回值是一个对象,那是返回这个对象里面的什么...
返回的是一个值:如果返回的是一个int型的a,它的值为10,则返回的就是10而不是a。如果返回的是一个对象a,它的值为这个对象的引用,通过这个对象的引用可以获得它相关的属性,也可以通过这些属性的方法改变其属性的值。

java中,想记录异常信息,该如何获得发生异常的类名和方法名呢?不要用l...
我觉得你写的是对的 StackTraceElement[] st = ex.getStackTrace();for (StackTraceElement stackTraceElement : st) { String exclass = stackTraceElement.getClassName();String method = stackTraceElement.getMethodName();System.out.println(exclass);System.out.println(method);} } 这个就是整个...

写出至少三个表达你对Java映像的词汇?
interface (接口):public interface B(){}花括号里有方法体,但没有实现,方法体句子后面是英文分号;结尾 abstract (声明抽象):public abstract class C(){}介于类与接口中间,可以有,也可以没有已经实现的方法体 implemenst (实现):用于类或接口,实现接口public class A interface B(){} exten...

Java中static和final的区别
此时,无论st1.i还是st2.i都有同样的值47,因为它们引用的是同样的内存区域。有两个办法可引用一个static变量。正如上面展示的那样,可通过一个对象命名它,如st2.i。亦可直接用它的类名引用,而这在非静态成员里是行不通的(最好用这个办法引用static变量,因为它强调了那个变量的“静态”本质)...

java中thread的start()和run()有何区别?
2、run()方法当作普通方法的方式调用,程序还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码;而如果直接用run方法,这只是调用一个方法而已,程序中依然只有主线程--这一个线程,其程序执行路径还是只有一条,这样就没有达到写线程的目的。3、调用start方法方可启动线程,而run方法...

在看一个java教材,里面他用new Thread(st).start();未报错,而我却显示...
public class 没写``怎么会不错 public class TicketsSystem { public static void main(String[] args){ SellThread st=new SellThread();new Thread(st).start();new Thread(st).start();new Thread(st).start();new Thread(st).start();} } class SellThread implements Runnable { int ...

锡林郭勒盟13946724540: Java,为什么说String为不可变字符串? -
唱颜络德: String A = "xx";String A = new String("xx");是一样的吗?肯定不一样,每一个String对象New出来后,JVM就会给他分配一个内存空间A = "ZZ";看起来像是给A赋值,改变了A实际上这样是让A指向另一个内存空间

锡林郭勒盟13946724540: 为什么说Java的String对象是不可变的 -
唱颜络德: 今天晚上部门领导开会的时候,又突然想起来这个问题,这里记录下来自己的理解,期待以后会有更深刻的收获. 根据JDK中java.lang.String的源码进行分析,从中可以得出String类型的对象不可变的原因,大致上有如下两个: 1、java.lang....

锡林郭勒盟13946724540: 在java中,说String是不可变的,可是为什么 -
唱颜络德: 首先在栈中有个"s"变量指向堆中的"wo"对象...栈中"s1"变量指向堆中的"de"对象 当执行到s = s + s1; 系统重新在堆中new一个更大的数组出来,然后将"wo"和"de"都复制进去,然后栈中的"s"指向这个新new出来的数组...所谓...

锡林郭勒盟13946724540: 为什么字符串在Java中是不可变的 -
唱颜络德: 你需要理解String中有一个pool(池),还有String a="name";其实是这样的:String a=new String(“name”);上网查查详细资料就能来理解了. String:是对象不是原始类型.为不可变对象,一旦被创建,就不能修改它的值.对于已经存在的String对象的修改都是重新创建一个新的对象,然后把新的值保存进去.String 是final类,即不能被继承.你应该是想要知道的是String、StringBuffer、StringBuilder之间的区别

锡林郭勒盟13946724540: java中string为什么不可变 -
唱颜络德: 为什么不可变,回答这个问题,你就要理解把它设计为不可变的好处,String作为java中最常用的一种类,提供了很多操作方法.把它设计为final有以下好处: 1:稳定性和节省内存开销 final型会在jvm进行类加载的时候就直接进行实例化,这样...

锡林郭勒盟13946724540: Java的String对象不能改变? -
唱颜络德: public final class String说String不参改变是指它的定义,是final的,不能被继承,方法不能被重写.不是说这个对象的引用不可改变.

锡林郭勒盟13946724540: JAVA中字符串类型String是不允许改变其内容的,那么请问简要谈谈下列语句是如何运行的: -
唱颜络德: 确实,Java中的String类型确实是不允许改变其内容的,String类型的对象一旦建立,将在堆内存当中占据一个固定的内存空间,String类型的对象无法改变.但是你在运算的时候又发现,你定义的String类型的s变量又是可以进行连接的,如"...

锡林郭勒盟13946724540: String为什么是不可变的 -
唱颜络德: 1、在C语言中我们知道是不存在字符串这一概念的,而只存在字符或字符数组概念,但是JAVA为了让用户更方便的对字符进行操作,所以自己定义了一个类,对字符数组进行了封装,而后形成了字符串. 2、面试题:请解释String类为什么不...

锡林郭勒盟13946724540: 为什么java中的string不可变 -
唱颜络德: 一: 原因分析: 因为String在源代码使用了final修饰, 所以不可变. //部分源代码 public final class String implements java.io.Serializable, Comparable, CharSequence { //..... }String 不可变的好处, 可以解决同步安全等问题. 二: 解决办法 StringBuffer 和 StringBuilder 是可变的字符串变量 , 可以提高效率 两者区别如下 StringBuffer 字符串变量(线程安全) StringBuilder 字符串变量(非线程安全)

锡林郭勒盟13946724540: java为什么不能用string声明 -
唱颜络德: java里面没有string,只有String,String和基本类型不同,它是个类.

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网