初学JAVA-17-String

            在JAVA已经实现的各种类中,java.lang.String是一个非常特殊的类。String的意思是字符串,通常是由一对字符组成,我们之前已经看过很多例子了。字符串的值用双引号包起来,允许包含各种字符,一个比较特殊的字符串是"",这是一个空字符串,它的长度为0,但是它是一个正常的字符串,不同于null。

        为什么说String是一个很特殊的类,因为在我们日常的java程序中,大部分的时间都是用来处理各种文本文字信息,相信大家也能想象得到,我们每天打交道的也就是一个个句子,一段段话,在你的excel里面,word里面也是一个个的字符串,你需要输出给用的报表,也是一个个字符串组成的。

        字符串的使用时如此之频繁,试想如果String不做点特殊处理,那么VM将不断的为了创建和销毁字符串对象而消耗大量的时间和资源。我们先来看个简单的对比。

public class F{
	private String name;
	
	public void setName(String name){
		this.name = name;
	}
	
	public String getName(){
		return this.name;
	}
	
	public void print(){
		System.out.println(this.name);
	}
	
	public static void main(String[] args){
		 F f1 = new F();
		 F f2 = f1;
		 F f3 = new F();
		 System.out.println(f1==f2);
		 System.out.println(f1==f3);
		 f1.setName("good");
		 f3.setName("good");
		 f1.print();
		 f2.print();
		 System.out.println(f1==f2);
		 System.out.println(f1==f3);
		 
		 String s = "abc";
		 String s1 = s;
		 System.out.println(s==s1);
		 s = s + "cba";
		 System.out.println(s==s1);
	}
}
	
	

            在上面的代码中,我们定义了一个测试类F,同时声明了两个变量f1和f2,我们让f2指向f1所指向的对象,此时判断f1==f2结果是成立的。当我们对f1的对象进行修改后,再判断f1==f2结果仍然是成立的。但是我们声明了一个名f3的引用变量,同时让其指向一个新的F对象,之后虽然我们把两个对象的name值设置成一样了,f1==f3仍然不成立。

            然后我们定义两个String类型的变量s和s1,也让s1指向s所指向的对象,此时判断s==s1是成立的。然后我们对s所指向的对象进行了s=s+"cba";操作,再比较s==s1时,结果不成立了。

            我们在前面讲过,当基本数据类型进行==比较时,是比较两个变量的值是否相等;当引用变量使用==进行比较时,是引用变量所引用的对象地址是否相等。在java虚拟机内存里,有一块空间是为了保存java对象而设置的,当java创建一个对象时,会在内存中为这个对象分配内存空间,并初始化这个对象,此时引用变量f1指向了这个对象,然后我们又用f2 = f1的语句,让f2也指向了这个对象。当我们进行F f3 = new F();时,这时候VM为这个新对象分配了新的内存空间并做了初始化。显然这是两个不同的对象,假定他们有1000个属性,我们把每个属性的值都变得一模一样,它们也是两个对象,当我们用==这样的语句来比较时,它直接比较这两个对象的内存地址,显然这是不会成立的。在我们的心目中,如果两个类的内容完全相等,那么这两个类就应该是相等的,但是如果只使用==来判断的话,那它们永远不会相等。好在java提供了一个equals()方法,这个方法的使用我们在之前讲null的时候已经提到过,例如"abc".equals(s);这个方法是java的始祖类Object中提供的一个方法,它的实现细节如下:

    public boolean equals(Object obj) {
        return (this == obj);
    }

            可以看到,它是使用了==来判断两个对象的,仍然达不到我们的要求,所以我们如果希望实现我们心目中的equals判断,必须重写这个方法。比如我们的类F中有一个成员变量name,如果两个F类对象的成员变量name值相同,我们认为它相等,那么我们可以这样写

