一. 两种创建String对象的方式:
1. 直接赋值: String s="hsp";
这种方式要先从常量池中查看是否有"hsp"的数据空间,如果有则直接指向; 如果没有则重新创建,然后指向.s最终指向的是常量池中的空间地址 ;
2. 调用构造器 String s2=new String("hsp");
首先我们要知道String类中有一个private final char value[] 数组,这个value数组是final的,也就是说value内的值可以改变,但是地址不能改变 ;
这种方式先在堆中创建空间, 里面维护了value属性, value先去常量池中找hsp空间. 如果常量池中没有"hsp", 重新创建,如果有,则直接通过value指向"hsp"的空间 ,s2最终指向的是堆中的空间地址.
二. 调用String 类对象的intern方法 :
当调用intern方法,如果常量池中已经包含一个等于此String对象的字符串,则返回常量池中的字符串; 否则将此String对象添加到常量池中,并返回此String对象的引用; 也就是说原来String对象是指向堆中的引用, 但是只要使用intern方法最终就会指向常量池中的地址 .
举例: String b=new String("hsp");
System.out.println( b==b.intern() ); //False(一个指向堆中的对象,一个指向常量池中的对象)
三. 比较是否相等
解题过程: 画出内存图可以清晰的看出它们的引用分别指向谁,以此得出答案
public class test_08 {
public static void main(String[] args) {
Person p1=new Person();
p1.setName("hsp");
Person p2=new Person();
p2.setName("hsp");
System.out.println(p1.getName().equals(p2.getName())); //T
System.out.println(p1.getName()== p2.getName()); //T
System.out.println(p1.getName()=="hsp"); //T
String s1=new String("abc");
String s2=new String("abc");
System.out.println(s1==s2); //F
}
}
" == " 比较String类型时比较的是对象也就是它们的引用 :
四. 分析如何创建的对象: 时刻清楚它们的引用是谁 :
public class test_09 {
public static void main(String[] args) {
//这个只创建了一个对象123456在常量池中,不会先创建123再创建456,最后再创建一个123456;
String s="123"+"456";
//a和b都是指向常量池中的两个对象hello和abc
String a="hello";
String b="abc";
//这个c指向的是堆中的对象,通过value指向常量池中第三个对象helloabc,间接获取
String c=a+b;
//所以最终创建了三个对象
}
}
五. 例题分析 :
public class test_09 {
String str=new String("hsp");
final char[] ch={'j','a','v','a'};
public void change(String str,char ch[])
{
str="java";
ch[0]='h';
}
public static void main(String[] args) {
test_09 ex=new test_09();
ex.change(ex.str,ex.ch);
System.out.print(ex.str+" and ");
System.out.println(ex.ch);
//最终输出hsp and hava
}
}
六 .String类的常用方法:
由于String类保存的是字符串常量 , 由final修饰的 ;
例如: String s="hsp"; 当改变s时让s="edu" ; 不会改变常量"hsp" , 而会改变s所指向的地址让s指向"edu" ,所以基于这种final修饰的String类每次更新值都得再重新开辟一块空间, 效率较低 ,所以提供了StringBuilder和StringBuffer 来增强String的功能 ,并提高效率.
public static void main(String[] args) {
//1. equals()方法已经被String类重写,所以比较内容是否相等,并区分大小写:
String str1="hello";
String str2="Hello";
System.out.println(str1.equals(str2));//输出false
//2. equalsIgnoreCase()方法可以忽略大小写,判断内容是否相等:
String name="john";
if("JOHN".equalsIgnoreCase(name))
{
System.out.println("Success!"); //会输出Success!
}
else
{
System.out.println("Failure!");
}
//3. length()方法可以获取字符的个数,字符串的长度:
System.out.println(name.length()); //输出长度4
//4. indexOf()方法获取字符在字符串对象中第一次出现的索引,索引从0开始,如果找不到返回-1:
String s1="wer@ter@weq";
int index=s1.indexOf('@');
System.out.println(index); //输出索引3
System.out.println("weIndex= "+s1.indexOf("we")); //也可以查找字符串,输出的是索引0
//5. lastIndexOf()方法获取字符在字符串中最后一次出现的索引,索引从0开始,如果找不到返回-1:
index=s1.lastIndexOf('@');
System.out.println(index); //输出索引7
System.out.println("terIndex= "+s1.lastIndexOf("ter")); //输出索引4
//6. substring()方法用于截取指定范围的子串:
name="hello,张三";
//这个表示从索引6开始(包含第6个字符)往后截取所有的字符: 输出张三
System.out.println(name.substring(6));
//这个表示从索引0开始往后截取5个字符(不包含第5个字符): 输出hello
//就相当于从索引0开始,往后数5个,正好到字符o的位置,截取输出hello
System.out.println(name.substring(0,5));
}
public static void main(String[] args) {
//1. toUpperCase()方法转换成大写:
String s="heLLo";
System.out.println(s.toUpperCase()); //输出HELLO
//2. toLowerCase()方法转换成小写:
System.out.println(s.toLowerCase()); //输出hello
//3.concat()方法拼接字符串:
String s1="宝玉";
s1=s1.concat("林黛玉").concat("薛宝钗").concat("together");
System.out.println(s1); //输出 :宝玉林黛玉薛宝钗together
//4. replace()方法替换字符串中的字符:
s1="宝玉 and 林黛玉 林黛玉 林黛玉";
//s1=s1.replace("林黛玉","薛宝钗");
//System.out.println(s1); //输出 :宝玉 and 薛宝钗 薛宝钗 薛宝钗
//注意!!! s1.replace() 方法执行后,返回的结果才是替换过的
// 对s1没有影响,说明s1.replace方法替换不是对s1做改变而是又新创建了个字符串,体现了final
//如果把上面的s1注释掉,变成下面这样:
String s11=s1.replace("林黛玉","薛宝钗");
System.out.println(s11); //输出: 宝玉 and 薛宝钗 薛宝钗 薛宝钗
System.out.println(s1); //输出: 宝玉 and 林黛玉 林黛玉 林黛玉
//5. split()方法用于分割字符串,对于某些分割字符,我们需要转义比如| \\等
String poem="锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦";
String[] split=poem.split(",");
for(int i=0;i< split.length;i++) //注意数组使用属性length,没有括号
{
//输出:
// 锄禾日当午
// 汗滴禾下土
// 谁知盘中餐
// 粒粒皆辛苦
System.out.println(split[i]);
}
poem="E:\\aa\\bbb";
//本意是想用\\来分割,但是这是特殊字符,所以需要转义字符\来对特殊字符\\转义
split=poem.split("\\\\"); //在每个分隔符\前面都需要加上转义字符\
for(int i=0;i< split.length;i++)
{
//输出:
// E:
// aa
// bbb
System.out.println(split[i]);
}
//6.toCharArray()方法转换成字符数组:
s="happy";
// for(int i=0;i<s.length();i++)
// {
// System.out.println(s[i]); 在java中不能直接通过索引输出字符串内容
// }
char[] chs=s.toCharArray();
for(int i=0;i<chs.length;i++)
{
System.out.print(chs[i]+" "); //输出:h a p p y
}
System.out.println();
//7.compareTo()方法比较两个字符串大小:如果前者大则返回正数,后者大返回负数,相等返回0:
String a="jaak";
String b="jabk";
//先比较长度,长度相等再挨个比较字符,第三个a小于b则做差输出结果
System.out.println(a.compareTo(b)); //输出-1是'a'-'b'的结果
a="ja";
//先比较长度,如果长度不等用前者-后者为输出的结果
System.out.println(a.compareTo(b)); //输出-2是长度2-长度4的结果
a="jabk";
System.out.println(a.compareTo(b));//输出0,说明长度相等,每个字符也相等
//8.format() 方法用于格式化字符串,类似printf(),是个类方法
String name="john";
int age=10;
double score=98.3/3;
char gender='男';
String info=String.format("我的名字是%s 年龄是%d,成绩是%.2f,性别是%c,希望大家喜欢我!",name,age,score,gender);
System.out.println(info); //输出: 我的名字是john 年龄是10,成绩是32.77,性别是男,希望大家喜欢我!
}