必威体育Betway必威体育官网
当前位置:首页 > IT技术

String类介绍

时间:2019-08-21 18:43:18来源:IT技术作者:seo实验室小编阅读:60次「手机版」
 

string类

一、String类介绍:

String是一个引用数据类型默认为null;

       String 为final类型不可更改,不能被继承;

       基本类型与String结合都会转换为String类型;

二、String两种赋值方式:

1)直接赋值:String str = " ";

String str = "" 原理:

       在 JVM(虚拟机)中有一个字符串池,专门用来存储字符串。如果遇到 String a=”hello”时(注意没有 NEW,不是创建新串),系统在字符串池中寻找是否有 ”hello”,

       此时字符串池中没有”hello”,那么系统将此字符串存到字符串池中,然后将 ”hello”在字符串池中的地址返回 a。

      如果系统再遇到String b=”hello”,此时系统可以在字符串池中找到  “hello”。则会把地址返回b,此时 a与b 为相同。

2)使用new进行赋值:String str = new String (" ");

3) 两种赋值方式的区别:

           1、直接定义的String "a"是储存在常量存储区中的字符串常量池中;new String(“a”)是存储在中;

           2、常量池中相同的字符串只有一个,但是new String(),每new一个对象就会在堆中新建一个对象;

           3、String a = “a”在编译阶段就会在内存中创建;String a = new String(“a”);是在运行时才会在堆中创建对象;

	    String a = "hello";
        String b = "hello";
        System.out.println(a == b );//true  a b 指向同一个值,地址相同
        System.out.println(a.equals(b));//true a b 是同一个值,当然相等

        String a1 = new String ("hello");
        String b1 = new String ("hello");
        System.out.println(a1 == b1 );//false  每次new都会创建一个新对象,a1 b1 地址不同 
        System.out.println(a1 .equals(b1) );//true 

由此可以得出两种实例化方式的区别

    1)直接赋值(String str = "hello"):只开辟一块堆内存空间,并且会自动入池,不会产生垃圾。

    2)构造方法(String str=  new String("hello");):会开辟两块堆内存空间,其中一块堆内存会变成垃圾被系统回收

        开发的过程中不会采用构造方法进行字符串的实例化。

4)常量池

字符串常量池在jdk1.6及之前在方法区中,但是在jdk1.7及以后就放在了堆中

编译阶段确定的字符串才会被放到字符串常量池中

分析下面创建几个对象:

                String s1 = "java"; 
		String s2 = "从0到1"; 
		String s3 = "java从0到1"; 
		String s4 = s1+s2;
		System.out.println(s3==s4);

s1和s2还有s4都会在字符串常量池中,这已经有三个对象了 。关键在于这行代码String s3 = s1 + s2;

对于s3无法在编译阶段确定下来,所以无论最后的字符串是什么都不会存在字符串常量池中,那么存在哪呢?因为对象创建在堆中,而字符串常量池也在堆中,既然不在字符串常量池中那就是在字符串常量池之外的堆中了,而s3最终的字符串对象是“Java从0到1”,那么也就是说这个字符串在常量池之外的堆中,这是一个对象了,加上之前的三个,这里一共四个了,但是我们还要分析这个s3是怎么来的,是通过s1和s2相加得到的,因为这个s3最终是在常量池之外的堆中形成的,而s1和s2都是在常量池中,因此会将s1和s2拷贝一份到字符串常量池之外的堆中来形成s3,我们看下面的一张图来加深理解

堆内存复制s1,s2,这样的话要再加上两个对象,那一共就是创建6个对象了!

三、String源码解析:

Jdk1.7 的String源码如下: 