public boolean equals(Object obj){
     if(obj instanceof F){
       if(this.name!=null&&obj!=null){
          return (this.name).equals(obj.getName());
       }
        return false;
     }
        return false;
}

            好了,回到我们的String类,首先,String类可以以String str = "abc";这样的方式直接定义一个String类型变量,其次,String类型的对象可以进行 + 操作。但是这个 + 并不是我们的四则运算加法,而是字符串的拼接。另外,我们看到当字符串进行拼接以后,原有的引用变量s和s1进行==操作结果就为false了,这说明这两个引用变量指向的内存地址不一样了。

            在java的处理机制中,由于我们会使用到大量的字符串对象,而字符串的值很有可能相同,为了节省资源和开销,java会对字符串做特殊处理。java在内存中单独开辟一块空间,专门用来保存字符串常量(我们称之为字符串池),当我们定义一个字符串的时候,java首先会去这个空间里查找是否有这个引用变量指向的常量,如果有就直接建立引用关系,如果没有,就先在此空间创建一个新的字符串常量,然后再建立引用变量和这个字符串常量的引用关系。

            也就是说,当我们使用String s = "abc";这样的语句来声明s时,并没有在java的对象内存空间创建对象,只是在java的字符串池中查找有没有"abc"这样的值,如果有就直接和s建立引用关系,如果没有就先创建"abc",再和s建立引用。

            那么我们知道,创建类是用new关键字来创建的,String既然是一个类,它当然也能用new来创建,所以我们也可以使用String s = new String("abc");来定义一个字符串类,不同于上面的方法,此时会先在字符串池中查找是否有"abc"这个常量对象,如果有,就直接去堆中创建一个字符串对象,初始化值为"abc";如果没有,则先在池中创建"abc",然后再到堆中取创建字符串对象,初始化值为"abc"。

            String s = "abc";  String s1 = new String("abc"); s == s1的返回结果是false,道理和上面的一样,这个也是java面试中常常会问到的问题。

            那么我们用String s = new String("abc"); String s1 = s; s = s+"abc";这样的操作变更了s的引用值时,s == s1成立吗?结果是不成立,这是因为String类是final的,它是一个非可变类,一旦我们定义了String s = new String("abc");那么这个对象的值就不会改变了。那么s = s + "abc";做了什么?它根据两个字符串拼接以后的值创建了一个新的字符串对象,s指向了一个新的对象,而s1还指向原来的对象,所以s==s1不成立。        

            String类的常用方法    

               作为最常用的java类,String类的一些方法是我们需要掌握的,String类的全部方法可以参考java API,这里有一个在线API的查看地址点击打开链接http://tool.oschina.net/apidocs/apidoc?api=jdk-zh,我只对其中我个人觉得比较常用的方法做个说明:

          int  length() :返回字符串的长度,如"abcde".length(),返回值是5

         boolean equals(String str): 基本上是最常用的方法,判断一个字符串和另一个字符串值是否相同

        char  charAt(int index);这个也是很常用的方法,返回指定位置的字符(char),我们知道字符串其实就是字符的组合,所以用这个方法可以把字符串拆分成不同的字符。另外,和数组一样,字符串的字符位置是从0开始的,比如"abcde".charAt(0)='a',

        int compareTo(String str) 比较两个字符串的大小,按照字典顺序(通常是ASCII码)进行比较,如果返回0表示值相等,大于0时表示比目标字符串大,如果小于0表示比目标字符串小。这个比较是逐一比较的,比如"abc"和"ade",先比较第一个字符,由于都是'a',再比较第二个字符,由于'b'的排序靠前,所以返回一个大于0的数,表示"abc"比"ade"大。请注意,和equals方法类似,compareTo方法也是从Object继承而来,通常我们也需要对这个方法进行重写。

        boolean startsWith(String str) 判断字符串是不是以某一字符串开头,如果是就返回true,否则返回false,比如"abcde".startsWith("ab") 返回true

            boolean endsWith(String str) 和startsWith正好相反,判断是不是以某字符串结尾

            boolean contains(String str)  判断字符串是不是包含目标字符串 "abcde".contains("cd")返回true

            String trim()   非常实用的方法,它会去掉原字符串开头和结尾的空格

            int indexOf(String str)  返回字符串中第一次出现目标字符串的位置码,如果未出现过则返回-1

            int indexOf(String str,int index) 从指定的位置开始,返回字符串中第一次出现目标支付传的位置码

            int lastIndexOf(String str)  最后一次出现目标字符串的位置码

            String replaceAll(String str1,String str2) 用str2替换在字符串中出现过的所有的str1

            String replaceFirst(String str1,String str2) 用str2替换字符串中的第一个str1

         String[] split(String str) 根据给定的规则拆分字符串,返回一个字符串数组,比如"a|b|c".split("|")返回三个字符串"a","b","c",作为分隔符的"|"不会计算在内

            String substring(int index)从第index位开始截取字符串,返回截取后的字符串,比如"abcde".substring(1)返回"bcde"

            String substring(int index,int length) 从第index位开始截取长度为length的字符串

            String toUpperCase() 将字符串全部字母小写转换成大写后返回

            String toLowerCase() 将字符串全部字母大写转换成小写后返回

            boolean matches(String regex) 判断字符串是否满足正则表达式,经常用于判断手机号码是否正确等

            boolean equalsIgnoreCase(String str) 比较字符串和目标字符串是否相同,不考虑大小写

            byte[] getBytes()将字符串转换成一个byte数组,主要用于中文传输问题,由于编码格式不一致,在中文进行页面间传输时常常会转换成乱码,为此经常需要先将字符串转换成byte类型数组再进行重组。

            String toString()  返回字符串本身。此方法在String类中基本没有用处,但是其他的类中基本上都要重写此方法,以便能顺利的把对象转换成字符串。


            String类的操作基本上是笔试中必考的题目查,下面有一个我前几天面试时对方公司出的笔试题目,大家可考虑一下怎么实现。

            如果一个字符串的值和它的反序字符串相等,那么我们称之为可逆字符串,比如"abcba"就是一个可逆字符串。请写出获取一个任意字符串中最长的可逆字符串的实现方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值