看了很多文章事实证明之前的通过new创建String对象只有一个是错误的,实际上创建一个或者创建两个对象,一个在堆区,一个在常量池,当常量池中已经存在就不会创建。看了一篇非常好的文章http://www.cnblogs.com/wxgblogs/p/5635099.html,详细讲述了创建String对象的过程和String中的intern方法,以及该方法在jdk1.6和1.7中intern方法的变化
/********************************************************************2017/9/21修改************************************************************************/
String类是被final修饰的类,没有子类,不能被继承,被final修饰的类我们不能断定他就是不变类,StringBuffer类也是被final修饰的类,他就是可变类,可变类与不可变类要看他内部怎么实现的,String底层声明了一个名为value的字符数组,注意这个数组使用final修饰的,String的不可变就是因为他,只要创建了字符串也就是向这个数组中存入内容了,那么这个引用指向的内容就不变。而StringBuffer的创建依赖继承的抽象类AbstractStringBuilder,他的创建默认只是创建了一个16个字符长度的数组,这个数组并没有用final修饰,所以StringBuffer是一个可变类。


        String str = "a";
String str1 = str + "b";
System.out.println(str == str1);

Java 会确保一个字符串常量只有一个拷贝。

如果String是一个可变类,也就是说可以对原对象操作,那么上面的输出应该是true,但是结果是false。也就说明了String对象一旦创建就不可以改变,那么上面的代码怎么运行的呢?简单说一下:用户通过直接赋值,在常量池中创建了一个字符串a,后面想对这个a进行追加操作,加上一个b,但是String不允许直接在原来对象后面追加,这时候就需要,再创建一个新的常量吧a拷贝过去的同时后面放上b,这个ab字符串常量是一个整体,和最开始的那个a是互不相关的。所以通过==判断地址值的时候返回结果是false。

注意:这个被final关键字修饰的只是引用不可变,也就是他指向的对象不能变,至于对象中的内容,随意,看下面
        final StringBuffer str = new StringBuffer("a");
str.append("b");//可以运行 str = new StringBuffer("a");//报错
看下面例子

        String s1 = "ab";
String s2 = "b";
String s3 = "a" + s2;
System.out.println(s1 == s3); //false String s1 = "ab";
final String s2 = "b";
String s3 = "a" + s2;
System.out.println(s1 == s3); //true
上面两段代码,看似结果一样加了一个final关键字结果却不一样?第一段的s2是字符串b的一个引用,在编译期间无法判断具体的内容,也就是先把引用拿过来,不管内容是什么,最后在运行期间发现是b,虚拟机再对其进行+操作,至于加了一个final关键字,final关键字在编译期间就可以判断他的内容是一个字符串,既然是一个字符串那就要放到常量池中,所以再进行+操作结果为true
String的本质是字符序列,它是通过字符数组实现的!

源码分析:String类中定义了一个char类型的数组,名字为value
接着向下看,String提供了好多创建String对象的方法,通过参数的不同实现构造方法的重载,可以通过byte数组,char数组,int数组,直接给定字符串都可以创建String对象,但是不管这些方法中的参数是什么,最终都是对value数组进行操作。

如果是默认的无参构造方法,创建0个长度的字符数组
看几个源码的例子,虽然每个构造方法参数不同,最终都是对value数组赋值



下面看看String创建对象的方式:
String可以通过直接赋值创建,也可以通过new创建,这两种方式有很大的区别:
总结:对于String str="a"这样的直接赋值字符串常量操作,如果内容相同,Java会认为他们代表的是同一个对象;而用关键字new调用构造方法创建的对象,无论内容是否相同,总是会创建新的对象。
        String s1 = new String("a");
String s2 = new String("a");
System.out.println(s1==s2); String s3 = "v";
String s4 = "v";
System.out.println(s3==s4);

上面代码依次输出false和true,也就验证了上面的话。

验证通过new创建的字符串会放在常量池中吗?

        String s1 = "good";
String s2 = new String("good");
System.out.println(s1==s2); String s3 = "go";
String s4 = s3 + new String("od");
System.out.println(s4 == s1);
System.out.println(s2 == s4);
上面依次输出false,false,false。为什么呢?记住用new关键字。创建的对象总是会在堆区,在堆区有一块空间存这个对象,这个s2就是指向堆区的这块空间,它们有自己的地址空间,使用new创建的对象都是在堆区,而常量池是在方法区的。上面的直接赋值操作,是在编译期就可以确定的,而通过new创建的对象是在程序运行期间才确定。程序运行的String s2=new String("good")的时候,从前向后的顺序,先在栈区创建一个引用s2,向后运行发现有个new,那就在堆区创建一个对象吧,在把s2指向堆区这个对象。但是程序还是是会去常量池中创建一个对象就是这个字符串常量,不过会先进行判断常量池中有没有这个字符串,发现已经有了那么堆区的这个对象就直接指向他。
        String s1 = "ab";
String s2 = "a" + "b";
System.out.println(s1==s2);

上面的输出:true

