1  字符串的声明与创建

  学习String的第一步就是创建(声明)字符串,我们在这里之所以分为创建和声明(其实是一个意思,都是创建字符串,但两者却有本质的区别)是因为String是一个很特殊的类,它的对象产生在五种创建对象之外,还有另外一种方式,下面我们就来详细了解一下.

1.1  声明字符串

  Java没有内置的字符串类型,而是在标准Java类库中提供了一个预定义的不可改变(final)的类,很自然的叫做String。在Java语言中字符串必须包含在一对””双引号中.例如:“23.3”,”adc”,”ad%-”,”1+3”.”你好,安静”,这些都是字符串常量(这里所说的常量并非是final的,不可更改的,而是可改变的,这里的改变也并非是改变字符串内容,而是改变String变量的指向),字符串常量是系统能够显示的任何文字信息,甚至是单个字符。在这里我们必须再强调一下凡是被双引号“”包含的都是字符串,不能作为其它数据类型使用,若要使用需要转型(可能出现类型转换异常),如上“1+2”如果输出的话是不会输出3的,输出结果是1+2.

  可以通过一下语法格式来声明字符串:

String str = [null];
  • String:描述符,指定该变量为字符串变量;
  • str:任意有效的标识符,表示字符串变量的名称;
  • =:赋值运算符,在数学上我们可以理解为等号,在内存层面我们可以理解为将str指向一个内存地址;
  • Null:在这里表示赋值的内容,如果未赋值,默认是初始化为null,意思是String变量没有指向任何对象。否则表明声明的字符串值为null.注意:成员字段可以不初始化,虚拟机给予初始化,局部变量必须进行初始化.
package cn.stringPractise.create;
//字符串创建的两种方法--声明字符串
public static void test1(){
String str1 = "abc";
String str2 = null;
// String str3;如果没有初始化就是用,会提示未曾初始化错误
//System.out.println(str3);//The local variable str3 may not have been initialized
System.out.println("str1:"+str1+"--hashcode:"+str1.hashCode());
System.out.println(str2);
//获取hashcode,此时null根本没有分配内存,自然是一个空指针,下面会报出空指针异常
// System.out.println("str2:"+str2+"--hashcode:"+str2.hashCode()); java.lang.NullPointerException
}

  通过这种声明的方式创建的字符串对象会首先到字符串常量池中去寻找是否存在这样一个字符串,如果有那么直接返回该字符串的地址,否则会在字符串常量池中创建该字符串然后使String变量指向该字符串。

1.2  创建字符串

  字符串除了可以直接赋值外,还可以由另一种方式来创建,下面我们来介绍一下.

  在Java中将字符串作为对象来管理,因此可以像创建其它类对象一样来创建字符串对象。创建对象要用到构造方法。String类的常用构造方法如下:

String()  初始化新创建的 String对象,使其表示空字符序列。

String(char a[],int offset,int length)   提取字符数组的一部分创建一个字符串对象.参数offset表示开始截取字符串的位置,length表示截取字符串的长度.

String(char[] value)    该构造方法可分配一个新的String对象,使其表示字符数组参数中所有的元素连接的结果。

String(byte[] bytes)  通过使用平台的默认字符集解码指定的字节数组来构造新的 String

String(byte[] bytes, Charset charset)  构造一个新的String由指定用指定的字节的数组解码charset 。

String(byte[] bytes, int offset, int length)  通过使用平台的默认字符集解码指定的字节子阵列来构造新的 String

String(byte[] bytes, int offset, int length, Charset charset)  构造一个新的String通过使用指定的指定字节子阵列解码charset
String(byte[] bytes, int offset, int length, String charsetName)  构造一个新的 String通过使用指定的字符集解码指定的字节子阵列。

  除了上面几种使用String类的构造方法来创建字符串变量外,还可通过字符串常量的引用赋值给一个字符串变量,以及提供的其它构造方法等(关于构造函数,我们在本节的最后会简单总结一下)。

【例7.1.2.1】验证创建字符串的几种方式。

//字符串创建的第二种方法--创建字符串
public static void test2(){
char[] ch = {'花','褪','残','红','青','杏','小'};
//使用字符数组创建字符串对象
String str1 = new String(ch);
System.out.println(str1);
//提取字符数组中的一部分,创建爱你字符串对象
String str2 = new String(ch, 1, 3);
System.out.println(str2);
String str3 = str1;
System.out.println(str3);
System.out.println(str1 == str3);
}

1.3  两种字符串创建的对比

  上面我们分别针对两种字符串的声明进行了分析,下面我们在来看一段代码,然后进行内存分析:

    //两种字符串创建的对比
public static void test3(){
String str1 = "123";
String str2 = new String("123");
String str3 = new String("234");
String str4 = "234";
System.out.println("str1:"+str1+"--hashcode:"+str1.hashCode());
System.out.println("str2:"+str2+"--hashcode:"+str2.hashCode());
System.out.println("str3:"+str3+"--hashcode:"+str3.hashCode());
System.out.println("str4:"+str4+"--hashcode:"+str4.hashCode());
String str5 = new String("123");
System.out.println("str5:"+str5+"--hashcode:"+str5.hashCode());
System.out.println((str2 == str5)+":"+(str1 == str2));
System.out.println((str2.equals(str5))+":"+(str1.equals(str2)));
}

  通过上面的比对,我们明白了一个问题,那就是hashcode一般情况下作为真实的内存地址的映射,我们知道String中”==”比较的是地址的内存地址,而equals()的源码如下:

