在群里看到一些对字符串还有静态变量的使用,接下来就看下测试:
*静态final是不可以改变的不可以二次的赋值;final就是不可变的。
* 当数据是基本类型时,意味着这是一个永不改变的编译时常量,一个在运行时被初始化的值,你不希望它改变。
*当数据是引用类型时,用static和final修饰表示这是只占据一块不能改变的内存空间
* 静态的可以进行赋值所以静态的可以进行对其+“xxx”操作并赋予新的值,但是final的就不可变的。不能对其做任何修改:
/**
* 静态final是不可以改变的不可以二次的赋值;final就是不可变的。
* 当数据是基本类型时,意味着这是一个永不改变的编译时常量,一个在运行时被初始化的值,你不希望它改变。
*当数据是引用类型时,用static和final修饰表示这是只占据一块不能改变的内存空间
* 静态的可以进行赋值
* @author Kay三石
*@date 2018年12月24日
*/
public class StringTest {
public static String string="ANC";
public static int str=122;
public final static String string2="111";
public static void main(String[] args) {
str=StringTest.str+1;//在静态中添加 添加final类型的肯定都是错误的。
System.out.println(str);
string=StringTest.string+"adb";//在静态中追加
System.out.println(string);
String string="123";
System.out.println(string);//输出的为123
string=StringTest.string+"adc";
System.out.println(string);
//报错:final是不可变的
// string2=StringTest.string2+"222";
// System.out.println(string2);
/**
* 字符串的基本操作:
* String类代表字符串。 Java程序中的所有字符串文字(例如"abc" )都被实现为此类的实例。
字符串不变; 它们的值在创建后不能被更改。 字符串缓冲区支持可变字符串。
因为String对象是不可变的,它们可以被共享。 例如:
String str = "abc";相当于:
char data[] = {'a', 'b', 'c'};
String str = new String(data);
*/
String str1 = "Lance";//在常量池中申请的,就是堆中保存值栈中保存变量然后引用指向堆。
String str2 = new String("Lance");//这个是无论常量池中有没有都会在堆中进行新建出一个实例,
String str3 = str2; //引用传递,str3直接指向st2的堆内存地址
String str4 = "Lance";
/**
* ==:
* 基本数据类型:比较的是基本数据类型的值是否相同
* 引用数据类型:比较的是引用数据类型的地址值是否相同
* 所以在这里的话:String类对象==比较,比较的是地址,而不是内容
*/
System.out.println(str1==str2);//false
System.out.println(str1==str3);//false
System.out.println(str3==str2);//true
System.out.println(str1==str4);//true
}
}
这里对string类官方API是这样解释的:
String类代表字符串。 Java程序中的所有字符串文字(例如"abc" )都被实现为此类的实例。
字符串不变; 它们的值在创建后不能被更改。 字符串缓冲区支持可变字符串。
因为String对象是不可变的,它们可以被共享。 例如:
String str = "abc";相当于:
char data[] = {'a', 'b', 'c'};
String str = new String(data);
String str=”xxx”;就是在常量池中申请的信息。就是堆中保存值栈中保存变量然后引用指向堆。
看下什么是常量池:
常量池在java用于保存在编译期已确定的,已编译的class文件中的一份数据。它包括了关于类,方法,接口等中的常量,也包括字符串常量,如String s = "java"这种申明方式;当然也可扩充,执行器产生的常量也会放入常量池,故认为常量池是JVM的一块特殊的内存空间。
java常量池技术 java中的常量池技术,是为了方便快捷地创建某些对象而出现的,当需要一个对象时,就可以从池中取一个出来(如果池中没有则创建一个),则在需要重复创建相等变量时节省了很多时间。常量池其实也就是一个内存空间,常量池存在于方法区中。
String类也是java中用得多的类,同样为了创建String对象的方便,也实现了常量池的技术。
测试代码如下:
public class Test{
public static void main(String[] args){
//s1,s2分别位于栈中,指向堆中不同的空间
String s1=new String("hello");
String s2=new String("hello");
System.out.println(s1==s2);//输出false
//s3,s4位于池中同一空间
String s3="hello" String s4="hello";
System.out.println(s3==s4);//输出true
}
}
用new String()创建的字符串不是常量,不能在编译期就确定,所以new String()创建的字符串不放入常量池中,他们有自己的地址空间。所以new String()无论他们的字符串相等不相等所在的地址都不会相同。
String 对象(内存)的不变性机制会使修改String字符串时,产生大量的对象,因为每次改变字符串,都会生成一个新的String。 java 为了更有效的使用内存,常量池在编译期遇见String 字符串时,它会检查该池内是否已经存在相同的String 字符串,如果找到,就把新变量的引用指向现有的字符串对象,不创建任何新的String 常量对象,没找到再创建新的。所以对一个字符串对象的任何修改,都会产生一个新的字符串对象,原来的依然存在,等待垃圾回收。
代码:
String a = “test”;
String b = “test”;
String b = b+"java";
a,b同时指向常量池中的常量值"test",b=b+"java"之后,b原先指向一个常量,内容为"test”,通过对b进行+"java" 操作后,b之前所指向的那个值没有改变,但此时b不指向原来那个变量值了,而指向了另一个String变量,内容为”test java“。原来那个变量还存在于内存之中,只是b这个变量不再指向它了。
而这样的是 String str3 = str2; //引用传递,str3直接指向st2的堆内存地址,二者地址必然相同。
下面试运行的截图: