Java第六章 String类

37 篇文章 4 订阅
32 篇文章 1 订阅

1.它不是java的基本类型之一。但可以像基本数据类型一样使用。String是final 不能被继承的。

2. string s = new string() 表示一个空字符串 并且可以在new的时候直接赋值,而String a = "hello"也是可以的 。 用 + 号链接字符串,和其他类型链接返回字符串。C#里不包含string无参的构造函数。indexof 返回字符在字符串里的位置 没有返回-1.其实就是字符的数组,String类有一个value字符数组。

3.字符串对象.charAt 方法 返回索引位置的字符。超出索引报错。去除字符串中的空格有两种方法,trim(去除字符前导和尾部空格),使用stringtokenizer()和replaceAll()方法实现去除字符串中所有空格,replace 和replaceFirst用于替换所有出现的字符和第一个出现的字符,注意替换后会生成新的字符串。字符串是否相等有equals和equalsIgnoreCase两种方法。前者区分大小写,后者不区分。判断字符串开始于结尾startswith和endswith。toLowerCase和toUpperCase字母大小写转换。可以用split()方法用指定的分割符对字符串分割。返回值为字符串数组,重载方法新增了分割次数限制。compareto 方法用来比较两个字符串的值,从第一个开始比较如果全部相同返回0,如果不同返回不同字符的ASCII差值,可正可负,如果是长度不同返回长度差值,这个可以看源码。string.format为格式化字符串。这里有很多的转换符,需要了解下。

4.正则表达式:当程序需要对输入的数据进行检查会用到,比如游戏里起名和聊天都会用到。"\"为转义符,跟其他语言一样,在正则表达式中要用普通意义上的字符需要用转义符。pattern类里有各种正则表达式。

5.正则表达式限定符:?——0次或1次,*——0次或者多次,+ ——1次或多次 {n}——正好出现n次{n,}——至少出现n次{n,m}——出现n~m次。"\\w+@\\w{2,6}(\\.\\w{2,3})+" ------ 54654@sina.com.cn   这里要注意的是两个“\\”代表一个"\",\\w表示【a-zA-Z_0-9】小写字符或大写字符或下划线或数字。也可以用()表示整体。“\\b\\w{3}\\b”表示3个字符的单词。硬盘上的路径在java的String里我们用"\\"代替一个"\",正则表达式里我们要用四个"\\\\"代替两个"\\"。

在java.util.regex包下有两个类即Pattern和Matcher,Pattern是正则表达式的编译器。Matcher通过pattern来匹配字符串的匹配器:

1.Pattern p = Pattern.compile("a*b")  把正则表达式编译成模式对象, p.split(String s)方法:用此模式分隔字符串。而p.pattern()是返回这个模式的正则表达式。

Pattern.quote:调用Patter.quote()方法之后,原有的字符串被\Q..\E包裹, \Q 代表字面内容的开始,\E 代表字面内容的结束。返回后的字符串成了单纯的字符值.举个例子,正则表达式”.*”表示匹配除"\r\n"之外的任何单个字符。若要匹配包括"\r\n"在内的任意字符,请使用诸如"[\s\S]"之类的模式。改变前和改变后

通过上面例子就可以看出,当使用quote()方法后,将”.*”转换为了它的字面量意思,也就是只能匹配”.*”字符串.使给定的正则表达式没有任何的特殊意义。

mather的quoteReplacement方法返回一个字面值的字符串,字符串里的斜杠“\”和"$"都没有特殊意义。该字符串可以用在appendReplacement等方法中。
pattern在compile时还可以指定标志模式,比如Pattern p = Pattern.compile("java", Pattern.CASE_INSENSITIVE); 不区分大小写。
2.调用匹配器对象功能:m.matches() 是一个静态方法,用于快速匹配字符串,该方法适合用于只匹配一次,且匹配全部字符串.。

因为matches()匹配的是整个字符串,所以第三个是fasle。‘a+’代表一个或多个a,matches()方法实际上调用的还是Matcher的matches()方法。

