一、String的实例化两种方式
1、直接赋值实例化:
String StringName= "xxx";
- 1
以上是String对象的直接赋值,以上的代码并没有使用关键字new进行。String类也是类,所以也有构造方法。
2、使用构造方法实例化:
public String(String str);
- 1
可以通过构造方法为String类对象实例化,但在构造里面依然要接收一个本类对象。
二、字符串的比较
如果要想知道两个int型变量是否相等,使用“==”进行验证,在String中也可以使用“==”来进行比较。我们来看一个例子:
public class StringDemo {
public static void main(String args[]) {
String str1 = "Hello" ;
String str2 = new String("Hello") ;
String str3 = str2 ; // 引用传递
System.out.println(str1 == str2) ;
System.out.println(str1 == str3) ;
System.out.println(str2 == str3) ;
}
}
运行结果:
false
false
true
发现使用“==”好象最终的判断结果是不一样的,为什么呢?下面通过内存关系图来分析:
通过以上分析可以发现,“==”比较的不是字符串对象包含的内容,而是两个对象所在的的内存对象的数值。所以“==”属于数值比较,比较的是内存地址。
如果想比较字符串的内容,可以使用String类的equals()方法。
public class StringDemo {
public static void main(String args[]) {
String str1 = "Hello" ;
String str2 = new String("Hello") ;
String str3 = str2 ; // 引用传递
System.out.println(str1.equals(str2)) ;
System.out.println(str1.equals(str3)) ;
System.out.println(str2.equals(str3)) ;
}
}
运行结果:
true
true
true
于是,现在比较的不是字符串的内存地址的数值,而是字符串的内容。
小结:
(1) ==:比较的是两个字符串内存地址的数值是否相等,属于数值比较;
(2)equals():比较的是两个字符串的内容,属于内容比较。
三、字符串常量是匿名对象
在各个语言中并没有提供字符串的数据类型定义,很多语言都是使用字符数组来描述字符串的概念,在Java中也没有字符串的概念,只是Java自己做了简单处理。但是在Java中字符串依然不属于基本数据类型,字符串是作为String类的匿名对象的形式存在的。
字符串是匿名对象的验证:
public class StringDemo {
public static void main(String args[]) {
String str = "Hello" ;
// 通过字符串调用方法
System.out.println("Hello".equals(str)) ;
}
}
运行结果:
true
匿名对象可以调用类中的方法与属性,而以上的字符串调用了equals()方法,所以它一定是一个对象。
四、String类对象两种实例化方式的区别
String类对象存在两种实例化的操作形式,那么这两种有什么区别,在开发之中应该使用那一种更好呢?
1、直接赋值的实例化方式:
String str = "Hello" ;
此时,只分配了一块堆内存空间和一块栈内存空间:
再看一下代码:
public class StringDemo {
public static void main(String args[]) {
String str1 = "Hello" ;
String str2 = "Hello" ;
String str3 = "Hello" ;
System.out.println(str1 == str2) ;
System.out.println(str1 == str3) ;
System.out.println(str2 == str3) ;
}
}
运行结果:
true
true
true
我们发现以上所有直接赋值的String类对象的内存地址完全相同,内存分配图如下:
在设计String类的时候采用了一种称为共享设计模式的概念。在运行的JVM底层存在一个字符串的对象池(Object Pool),如果用户采用了直接赋值的方式时,会将字符串的内容放入池保存,如果以后其他String对象继续使用直接赋值方式实例化,并且设置了同样的内容时,那么将不会分配新的堆内存空间,而是使用已有对象的引用进行分配继续使用。如果新声明的字符串内容不在对象池中,则会分配一个新的,然后继续放到池中以供下次使用。
2、采用构造方法实例化的方式:
使用构造方法实例化一定要用到new关键字,而一旦使用了new就表示要分配新的内存空间。
String str = new String("Hello") ;
内存分配图如下:
从上可以发现,分配了两块堆内存空间,其中一块是垃圾。这样处理内存的浪费外,使用构造方法定义的String类对象,其内容不会保存在对象中(因为重新分配了新的一块堆内存)。
现在希望使用构造方法定义的String类对象,其内容要保存在对象中,该怎么办么?我们可以使用String类定义的一个手工入池的方法:
public String intern()
范例如下:
public class StringDemo {
public static void main(String args[]) {
String str1 = new String("Hello").intern() ;
String str2 = "Hello" ; // 入池
String str3 = "Hello" ; // 使用池对象
System.out.println(str1 == str2) ;
System.out.println(str1 == str3) ;
System.out.println(str2 == str3) ;
}
}
运行结果:
true
true
true
小结:String类对象两种实例化的区别?
(1)直接赋值实例化方式(String str = “xxx”):只会分配一块堆内存空间,并且对象内容自动入池,以供重复使用;
(2)构造方法实例化方式(String str = new String(“xxx”)):会分配两块堆内存空间,其中有一块是垃圾,并且不会自动入池,用户可以使用intern()方法手动入池。
五、字符串的内容一旦定义则不可改变
先看一段代码:
public class StringDemo {
public static void main(String args[]) {
String str = "Hello " ;
str += "World " ;
str = str + "!!!" ;
System.out.println(str) ;
}
}
运行结果:
Hello World !!!
我们通过内存分配图分析一下:
通过以上的分析可以发现:字符串内容的更改,实际上改变的是字符串对象的引用过程,并且会伴随有大量的垃圾出现,在实际开发中应该避免。
一、字符串的常用方法 — 字符与字符串
很多编程语言利用了字符数组的概念来描述字符串的概念,在String类的方法上也有所体现。
一个例子:字符串和字符数组转换,完成一个小写字符串变为大写字符串的操作
public class StringDemo {
public static void main(String args[]) {
String str = "helloworld" ;
char data [] = str.toCharArray() ; // 字符串变为字符数组
for (int x = 0 ; x < data.length ; x ++) {
System.out.print(data[x] + "、") ;
data [x] -= 32 ; // 变大写
}
System.out.println();
System.out.println("全部字符数组变为字符串:" + new String(data)) ;
System.out.println("部分字符数组变为字符串:" + new String(data,0,5)) ;
}
}
运行结果:
h、e、l、l、o、w、o、r、l、d、
全部字符数组变为字符串:HELLOWORLD
部分字符数组变为字符串:HELLO
二、字符串的常用方法 — 字节与字符串
字节使用byte描述,字节一般用在数据的传输和进行编码转换的时候使用。String中也提供相应的方法,来进行数据传输和编码转换。
一个例子:完成一个小写字母变为大写字母的操作
public class StringDemo {
public static void main(String args[]) {
String str = "helloworld" ;
byte data [] = str.getBytes() ; // 字符串变为字节数组
for (int x = 0 ; x < data.length ; x ++) {
System.out.print(data[x] + "、") ;
data [x] -= 32 ; // 变大写
}
System.out.println() ;
System.out.println("全部字节数组变为字符串:" + new String(data)) ;
System.out.println("部分字节数组变为字符串:" + new String(data,0,5)) ;
}
}
运行结果:
104、101、108、108、111、119、111、114、108、100、
全部字节数组变为字符串:HELLOWORLD
部分字节数组变为字符串:HELLO
三、字符串的常用方法 — 字符串比较
一个例子:
public class StringDemo {
public static void main(String args[]) {
String str1 = "helloworld" ;
String str2 = "HELLOWORLD" ;
System.out.println(str1.equals(str2)) ;
System.out.println(str1.equalsIgnoreCase(str2)) ;
}
}
运行结果:
false
true
四、字符串的常用方法 — 字符串查找
一个例子:判断开头和结尾操作
public class StringDemo {
public static void main(String args[]) {
String str = "**@@hello##" ;
System.out.println(str.startsWith("**")) ;
System.out.println(str.startsWith("@@",2)) ;
System.out.println(str.endsWith("##")) ;
}
}
运行结果:
true
true
true
另外一个例子:使用contains()方法查找字符串是否存在,直接返回boolean,用于各种的执行判断
public class StringDemo {
public static void main(String args[]) {
String str = "helloworld" ;
System.out.println(str.contains("hello")) ;
System.out.println(str.contains("xx")) ;
}
}
运行结果:
true
false
五、字符串的常用方法 — 字符串替换
一个例子:
public class StringDemo {
public static void main(String args[]) {
String str = "Hello World ." ;
System.out.println(str.replaceAll("l","_")) ;
System.out.println(str.replaceFirst("l","_")) ;
}
}
运行结果:
He__o Wor_d .
He_lo World .
六、字符串的常用方法 — 字符串截取
例子:
public class StringDemo {
public static void main(String args[]) {
String str = "Hello World ." ;
System.out.println(str.substring(6)) ;
System.out.println(str.substring(0,5));
}
}
运行结果:
World .
Hello
七、字符串的常用方法 — 字符串拆分
例子:
public class StringDemo {
public static void main(String args[]) {
String str = "Hello World !!!" ;
String result [] = str.split(" ") ;
for (int x = 0 ; x < result.length ; x ++) {
System.out.println(result[x]) ;
}
}
}
运行结果:
Hello
World
!!!
八、字符串的常用方法 — 其他方法
例子1:取得字符串长度和是否为空
public class StringDemo {
public static void main(String args[]) {
String str = "hello" ;
System.out.println(str.isEmpty()) ;
System.out.println("".isEmpty()) ;
System.out.println(str.length()) ;
System.out.println(" Hello ".length()) ; // 空格也计算
}
}
运行结果:
false
true
5
14
例子2:
public class StringDemo {
public static void main(String args[]) {
String str = "Hello World !~!!" ;
System.out.println(str.toUpperCase());
System.out.println(str.toLowerCase());
System.out.println("Hello ".concat("World .")); // +也可以
}
}
运行结果:
HELLO WORLD !~!!
hello world !~!!
Hello World .
StringBuffer append():将指定数据作为参数添加到已有数据结尾处。
StringBuffer insert(index,数据):可以将数据插入到指定index位置。
2,删除。
StringBuffer delete(start,end):删除缓冲区中的数据,包含start,不包含end。
StringBuffer deleteCharAt(index):删除指定位置的字符。
3,获取。
char charAt(int index)
int indexOf(String str)
int lastIndexOf(String str)
int length()
String substring(int start, int end)
4,修改。
StringBuffer replace(start,end,string);
void setCharAt(int index, char ch) ;
5,反转。
StringBuffer reverse();
6,
将缓冲区中指定数据存储到指定字符数组中。
void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
JDK1.5 版本之后出现了StringBuilder.
StringBuffer是线程同步。
StringBuilder是线程不同步。
以后开发,建议使用StringBuilder
升级三个因素:
1,提高效率。
2,简化书写。
3,提高安全性。
- class StringBufferDemo
- {
- public static void main(String[] args)
- {
- //method_update();
- StringBuilder sb = new StringBuilder("abcdef");
- char[] chs = new char[6];
- sb.getChars(1,4,chs,1);//将
- for(int x=0; x<chs.length; x++)
- {
- sop("chs["+x+"]="+chs[x]+";");
- }
- draw(3,6);
- draw(8,9);
- // StringBuilder sb1 = new StringBuilder();
- // sb1.append(new Demo()).append(new Demo());
- // sop("sb1="+sb1);
- }
- public static void method_update()
- {
- StringBuffer sb = new StringBuffer("abcde");
- // sb.replace(1,4,"java");
- sb.setCharAt(2,'k');
- sop(sb.toString());
- }
- public static void method_del()
- {
- StringBuffer sb = new StringBuffer("abcde");
- // sb.delete(1,3);
- //清空缓冲区。
- //sb.delete(0,sb.length());
- //sb.delete(2,3);
- sb.deleteCharAt(2);
- sop(sb.toString());
- }
- public static void method_add()
- {
- StringBuffer sb = new StringBuffer();
- //sb.append("abc").append(true).append(34);
- // StringBuffer sb1 = sb.append(34);
- // sop("sb==sb1:"+(sb==sb1));//true
- sb.insert(1,"qq");
- sop(sb.toString());//abctrue34
- //sop(sb1.toString());
- }
- public static void sop(String str)
- {
- System.out.println(str);
- }
- public static void draw(int row,int col)
- {
- StringBuilder sb = new StringBuilder();
- for(int x=0; x<row; x++)
- {
- for(int y=0; y<col; y++)
- {
- sb.append("*");
- }
- sb.append("\r\n");
- }
- sop(sb.toString());
- }
- }