一 字符串
1.String概述及特点
String 类代表字符串,是一个特殊的对象。
Java 程序中的所有字符串(如 "abc" )都作为此类的实例实现。
字符串是常量;字符串最大的特点是,它们的值在创建之后不能更改。
字符串缓冲区支持可变的字符串。因为 String对象是不可变的,所以可以共享。
(1)初始化过程
String s1="abc"
String s1="efg" //变化的是s1的内存地址,字符串最大的特性是一旦被初始化就不可以被改变。
s1是一个类类型变量,“abc”是一个对象,创建的过程是在JVM的栈内存中产生一个s变量,堆内存中产生abc字符串对象。s指向了abc的地址。像上面这种方式产生的字符串属于直接量字符串对象,JVM在处理这类字符串的时候,会进行缓存,产生时放入字符串池,当程序需要再次使用的时候,无需重新创建一个新的字符串,而是直接指向已存在的字符串。
(2)equals和“==”号区别
class Test2
{
publicstatic void main(String[] args)
{
//字符串==和equals的区别
Strings="hello world";
Strings1=new String("hello world");
Strings2=new String("hello world");
Strings3=new String("hello");
Strings4="hello world";
System.out.println(s.equals(s1));
System.out.println(s1.equals(s2));
System.out.println(s2.equals(s3));
System.out.println(s.equals(s4));
System.out.println("----------");
System.out.println(s==s1);
System.out.println(s1==s2);
System.out.println(s2==s3);
System.out.println(s==s4);
}
}
运行结果
true
true
false
true
----------
false
false
false
true
通过结果可以看出,比较方法equals()和==的区别,一句话:equals()比较的是对象的内容,也就是JVM堆内存中的内容,==比较的是地址,也就是栈内存中的内容。
注意:
对于Object类而言,原生的equals()方法,必须两个对象的地址和内容都一样才返回true,同时Object类原生的hashCode()是参照对象的地址和内容根据一定的算法生产的。所以原生的hashCode()只有调用equals()返回true才相等。而String类不同,String类重写了Object的equals(),放松了条件,只要对象地址或者内容相等就返回true,同时,String类重写了hashCode()方法,只要内容相等,则调用hashCode返回的整数值也相等
s和s1有什么区别
s在内存中只有一个对象。
S1在内存中有俩个对象。
(3)常量池
常量池一般就是指字符串常量池,是用来做字符串缓存的一种机制,当我们在程序中写了形如String s = "abc"这样的语句后,JVM会在栈上为我们分配空间,存放变量s和对象”abc“,当我们再次需要abc对象时,如果我们写下:String s1 = "abc"的语句时,JVM会先去常量池中找,如果不存在,则新创建一个对象。如果存在,则直接将s1指向之前的对象”abc“,此时,如果我们用==来判断的话,返回的true。这样做的好处就是节省内存,系统响应的速度加快,(因为省去了对象的创建时间)这也是缓存系统存在的原因。
常量池是针对在编译期间就确定下来的常量而言的。但是,当类被加载后,常量池会被搬到方法区的运行时常量池,此时就不再是静态的了,那么是不是就不能向常量池中添加新的内容了呢?答案是否定的,我们依然可以在运行时向常量池添加内容!这就是我们说过的String类有个方法叫intern(),它可以在运行时将新的常量放于常量池。
补充:
intern返回字符串一个规范的表示。比如:有两个字符串s和t,s.equals(t),则s.intern()==t.intern()
intern()做到了一个很不寻常的行为:在运行期动态的在方法区创建对象,一般只有像new关键字可以在运行期在堆上面创建对象,所以此处比较特殊。属于及时编译的概念。
2.string常见操作
string类描述字符串事物,那么他提供了多个方法对字符串进行操作。
(1)获取
(1)public int length()返回此字符串的长度。
(2)public char charAt(int index) 根据位置获取某个位置上的字符。
(3)public int indexOf(int ch) 返回ch在字符串中第一次出现的位置。
public int indexOf(int ch,int fromIndex)
从指定的索引开始搜索,返回在此字符串中第一次出现指定字符处的位置。
publicint indexOf(String str)返回指定子字符串在此字符串中第一次出现处的位置。
publicint indexOf(String str, int fromIndex)
从指定的索引开始,返回指定子字符串在此字符串中第一次出现处的位置。
public int lastIndexOf(int ch) 和indexOf相反,从右往左查找。
(2)判断
(1)public boolean contains(CharSequence s) 字符串中是否包含某一个字符。如果此字符串包含 s,则返回 true,否则返回 false
特殊之处:indexOf(stringstr):可以索引str第一次出现位置,如果返回-1,表示str不在字符串中存在,所以也可以用于对指定判断是否包含;所以该方法即可以判断,又可以获取出现位置。
(2)public boolean isEmpty() 字符中是否有内容。如果长度为 0,则返回 true;否则返回 false。
(3)public boolean startsWith(String prefix) 字符串是否是以指定内容开头。
(4)public boolean endsWith(String suffix)字符串是否是以指定内容结尾。
(5)public boolean equals(Object anObject)判断字符串内容是否相同,复写了Object类中的equals()方法。
(6)compareTo() ------判断字符串的大小关系。
(7)public boolean equalsIgnoreCase(String anotherString)判断内容是否相同,并忽略大小写;
(3)转换
(1)将字符数组转换成字符串;
构造函数:String (char [ ])String(char [ ],offset,count)
将字符数组的一部分转换为字符串。
静态方法:public staticString copyValueOf(char[] data)
public static String copyValueOf(char[]data, int offset, int count)
(2)将字符串转换成字符数组;
public char[] toCharArray()
(3)将字节数组转换成字符串;
构造函数:public String(byte[] bytes)
public String(byte[] bytes,Charset charset)将字节数组的一部分转换为字符串。
(4)将字符串转换成字节数组;
public byte[] getBytes()
public byte[] getBytes(Charsetcharset)
特殊;字符串和字符数组在转换过程中,是可以指定编码表的。
(5)将基本数据类型转换为字符串;(没有字节数组,因为字节数组是最小单位)
(4)替换
public String replace(char oldChar,charnewChar)如果要替换的字符串不存在,则返回原字符串
public String replaceAll(Stringregex,String replacement)
(5)切割
public String[] split(String regex)按照regex字符切割字符串。
截取字符串的一部分;
public String substring(int beginIndex)从指定位置开始到结尾,
public String substring(int beginIndex,intendIndex)包含头,不包含尾。
(6)转换、去除空格、大小写转换;
(1)将字符串转换成大小写;
public String toLowerCase() 将String中的所有字符都转换为小写。这等效于调用toLowerCase(Locale.getDefault())。
public String toLowerCase(Locale locale)使用给定 Locale 的规则将此 String 中的所有字符都转换为小写。大小写映射关系基于 Character 类指定的 Unicode 标准版。由于大小写映射关系并不总是 1:1 的字符映射关系,因此所得 String 的长度可能不同于原 String。
(2)将字符串两端多个空格去除空格
public String trim()返回字符串的副本,忽略前导空白和尾部空白。
(3)对俩个字符串进行自然顺序的比较。
public int compareTo(String anotherString)对俩个字符串进行自然顺序比较。
3、stringbuffer
是字符串缓冲区,他是一个容器(面盆原理)。
其实在使用方法,StringBuffer的许多方法和String类都差不多,所表示的功能几乎一模一样,只不过在修改时StringBuffer都是修改自身,而String类则是产生一个新的对象,这是他们之间最大的区别。
StringBuffer类是线程安全的可变字符序列。一个类似于 String 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。
可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。
特点;
长度可以变化;
可以操作多种数据类型;
最终会通过tostring方法返回字符串。
在StringBuffer的使用方面,它更加侧重于对字符串的变化,例如追加、修改、删除,相对应的方法:
追加:
public StringBuffer append();可以将指定数据作为参数添加到已有数据结尾处。
public StringBuffer insert(int offset,数据)可以将数据插入到指定的位置。
删除;delete:该类方法主要用于移除StringBuffer对象中的内容。
反转;stringbuffer reverse();
将缓冲区中指定数据反转后存储到指定字符数组中。
注意:Stringbuffer没有重写Object的equals方法,所以判断时,必须要内容和地址都相同。
4、StringBuilder
此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。
StringBuffer 线程同步
StringBuilder线程不同步
以后开发建议使用StringBuilder
StringBuilder是jdk1.5版本之后出现的
升级的三个因素;提高效率,简化书写,提高安全性。
5.string和stringbuffer和stringBuileder的区别。
(1)内存方面
简单地说,就是一个变量和常量的关系。
StringBuffer对象的内容可以修改;而String对象一旦产生后就不可以被修改,重新赋值其实是两个对象。
StringBuffer的内部实现方式和String不同,StringBuffer在进行字符串处理时,不生成新的对象,在内存使用上要优于String类。所以在实际使用时,如果经常需要对一个字符串进行修改,例如插入、删除等操作,使用StringBuffer要更加适合一些。
在String类中没有用来改变已有字符串中的某个字符的方法,由于不能改变一个java字符串中的某个单独字符,所以在JDK文档中称String类的对象是不可改变的。然而,不可改变的字符串具有一个很大的优点:编译器可以把字符串设为共享的。
(2)速度方面
string<stringbuffer<stringbuilder。
这时因为string是字符串常量,stringbuffer是字符串变量(线程安全),stringbuilder也是字符串变量(线程非安全)
当我们在字符串缓冲去被多个线程使用是,JVM不能保证StringBuilder的操作是安全的,虽然他的速度最快,但是可以保证StringBuffer是可以正确操作的。当然大多数情况下就是我们是在单线程下进行的操作,所以大多数情况下是建议用StringBuilder而不用StringBuffer的,就是速度的原因。
(3)在什么情况下使用哪个?
String:在字符串不经常变化的场景中可以使用String类,如:常量的声明、少量的变量运算等。
Stringbuffer:在频繁进行字符串的运算(拼接、替换、删除等),并且运行在多线程的环境中,则可以考虑使用StringBuffer,例如XML解析、HTTP参数解析和封装等。
Stringbuilder:在频繁进行字符串的运算(拼接、替换、删除等),并且运行在多线程的环境中,则可以考虑使用StringBuffer
二基本数据类型包装类
Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的,这在实际使用时存在很多的不便,为了解决这个不足,在设计类时为每个基本数据类型设计了一个对应的类进行代表,将其封装成对象。这样八个和基本数据类型对应的类统称为包装类(Wrapper Class),有些地方也翻译为外覆类或数据类型类。这样基本数据类型对象描述中就可以定义更多的属性和行为对该基本数据类型进行操作。
1、基本类型对应图
基本数据类型对象包装类最常用的就是用于数据类型与字符串转换。对应图如下:
基本数据类型 | 基本数据类型包装类 |
byte | Byte |
short | Short |
int | Integer(特殊) |
long | Long |
double | Double |
flout | Flout |
char | character( 特殊) |
boolean | Boolean |
2、基本类型与字符串的相互转换
(1)基本类型转换成字符串
A:基本数据类型+""
B:基本数据类型对象包装类中的方法:static String tostring(基本类型)
C: String类中的方法: static String valueOf(基本类型)
(2)字符串转换成基本类型
Integer i=newInteger("123"); intnum=i.intValue(); 构造函数
integer.parseint(”1123“)将字符串转换成整数。
double.parsedouble("11.12")将字符串转换成浮点型。
Long.parseLong(String str);将字符串转换成长整型数。
注意:其他的基本数据类型都是这种个格式,但是需要注意的是char类型没有转换方式,因为字节是字符的一个单位,字符中的操作字节中都有方法。
(3)基本类型转换成包装类
A:Integer i=new Integer(123); 构造函数
B:static Integer valueOf(int);
异常:类型转换错误——NumberFormatException
注意:如果两数被封装成了对象该如何比较呢?
对象想要进行比较,必须通过方法来完成,这个方法就是compareTo。
而很多对象都可以进行比较。所以这个方法定义在Comparable接口中。
想要对象具备比较功能,只要实现Comparable接口。
3、进制之间的转换
(1)十进制转其他进制
toBinaryString( ) 二进制
toHexString( ) 16进制
toOctalString( ) 八进制
(2)其他进制转十进制
Integer.toString(6 , 2); 将6转换为二进制。
parseInt(intString , radix);将intstring转换成radix进制。
4. 自动拆箱,装箱
基本数据类型对象包装类JDk1.5以后的新特性
Integer x=new Integer("123");
Integer y=new Integer(123);
x==y是false 重新创建了一个对象
x.equals(y)是true 内容是相同的。
基本数据类型对象包装类,对象创建的简化写法Integeri = 5;
1. Integer i = 5;(其实在内存中也是通过 new Integer(5)这种方式创建的!)
这种方式成为——自动装箱,Integer.valueOf(5)自动完成了对象创建的动作。
2. 在进行 i = i + 5,运算时——
= 右边的i 会先转成基本数据值(自动拆箱)i.intValue(),其实质为:
i = i.intValue() + 5 ;然后再和5进行加法运算。
= 右边运算完的结果,再次被自动装箱变成Integer对象赋给i.
一旦简化就有弊端:多具备一个值null. 使用自动装箱拆箱时,要进行null的健壮性判断。
在JdK1.5的新特性自动装箱中,如果数值在byte类型范围内(-128 ~ 127)。如果该对象数值重复出现
多个引用其实是指向同一个Integer对象,节省空间!但是超出了byte范围,都会生产新的Integer对象。
Integer m = 127;
Integer n = 127;
System.out.println( m == n); //true
System.out.println(m.equals(n)); //true
【异常】
Integer x = null;
x = x.intValue() + 4;
x为null 不能调用方法,此时会发生:NullPointerException异常。
注意:
Boolean b = true;
boolean b = true;的区别
前者:类类型变量指向一个对象,true为一个对象;
后者:true为基本类型变量。
5、常见操作
(1)删除
public void getChars(int srcBegin,intsrcEnd,char[] dst,int dstBegin)
public StringBuffer delete(int start, intend),删除缓冲区指定位置的内容,包含头不包含尾
delete(0,str.length())删除缓冲区中所有的内容;
delete(1,2)和deletecharat(1)相同,删除一个字符;
(2)获取;
char charat(int index)
int indexof(String s)
int lastindexof(string s)
int length() 获取长度
(3)修改;
public StringBuffer replace(int start,intend,String str),指定内容插入到指定位置
public void setCharAt(int index, char ch)指定位置及修改内容