public boolean equals(Object anObject) {
if (this == anObject) {//此时通过对象地址判断,地址一样自然是同一个对象
return true;
}
if (anObject instanceof String) {//判断该对象是否是String对象
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}

  String重写了Object的equals(),通过比对hashcode和字符串内容来确定equals的返回值,当他们有一点满足true就是true.下面我们来分析一下上面的test3()在内存中的情形:

  美术功底太差,将就看吧,从上面我们可以看出,通过声明字符串的形式进行字符串的创建的时候,会先在字符串常量池中查看是否有这个字符串,如果有那么就将这个引用指向这个字符串的地址,如果没有那么就在字符串常量池中创建该字符串,并将指针指向该字符串的内存地址.

  而通过new创建字符串则不同,它会在堆中创建一个字符串对象,然后才是在字符串常量池中查找是否有这个字符串,如果有那么会在堆中的对象中放入一个该字符串常量池中字符串的地址,如果没有在字符串常量池中创建字符串并将地址放在堆中对象里边,而我们的指针是指向堆中的字符串对象的.所以说通过声明方式创建字符串能够减少对象的创建和内存的消耗,这也是开发中我们建议采取和常用的做法。有了这个分析,我们思考一道面试题有关字符串常量池和String.intern;

1.4  String的构造方法简略

  在1.2创建字符串中,我们简单了解了几种String的构造方法,本节我们将String的构造方法罗列出来,我们可以作为一个消遣内容,红色的为个人认为重要的构造方法,蓝色的是弃用的无需关注.

  1. String()      初始化新创建的 String对象,使其表示空字符序列。
  2. String(byte[] bytes)   通过使用平台的默认字符集解码指定的字节数组来构造新的 String
  3. String(byte[] bytes, Charset charset)构造一个新的String由指定用指定的字节的数组解码charset 。
  4. String(byte[] ascii, int hibyte)   已弃用  此方法无法将字节正确转换为字符。 从JDK 1.1开始,首选的方法是通过String构造函数获取Charset ,字符集名称,或者使用平台的默认字符集。
  5. String(byte[] bytes, int offset, int length)通过使用平台的默认字符集解码指定的字节子阵列来构造新的 String
  6. String(byte[] bytes, int offset, int length, Charset charset)构造一个新的String通过使用指定的指定字节子阵列解码charset 。
  7. String(byte[] ascii, int hibyte, int offset, int count)已弃用此方法无法将字节正确转换为字符。 从JDK 1.1开始,首选的方式是通过String构造函数获取Charset ,字符集名称,或使用平台的默认字符集。
  8. String(byte[] bytes, int offset, int length, String charsetName)构造一个新的 String通过使用指定的字符集解码指定的字节子阵列。
  9. String(byte[] bytes, String charsetName)构造一个新的String由指定用指定的字节的数组解码charset 。
  10. String(char[] value)分配一个新的 String ,以便它表示当前包含在字符数组参数中的字符序列。
  11. String(char[] value, int offset, int count)分配一个新的 String ,其中包含字符数组参数的子阵列中的字符。
  12. String(int[] codePoints, int offset 起始位置, int count)分配一个新的 String ,其中包含 Unicode code point数组参数的子阵列中的 字符 。
  13. String(String original)初始化新创建的String对象,使其表示与参数相同的字符序列; 换句话说,新创建的字符串是参数字符串的副本。
  14. String(StringBuffer buffer)分配一个新的字符串,其中包含当前包含在字符串缓冲区参数中的字符序列。
  15. String(StringBuilder builder)分配一个新的字符串,其中包含当前包含在字符串构建器参数中的字符序列。

1.5 空串与null串

  字符串中关于空串和null串,是很容易弄混的一个地方,在这里特地说一下:

  空串“”是长度为0的字符串。空串是一个Java对象,有自己的长度(0)和内容(空)。不过String变量还可以存放一个特殊的值,名为null,这表示目前没有任何对象与该变量关联,null也并非是String特有的,它是一个关键字,属于Java。要检查一个字符串是否为null,可以通过(string == null)判断。非空判断也是程序中我们常见的操作,我们通过下面代码来实现;

if(str != null && str.length() != 0)

  关于空串,我们就讲解到这里;

Notes 20180310 : String第二讲_String的声明与创建的更多相关文章

  1. Notes 20180309 : String第一讲_char的可读序列

    实际上在写本文之前,我曾考虑是先探讨面向对象,还是先选择String和Arrays,最后还是选择了后者,并非是面向对象对我们不重要,相反它是Java的灵魂所在,之所以这样的安排是因为这两个是在是我们程 ...

  2. WebApp 安全风险与防护课堂(第二讲)开课了!

    本文由葡萄城技术团队于原创并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 在昨天的公开课中,由于参与的小伙伴们积极性和热情非常高,我们的讲师Carl ...

  3. POI教程之第二讲:创建一个时间格式的单元格,处理不同内容格式的单元格,遍历工作簿的行和列并获取单元格内容,文本提取

    第二讲 1.创建一个时间格式的单元格 Workbook wb=new HSSFWorkbook(); // 定义一个新的工作簿 Sheet sheet=wb.createSheet("第一个 ...

  4. 《ArcGIS Engine+C#实例开发教程》第二讲 菜单的添加及其实现

    原文:<ArcGIS Engine+C#实例开发教程>第二讲 菜单的添加及其实现 摘要:在上一讲中,我们实现了应用程序基本框架,其中有个小错误,在此先跟大家说明下.在“属性”选项卡中,我们 ...

  5. 32位汇编第二讲,编写窗口程序,加载资源,响应消息,以及调用C库函数

    32位汇编第二讲,编写窗口程序,加载资源,响应消息,以及调用C库函数 (如果想看所有代码,请下载课堂资料,里面有所有代码,这里会讲解怎么生成一个窗口程序) 一丶32位汇编编写Windows窗口程序 首 ...

  6. C++反汇编第二讲,不同作用域下的构造和析构的识别

    C++反汇编第二讲,不同作用域下的构造和析构的识别 目录大纲: 1.全局(静态)对象的识别,(全局静态全局一样的,都是编译期间检查,所以当做全局对象看即可.) 1.1 探究本质,理解构造和析构的生成, ...

  7. 框架原理第二讲,RTTI,运行时类型识别.(以MFC框架讲解)

    框架原理第二讲,RTTI,运行时类型识别.(以MFC框架讲解) 一丶什么是RTTI,以及RTTI怎么设计 通过第一讲,我们知道了怎么样升成一个窗口了,以及简单的消息循环. 第二讲则是主要讲解RTTI ...

  8. Stanford机器学习---第二讲. 多变量线性回归 Linear Regression with multiple variable

    原文:http://blog.csdn.net/abcjennifer/article/details/7700772 本栏目(Machine learning)包括单参数的线性回归.多参数的线性回归 ...

  9. 【军哥谈CI框架】之入门教程之第二讲:分析CI结构和CI是怎么工作的

    [军哥谈CI框架]之入门教程之第二讲:分析CI结构和CI是怎么工作的   之入门教程之第二讲:分析CI结构和CI是如何工作的大家好!上一节,我们共同部署了一个CI网站,做到这一点非常简单,但是,亲们, ...

随机推荐

  1. Maven学习总结(一):基本概念

    一.Maven的基本概念 Maven(翻译为"专家","内行")是跨平台的项目管理工具.主要服务于基于Java平台的项目构建,依赖管理和项目信息管理. 1.1. ...

  2. 当react 项目使用px2rem

    参考资料:http://easywork.xin/2018/09/02/react-2/ 我拿到的设计图 是  375px //配置px2rem px2rem({remUnit: 37.5})   在 ...

  3. Android BitmapDrawable

    功能:显示缩略图,大小为40*40 //通过openRawResource获取一个inputStream对象 InputStream inputStream = getResources().open ...

  4. MUI框架-12-使用原生底部选项卡(凸出图标案例)

    MUI框架-12-使用原生底部选项卡(凸出图标案例) 今天,用 mui 做 app 时,遇到了可能各位都遇到过的头疼问题:底部中间图标凸起,如下图: 最后有源代码 [提示]:有人问我在 HBuilde ...

  5. 用Jmeter进行接口测试及乱码问题

    web接口测试工具: 手工测试的话可以用postman ,自动化测试多是用到 Jmeter(开源).soupUI(开源&商业版). 下面将对前一篇Postman做接口测试中的接口用Jmeter ...

  6. 线程Event事件

    事件(event) 事件是不同线程之间的同步对象 enent可以通过设置.等待.清除一个标识(flag),来进行线程间的控制 线程可以通过获取这个标志位(flag)的状态(设置或未设置)来控制线程 事 ...

  7. 【转】c++ http下载文件

    #include <afx.h> #include <afxinet.h> #define RECVPACK_SIZE 2048 bool DownloadSaveFiles( ...

  8. 连接到 Azure 上的 SQL Server 虚拟机(经典部署)

    概述 本主题介绍如何连接到运行于 Azure 虚拟机的 SQL Server 实例. 它介绍了一些常规连接方案,并提供了在 Azure VM 中配置 SQL Server 连接的详细步骤. Impor ...

  9. js获取鼠标坐标位置兼容多个浏览器

    这个是IE 11 下兼容下视图测试时可用. $(window).bind('beforeunload', function (event) { var _this = this; var x = ev ...

  10. 布隆过滤器(Bloom Filter)简要介绍

    一种节省空间的概率数据结构 布隆过滤器可以理解为一个不怎么精确的 set 结构,当你使用它的 contains 方法判断某个对象是否存在时,它可能会误判.但是布隆过滤器也不是特别不精确,只要参数设置的 ...