6.1 String 字符串
JVM为了更高效地处理数据,会用不同的算法把内存分为各种区域,不同的区域拥有各自的特性,Java中,内存可以分为栈,堆,静态域和常量池等。
- 栈:存放局部变量(变量名,对象的引用等)特点:内存随着函数的调用而开辟,随着函数调用结束而释放。
- 堆:堆区:存放对象(也就是new出来的东西)特点:可以跨函数使用,每个对象有自己对应的存储空间。
- 静态域:存放在对象中用static定义的静态成员。
- 常量池:存放常量。(常量池指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。)
Java字符串就是Unicode字符序列。Java没有内置的字符串类型,而是在标准的Java类库中提供了一个预定义类(String)。
每个用双引号括起来的字符串都是String类的一个实例:
String a = "";//这是一个字符串
String get = "Hello";
这种方式的定义的String,引用get,存放在栈区。字符串常量"Hello"被存放在常量池引用get引用指向了常量池中俄"Hello"
String str = new String("new Hello World!");//被存放在堆区
这种方式定义的String,引用str,存放在栈区,字符串"new Hello World!"存放在堆区
内存图
两者的区别:
第一种:常量池的字符串常量,不能重复出现,也就是说,在定义多个常量时,编译器先去常量池查找该常量是否已经存在,如果不存在,则在常量池创建一个新的字符串常量;如果该常量已经存在,那么新创建的String类型引用指向常量池中已经存在的值相同的字符串常量,也就是说这是不在常量池开辟新的内存。
第二种:在堆中创建新的内存空间,不考虑该String类型对象的值是否已经存在。换句话说:不管它的 只是多少,第二种方法的这个操作已经会产生的结果是:在堆区开辟一块新的内存,用来存放新定义的String类型的对象。
6.1.1子串
String类的 substring() 方法可以从一个较大的字符串中提起出一个子串。
String greeting = "Hello World!"; //原字符串
String s = greeting.substring(0,5);// substring(int startIndex,int endIndex); 取值区间为[starIndex,endIndex)
substring(int starIndex,int endIndex) 是从基字符串的startIndex 位置开始复制 到endIndex 位置,但是不包括endIndex位置的字符
优点:子字符的长度容易计算:长度=endIndex – startIndex;
6.1.2 拼接
Java允许使用'+'连接(拼接)两个字符串。
常用示例:
String greeting = "Hello World!";
System.out.println("这是一个字符串"+greeting);//可以使用+连接两个字符串
6.1.3不可变字符串
String对象是不可变的。String类中每一个看起来会修改String值得方法实际上都是创建一个全新的String对象,以包含后的字符串内容。而最初的String对象丝毫未动。
以substring(int startIndex,int endIndex)方法的源码为例:
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > value.length) {
throw new StringIndexOutOfBoundsException(endIndex);
}
int subLen = endIndex - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return ((beginIndex == 0) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
}
可以发现当产生字符串时,是产生了一个新的String对象返回。
6.1.4检测字符串是否相等
- 使用equals方法来检测两个字符串时否相等
表达式: s.equals(t) 如果字符串s与字符串t则返回true;否则返回false。
S与t可以是字符串变量,也可以是字符串常量 。
String greeting = "Hello World!";
"Hello World!".equals(greeting);//合法
- 使用equalsIgnoreCase方法,不区分大小写检测两个字符串是否相等。
String greeting = "Hello World!";
System.out.println("hello world!".equalsIgnoreCase(greeting));//不区分打小写的比较两个字符是否相等
- 不能使用 == 符号判断两个字符串是否相等。这个运算符是只能够确定两个字符串是否放在同一个位置上。如果是放在同一位置上那么就相等
String greeting = "Hello World!"; //原字符串
String s = greeting.substring(0,5);
String get ="Hello";
System.out.println("使用==比较两个不共享字符串:"+(get==s));
System.out.println("使用==比较两个共享字符串:"+("Hello World!"=="Hello World!"));
实际上只有字符串常量是共享的,而+活substring的操作产生的字符串时不共享的。
6.1.5空串与null
- 空串 ""是长度为0的字符串
判断字符串是否为空串 str.length == 0 或str.equals("")
- 字符串还可以存放null值,当为字符串为 null时,不能调用方法
判断是否 为null
null == str
String empty = "";
System.out.println("empty是否为空串:"+("".equals(empty)));
String nullStr = null ;
System.out.println("nullStr是否为null:"+(nullStr == null));
nullStr.equals("");//编译时正确,运行时抛出异常: java.lang.NullPointerException.原因:nullStr 为null
6.1.6 String类API
下面 是一些常用的String类方法介绍:
- char charAt(int index)
返回给定位置的字符。
- int compareTo(String other)
按字典顺序,如果字符串位于other之前返回负数;如果字符串位于other之后,返回一个正数;如果两个字符串相等,返回0。
- boolean endsWith(Stirng suffix)
如果字符串以suffix结尾,返回true
- int length()
返回字符串的长度
- String replace(CharSequence oldString, CharSequence newString)
返回一个新的字符串,这个字符串用newString代替原始字符串中所有的oldString。可以用String或StringBuilder对象作为CharSequence参数
- boolean startsWith(String suffix)
如果字符串以suffix开始,返回true
- String toLowerCase()
返回一个新的字符串,把字符串所有的字符转化为小写
- String toUpperCase()
返回一个新的字符串,把字符串所有的字符转化为大写
- String trim()
返回一个新的字符串,去除字符串中头部和尾部的空格
示例:
步骤1,在Demo010项目的com.zjk.type包下创建StudyString类
源码:
package com.zjk.type;
public class StudyString {
public static void main(String[] args) {
String greeting = "Hello World!"; //原字符串
String get ="Hello";
String s = greeting.substring(0,5);// substring(int startIndex,int endIndex); 取值区间为[starIndex,endIndex)
System.out.println(s);
System.out.println("这是一个字符串"+greeting);//可以使用+连接两个字符串
System.out.println("比较两个字符串是否相等:"+("Hello World!".equals(greeting)));//合法
System.out.println("使用==比较两个不共享字符串:"+(get==s));
System.out.println("使用==比较两个共享字符串:"+("Hello World!"=="Hello World!"));
System.out.println("不区分大小写比较两个字符串是否相等:"+("hello world!".equalsIgnoreCase(greeting)));//不区分打小写的比较两个字符是否相等
String empty = "";//这是一个字符串
System.out.println("empty是否为空串:"+("".equals(empty)));
String nullStr = null ;
System.out.println("nullStr是否为null:"+(nullStr == null));
// nullStr.equals("");//编译时正确,运行时抛出异常: java.lang.NullPointerException.原因:nullStr 为null
/* API */
String ss = " Hello World!"; //原始字符串
System.out.println("ss字符串的长度为:"+(ss.length()));
System.out.println("ss的第3个字符为:"+(s.charAt(3)));
System.out.println(""kl"字符串在与ss字符串排序比较"+(ss.compareTo("kl")));
System.out.println("ss字符串是否是以"!"结尾"+(ss.endsWith("!")));
System.out.println("ss字符串是否是以" "开始"+(ss.startsWith(" ")));
System.out.println("用"hello world!"代替ss字符串中的"Hello World!""+(ss.replace("Hello World!", "hello world!")));
System.out.println("ss字符串全部变为大写:"+(ss.toUpperCase()));
System.out.println("ss字符串全部变为小写:"+(ss.toLowerCase()));
System.out.println("去除ss字符串头部和尾部的空格:"+(ss.trim()));
}
}
6.2可变字符StringBuilder和StringBuffer
6.2.1 StringBuilfer
每次连接字符串,都会构建一个新String对象,即耗时又浪费空间使用StringBuilder类可以避免这个问题的发生
第一:构建字符串构建器:
StringBuilder builder = new StringBuilder();//一个空的字符串构造器
StringBuilder builder2 = new StringBuilder("Hello");//一个有初始值的字符串构造器
第二: 需要添加内容时,调用append方法
builder.append("hello");//在字符串的后面添加一个字符串
第三:需要显示是调用toString方法
System.out.println(builder.toString());//输入
API文档:
- int length()
返回字符长度
- void setCharAt(int I,char c)
将第i位置的字符设置为c
- StringBuilder insert(int offset,String str)
在oddset位置插入字符str并返回插入后字符构建器
- StringBuilder delete(int startIndex,int endIndex)
删除startIndex位置到endIndex-1位置的字符串并返回删除后的字符构造器
示例:
步骤1: 在Demo010项目的com.zjk.type包下创建StudyStringBuilder类
源码:
package com.zjk.type;
/**
*
*@类名 StudyStringBuilder
*@日期 2015年11月29日下午3:04:34
*@作者 zjkorder
*@版本 v1.0
*@描述
* StringBuilder类的学习
* main方法所在类
*/
public class StudyStringBuilder {
public static void main(String[] args) {
StringBuilder builder = new StringBuilder();//一个空的字符串构造器
StringBuilder builder2 = new StringBuilder("Hello");//一个有初始值的字符串构造器
builder.append("hello");//在字符串的后面添加一个字符串
System.out.println(builder.toString());//输入
System.out.println("字符构建器的长度为:"+builder.length());
builder.setCharAt(0, 'H');//将第0位置的h更改为H
System.out.println("更改后的字符串为:"+builder.toString());
builder = builder.insert(0, 'h');//在第0位置插入h
System.out.println("更改后的字符串为:"+builder.toString());
builder = builder.delete(1, 2);//删除第1位置到2-1位置的字符
System.out.println("更改后的字符串为:"+builder.toString());
}
}
6.2.2 StringBuffer
在讲解StringBuffer类之前先来回顾一下String类特点:
一个字符串常量就是String类的匿名对象;
String类对象有两种实例化方式:
|-方式一:直接赋值,可以自动入池,只开辟一块内存空间;
|-方式二:构造方法实例化,会开辟两块空间,其中一块将成为垃圾,不会自动入池,可以使用intern()方法手工入池;
·字符串内容一旦声明则不可改变。
正是因为字符串内容一旦声明不可改变,所以如果在频繁修改字符串内容的程序上是不能够使用String的,那么为此在Java之中又提供有一个StringBuffer类,而String和StringBuffer类最大的特征在于:String不可改变内容,而StringBuffer可以改变。在String类对象之中使用"+"可以实现字符串连接操作,但是在StringBuffer类之中只能够使用append()方法实现字符串连接:public StringBuffer append(数据类型b)。既然返回的是StringBuffer就可以一直使用append()连接。
跟StringBuilder类的方法组相似。
6.2.3 String StringBuilder和StringBuffer的比较
String、StringBuffer、StringBuilder的区别:
- String不适合于字符串的频繁修改,而StringBuffer和StringBuilder适合于频繁修改,而且速度要远远高于String;
- StringBuffer是在JDK 1.0的时候引入的,而StringBuilder是在JDK 1.5的时候引入的,而且StringBuffer和StringBuilder继承结构相同,方法的组成也相同;
- StringBuffer中的所有方法都使用synchronized进行标记,都是同步方法,性能相对较低,而StringBuilder采用的异步处理,性能相对较高,但是StringBuffer在多线程操作时的数据安全性要高于StringBuilder。
6.3输入
需要在控制台输入需要Scanner的对象。
System.out 是标准输出流那么System.in 就是标准输入流
第一:构建Scanner对象
Scanner input = new Scanner(System.in);//构建控制台接收对象
第二:读取读取输入的一行数据
String ss = input.nextLine();//接收控制台输入的一行数据并保存到SS字符串中
第三: 关闭Scanner
input.close();//关闭控制台的接收器
Scanner 的常用方法有:
- String next()
读取输入的单词以空格作为分割
- Int nextInt()
读取输入的整数返回int型数据
- double nextDouble()
读取输入的浮点数
- boolean hasNext()
检测输入中是否还有其他单词
- boolean hasNextInt()
检测输入中是否还有其他整数
- boolean hasNextDouble()
检测输入中是否还有其他浮点数