3.Pattern类只能做一些简单的匹配操作,要想得到更强更便捷的正则匹配操作,那就需要将Pattern与Matcher一起合作.Matcher类提供了对正则表达式的分组支持,以及对正则表达式的多次匹配支持. 下面来看看Pattern.matcher(CharSequence input)的具体用
group() 等效与group(0),返回的是find到的与模式匹配的接取字符。表示如果find到的这个模式(小括号里的内容)里还嵌套了小括号,那么group(1)表示从左往右第一组小括号,依次类推。group(2)表示第二组小括号。如果超过了matcher的groupCount则会抛出java.lang.IndexOutOfBoundsException异常。有的时候我们不想要捕获一个捕获模式中嵌套小括号内的内容,我们可以用(?:pattern)来匹配 pattern 但不获取匹配结果,这样就不会影响用“|”或匹配多个模式时的捕获索引,也就是不能使用 反向引用。

单独的bai“?”:匹配前面的子表达式零次或一次。当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。


4.m.find()方法扫描输入序列以查找与该模式匹配的下一个子序列,如果有再用group方法收集。这里要注意。一定要先find才能group,gourp里的数字是第几个捕获,一个小括号是一个捕获。matcher.groupcount()返回捕获组的数量,对应小括号的数量,start和end方法对应每个捕获在find后的索引。matcher.replaceAll(str)是将与模式匹配的输入序列的每个子序列替换为给定的替换字符串str。

5.m.lookingAt()方法对符串最前面进行匹配,只有匹配到的字符串最前面符合正则表达式才返回true。

appendTail:这个方法是把最后一次匹配到内容之后的字符串追加到StringBuffer中
appendReplacement:这个方法会把匹配到的内容替换为"_",并且把从上次替换的位置到这次替换位置之间的字符串也拿到,
     然后,加上这次替换后的结果一起追加到sb2里(假如这次替换是第一次替换,那就是只追加替换字符位置前的字符和替换后的字符串啦)。

6.方括号中元字符的含义【abc】表示a或b或c【^abc】表示除abc外的任何字符【a-zA-Z】表示a~z或A~Z,【a-d【m-p】】表示a~d或m~p的任何字符, 表达式中 “|”表示或   。[\u4e00-\u9fa5] 是/Unicode表中的汉字的头和尾

7.字符串生成器 StringBuilder 这个类的对象初始容量为16个字符,可以自行增长长度,动态的增加删除插入等编辑字符串操作,节省内存和时间,不创建新的对象。append(string str)将指定字符串增加到对象中,append(stringBuffer str)将指定字符串缓存增加到对象中,insert(int offset, string str)插入操作。delete(int start, int end)和deleteCharAt(index)删除操作。 tostring()转换为字符串,线程不安全适用于单线程。

8.StringBuffer :长度和内容可变,String不可变,如果使用前者做字符拼接,不会浪费太多内存。初始容量为初始的字符串length + 16,保证同步适用于多线程,数据安全,但是效率低,StringBuilder 这个类的功能与StringBuffer同样。 但是这个StringBuilder不保证同步,数据不安全,效率高。String是不可变的,如果重新赋值会在堆上重新开辟一个内存来存储新的值,地址变化。设置成不可变的原因:字符串常量池的需要,提升效率和减少内存分配,2.安全性考虑,防止被意外修改(HashSet中存的值如果是可变的String,则破坏了唯一性;不可被写所以线程安全;)3.作为HashMap、HashTable等hash型数据key的必要。因为不可变的设计,jvm底层很容易在缓存String对象的时候缓存其hashcode,这样在执行效率上会大大提升。引用类型作为参数传递的时候方法里改变形参外面改变,但是String是个特殊的引用类型,它是不可变的,所以它传递的是值, 所以方法里改变String类型变量的值不影响外面的String变量。而StringBuffer等引用类型用作参数,用别的对象直接赋值不会改变外面的值(可以理解为创建了副本引用对象指向原来的引用),只改变里面的值,但是用append等方法操作会改变外面的值。原因:

基本类型:值存放在局部变量表中,无论如何修改只会修改当前栈帧的值,方法执行结束对方法外不会做任何改变;此时需要改变外层的变量,必须返回主动赋值。