public final class String
    implements java.io.serializable, Comparable<String>, Charsequence {
    /** The value is used for character storage. */
    private final char value[];
 
    /** cache the hash code for the string */
    private int hash; // Default to 0

由以上的代码可以看出, 在Java中String类其实就是对字符数组的封装,除此之外还有一个hash成员变量,是该String对象的哈希值的缓存。

value这个变量是final的, 也就是说在String类内部,一旦这个值初始化了, 也不能被改变。所以可以认为String对象是不可变的了。

String s = new ("ABCabc"); 对应的内存模型为:

当我们调用a.replace('A', 'a')时, 方法内部创建了一个新的String对象,并把这个新的对象重新赋给了引用a;

因此结果为 aBCabc

Spring是否真的是不可变?

我们知道被final修饰的引用类型变量是引用的地址不可变,而不是引用的值不可变,因此我们能否改变value数组的值而使String改变???答案当然是可以的,反射可以搞定。

反射可以访问私有成员,因此我们可以反射出String对象中的value属性, 进而改变通过获得的value引用改变数组的结构。

	public static void testReflection() throws Exception {
		
		//创建字符串"hello world", 并赋给引用s
		String s = "Hello World"; 
		
		System.out.println("s = " + s);	//Hello World
		
		//获取String类中的value字段
		field valueFieldOfString = String.class.getDeclaredField("value");
		
		//改变value属性的访问权限
		valueFieldOfString.setaccessible(true);
		
		//获取s对象上的value属性的值
		char[] value = (char[]) valueFieldOfString.get(s);
		
		//改变value所引用的数组中的第5个字符
		value[5] = '_';
		
		System.out.println("s = " + s);  //Hello_World
	}

在这个过程中,s始终引用的同一个String对象,但是再反射前后,这个String对象发生了变化, 也就是说,通过反射是可以修改所谓的“不可变”对象的。但是一般我们不这么做。这个反射的实例还可以说明一个问题:如果一个对象,他组合的其他对象的状态是可以改变的,那么这个对象很可能不是不可变对象。例如一个Car对象,它组合了一个Wheel对象,虽然这个Wheel对象声明成了private final 的,但是这个Wheel对象内部的状态可以改变, 那么就不能很好的保证Car对象不可变。

四、String进行字符串拼接:

拼接原理:String是字符串常量的引用,String += String的本质是new了新的临时对象Stringbuild,拼接后再把StringBuild.toString赋给原String。

       String s="a"+"b"+"c"+"d"; 实际只创建了一个对象  ,过程是new 了 一个临时的StringBuild,然后把"a"+"b"+"c"+"d"进行拼接,结果"abcd".toString 返回gei s;

       

       所有大量字符串拼接不要直接使用String,否则会生成大量临时对象,严重影响性能。 

五、String,StringBuffer, stringbuilder比较:

       

       1、String是字符串常量,StringBuffer和StringBuilder都是字符串变量。后两者的字符内容可变,而前者创建后内容不可变(String进行字符串拼接时创建新对象)。

       2、StringBuffer是线程安全的,而StringBuilder是非线程安全的。

       3.线程安全会带来额外的系统开销,所以StringBuilder的效率比StringBuffer高。如果对系统中的线程是否安全很掌握,

       可用StringBuffer,在线程不安全处加上关键字Synchronize。

4.  StringBuffer 和 StringBuilder 要调用.toString方法在进行比较

相关阅读

七、输入/输出流--基于字符串的流---basic_ostringstr

3 basic_ostringstream模板 basic_ostringstream模板支持写入basic_string对象,使用basic_stringbuf控制相关存储区域; 定义: tem

C++之substr与substring浅谈

转自:http://blog.sina.com.cn/s/blog_9d85c1900102v1rm.html区别:主要是两者的参数不同功能:相似        substr :返回一个从

stringstream 用法

在使用C++编程的时候,有时会输入一段英文句子,如果使用Python原因的话,那么直接使用 split() 函数就好了。那么使用C++有没有方便的

java.lang.NumberFormatException: For input string:

我遇到的这个错误是在执行查询的时候遇到的错误,所以就不说因为类型转换引起的原因了 先贴上相关的sql 其实报这个错误的原因就是

StringBuffer源码

package java.lang; import java.util.Arrays; /** * A thread-safe, mutable sequence of characters. * A string buffer i

分享到:

栏目导航

推荐阅读

热门阅读