总结:既然上面的代码输出true说明s2和s1都是指向一个地方,常量池中ab的地址,因为在百衲衣期间,虚拟机就对+进行操作,s2在编译期间就已经确定为ab。
遇到一个问题:为什么输出的String对象是String对象的内容而不是String对象的地址值,我们在平时创建对象输出的时候输出的总是该对象的地址值
        String str = new String("abc");
System.out.println(str);

上面的输出:abc,为什么不是输出str的地址值?因为String类中重写了toString方法,至于平时我们输出的地址值是调用的Object类中的toString方法


创建Integer对象,int的包装类输出也是对象中的值,也是因为Integer类中重写了toString方法。


String类详解的更多相关文章

  1. Java String类详解

    Java String类详解 Java字符串类(java.lang.String)是Java中使用最多的类,也是最为特殊的一个类,很多时候,我们对它既熟悉又陌生. 类结构: public final ...

  2. java 复习整理(四 String类详解)

    String 类详解   StringBuilder与StringBuffer的功能基本相同,不同之处在于StringBuilder是非线程安全的,而StringBuffer是线程安全的,因此效率上S ...

  3. STL之string类详解

    通过在网站上的资料搜集,得到了很多关于string类用法的文档,通过对这些资料的整理和加入一些自己的代码,就得出了一份比较完整的关于string类函数有哪些和怎样用的文档了!下面先罗列出string类 ...

  4. Java的String类详解

    Java的String类 String类是除了Java的基本类型之外用的最多的类, 甚至用的比基本类型还多. 同样jdk中对Java类也有很多的优化 类的定义 public final class S ...

  5. String类详解(1)

    首先String是一个类. 1,实例化String类方法. 1)直接赋值:String name="haha"; 2)通过关键字:String name=new String(&q ...

  6. String类详解,StringBuffer

    先说一下String类的equals()方法. 下面我们先看一段代码: 这段代码输出的结果为: ture true -------------- false 咋看之下貌似Object类比较特别,那么我 ...

  7. Java常用类(一)String类详解

    前言 在我们开发中经常会用到很多的常用的工具类,这里做一个总结.他们有很多的方法都是我们经常要用到的.所以我们一定要把它好好的掌握起来! 一.String简介 1.1.String(字符串常量)概述 ...

  8. 深入理解String类详解

    1.Stringstr = "eee" 和String str = new String("eee")的区别 先看一小段代码, 1 public static ...

  9. C++ string 类详解

    字符串是存储在内存的连续字节中的一系列字符.C++ 处理字符串的方式有两种,一种来自 C 语言,常被称为 C-风格字符串,另一种是基于 string 类库的字符串处理方式.C 风格字符串的处理可以参考 ...

随机推荐

  1. MyBatis框架概述

    MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身,而不需要花费精力去处理例如注册驱动.创建connection.创建statement.手动设 ...

  2. 了解c3p0,dbcp与druid

    说到druid,这个是在开源中国开源项目中看到的,说是比较好的数据连接池.于是乎就看看.扯淡就到这. 下面就讲讲用的比较多的数据库连接池.(其实我最先接触的是dbcp这个) 1)DBCP DBCP是一 ...

  3. php和java中的加密和解密

    遇到的java代码如下: Cipher cipher=Cipher.getInstance("DESede/CBC/PKCS5Padding"); 在php中使用des算法 始终校 ...

  4. windows下python3.4安装lxml提示"Unable to find vcvarsall.bat"

    "https://pypi.python.org/pypi/lxml/3.6.0"从这个网址直接下载对应的lxml包,exe格式的,直接安装,问题解决!

  5. 安装coreseek cannot find input file: src/Makefile.in 错误解决方法

    安装coreseek 出现了cannot find input file: src/Makefile.in 解决方法如下 >autoheader >automake --add-missi ...

  6. 利用squid 搭建简单的透明代理服务器

    环境介绍 虚拟主机1: ip eth0192.168.0.100/24 eth1: 200.168.0.100/24 虚拟主机2(模拟外网) 200.168.0.109/24 (运行web serve ...

  7. Error #2044: 未处理的 ioError:。 text=Error #2032

    1.错误描述 Error #2044: 未处理的 ioError:. text=Error #2032: 流错误. URL: http://127.0.0.1:8080/HBMB/analysis/a ...

  8. boost asio allocation

    allocation演示了自定义异步操作的内存分配策略,因为asio在执行异步IO操作时会使用系统函数来动态分配内存,使用完后便立即释放掉:在IO操作密集的应用中,这种内存动态分配策略会较大地影响程序 ...

  9. 简单使用Mysql-Cluster-7.5搭建数据库集群

    阅读目录 前言 mysql cluster中的几个概念解释 架构图及说明 下载mysql cluster 安装mysql cluster之前 安装配置管理节点 安装配置数据和mysql节点 测试 启动 ...

  10. Aspose实现Office转PDF (ASP.NET)

    0.添加Aspose的DLL 1.可以直接去官网下载,不过默认是带水印的,如需去除水印可以购买 2.当然也可以在国内的一些下载站下载 3.将Aspose.Cells.dll.Aspose.Words. ...