引用数据类型:指针存放在局部变量表中,调用方法的时候,副本引用压栈,赋值仅改变副本的引用。但是如果直接改变副本引用的值,修改了引用地址的对象,此时方法以外的引用此地址对象当然被修改。(两个引用,同一个地址,任何修改行为2个引用同时生效).这个原因解释了在方法里直接给引用对象赋值的情况,而不是改变引用对象里的值。

而String ,Integer 等包装类, 里的存的值都是 final【】char 和final int 类型。所以在方法里改变值的时候相当于重新开辟了一块内存。所以外面的引用不会变。

这里有个联系字符串加密操作:思想就是将字符串转换成字节数组,再将每个字节和密文字符异或操作进行加密,相反的运算就可以解密。

String str="i"与 String str=new String("i")不一样,因为内存的分配方式不一样。String str="i"的方式,Java 虚拟机会将其分配到常量池中;而 String str=new String("i") 则会被分到堆内存中。

后者的步骤是:

1、 在常量池中创建内容为“i”的对象,在堆中创建内容为“i”的对象。

2、 String str1 = new String(“i”); String str2 = new String(“i”);str2不会指向之前创建的对象,而是重新创建一个对象。

str1 != str2;并且 str != str1;

Java 中字符串相加

1. 字符串常量相加,jvm 会进行优化,不会创建 StringBuilder 对象

2.字符串变量加上常量,会创建String对象来用作创建 StringBuilder 对象,然后调用 append 方法。

3. for 循环中的字符串变量加上常量,会被优化成 StringBuilder.append(),每次相加都会创建一个 StringBuilder 对象,并且最终通过tostring返重新new一个String对象。

4.所以 两个String相加或者String常量相加会用 new的方式创建String对象,而两个常量相加不会用new 的方式创建String对象,string.valueof 和 stringbuilder的tostrring都会new string对象。所以String的索引指向堆内存中。

static final String f = "helloworld";
public static void main(String [] args) {  
        String a  = "hello";
        String b  = "world";
        String c = a + b;
        String d = "hello" + "world";
        String e  = "hello";
        //String f = e + "world";
        System.out.println(a+b == f);//false
        System.out.println(c == f);//false
        System.out.println(d == f);//true
        System.out.println(a == e);//true
        String h = e + "world";
        System.out.println(h == d);//false
        //String s5 = ',' + '='; //报错,实质上为','和'='的ASCII码值相加,相加得到的是 整数“
        //String s5 = "," + '=';不会报错
        //即使是 'a' 和 'b' 也一样
        Object dd = (Object)"a";//实际上做了Object dd = "a";
        System.out.println(dd.getClass().getTypeName());//java.lang.String实际还是String引用
        System.out.println(dd == "a");//true 说明没有用new的方法创建对象,也就是说引用没有
        //指向堆
        String hah = String.valueOf("a");//先转化为Object再传进去,相当于先执行上面Object的操作。
        System.out.println(dd == hah);//true 确实也证明了上面说的 
        String s = "world";
        for (int i = 0; i < 5; i++)
        {
            s = s + "sh";
        }      
}
String的valueof方法之一,有重载。tostring里返回的是this对象。
    public static String valueOf(Object obj) {
        return (obj == null) ? "null" : obj.toString();
    }

class 反编译获得
	static final String f = "helloworld";

	public Test()
	{
	}

	public static void main(String args[])
	{
		String a = "hello";
		String b = "world";
		String c = (new StringBuilder()).append(a).append(b).toString();
		String d = "helloworld";
		String e = "hello";
		System.out.println((new StringBuilder()).append(a).append(b).toString() == "helloworld");
		System.out.println(c == "helloworld");
		System.out.println(d == "helloworld");
		System.out.println(a == e);
		String h = (new StringBuilder()).append(e).append("world").toString();
		System.out.println(h == d);
		Object dd = "a";
		System.out.println(dd.getClass().getTypeName());
		System.out.println(dd == "a");
		String hah = String.valueOf("a");
		System.out.println(dd == hah);
		String s = "world";
		for (int i = 0; i < 5; i++)
			s = (new StringBuilder()).append(s).append("sh").toString();

	}
stringbuilder的 tostring方法会new新对象
public String toString() {
        // Create a copy, don't share the array
        return new String(value, 0, count);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值