zoukankan      html  css  js  c++  java
  • JAVA中的字符串小结

    String字符串是只读的,不可变的

    查看String类的源码,可以发现String类是被final关键字修饰的;

    另外还可以看下String类源码中的其它方法实现,随便举个可以修改String值的方法,如字符串拼接方法concat(String str),返回的是一个全新的String对象,而不是在原有的String对象上做修改,代码如下:

        public String concat(String str) {
            int otherLen = str.length();
            if (otherLen == 0) {
                return this;
            }
            int len = value.length;
            char buf[] = Arrays.copyOf(value, len + otherLen);
            str.getChars(buf, len);
            return new String(buf, true);
        }

    以上代码中,将原有的字符数组和新字符串数组拷贝到一个新的字符数组中,然后new出一个新的String对象返回;

    重载“+”与StringBuilder

     先看一段使用“+”拼接字符串的代码如下:

    package strings;
    
    public class Test {
    
        public static void main(String[] args) {
            String a = "test";                
            String b = a;                //b保存了a的引用
            
            //这里编译器会为我们自动创建StringBuilder对象,并调用append方法,
            //最终调用StringBuilder的toString方法返回一个新的字符串对象
            a = a + "1" + "2" + "3";    //生成了一个新的String对象赋给a
            
            System.out.println(b==a);    //引用a指向了新的字符串对象,不相等
            System.out.println(a);
        }
    }

    在使用“+”拼接字符串的时候,编译器会为我们自动创建StringBuilder对象,并调用append方法拼接字符串,最终调用StringBuilder的toString方法返回一个新的字符串对象;

    或许你认为既然编译器会为我们创建自动StringBuilder对象就可以任意使用“+”操作符了,实际上编译器在某些情况下为我们优化的程度还是不够,如下代码例子,在循环体内使用“+”操作符;

    package strings;
    
    public class Test {
    
        public static void main(String[] args) {
            String a = "";                
            for(int i = 0;  i < 5; i++){
                //编译器每次都会生成一个StringBuilder对象,并调用toString方法生成一个新的String对象
                //这中间产生了两个临时对象
                a +=i;
            }
            System.out.println(a);
        }
    }

    可以使用eclipse调试进入源码,会发现,编译器每次都会生成一个StringBuilder对象,并调用toString方法生成一个新的String对象,也就是说。每循环体执行一次,就产生了两个临时对象,可见,当循环次数大的时候,会产生一大堆需要垃圾回收的中间对象,而直接使用StringBuilder就没有这种情况,如下代码,为一个正确的例子:

    package strings;
    
    public class Test {
    
        public static void main(String[] args) {
            StringBuilder a = new StringBuilder("");                
            for(int i = 0;  i < 5; i++){
                a.append(i);
            }
            System.out.println(a);
        }
    }

    总之,只要涉及字符串的操作,选择StringBuilder总是没错的;

    无意识的递归调用

    在重写toString方法的时候,如果不注意使用了this关键字,很有可能会调入递归调用的陷阱,如下代码:

    package strings;
    
    public class Test {
    
        @Override
        public String toString() {
            
            return "addr:" + this;
        }
        
        public static void main(String[] args) {            
            Test t = new Test();
            System.out.println(t);
        }
    }

    执行的时候,将抛出StackOverflowError异常,因为toString方法里的"addr:" + this语句会调用自身toString方法,导致无穷无尽的递归调用,然后堆栈溢出,抛出异常;

    如果你仅仅是想打印下对象的地址,那么可以调用super.toString()方法,因为Object对象的toString方法默认会调用hashCode打印对象地址;

    Sting类的方法

    关于String类中的方法,可以查看String源码或JDK的API文档,相对来说还是很好理解的,所谓String对象,实质上来说就是一个字符数组;

    String类中的方法,大部分都是操作String内部维护的char value[]数组实现的;

    主要方法如下,图片参考自java编程思想-4:

    字符串格式化输出

    关于格式化输出,了解以下几个例子吧:

    format方法:可用于PrintString和PritWriter, 如System.out.format, 如果有C语言的printf语法的使用经验的话,学习format语法会非常轻松,基本类似,如下为一个简单例子:

    System.out.format("%5d: %2f", 101,1.131452);

    Formatter类:printf 风格的格式字符串的解释程序,如下例子:

    package strings;
    
    import java.util.Formatter;
    
    public class Test {
    
        public static void main(String[] args) {
            Formatter formatter = new Formatter(System.out);
            formatter.format("%5d: %2f", 101, 1.131452);
            formatter.close();
        }
    }

    String.format方法:String类的静态方法,在其内部实际上也是通过创建Formatter对象实现的;

    System.out.println(String.format("%5d: %2f", 101, 1.131452));

    正则表达式

    关于正则表达式的具体语法就不细说了,在String类中,涉及正则表达式的主要是以下方法:

    matches:判断是否匹配指定的正则表达式规则

    split:分割字符串

    replaceAll/replaceFirst:将匹配的字符替换为指定的字符串

    如下代码为一个简单的使用例子:

    package strings;
    
    public class RegexTest {
        public static void main(String[] args) {
            
            //匹配数字
            System.out.println("1314".matches("\d+"));
    
            //按数字分割
            String[] splitArr = "asdashh45hiu9jkjaks54d".split("-?\d+");
            for(String str:splitArr){
                System.out.print(str + ", ");
            }
            
            //替换数字为*号
            System.out.println();
            System.out.println("asdashh45hiu9jkjaks54d".replaceAll("-?\d+", "*"));
            
        }
    }
    //输出
    //true
    //asdashh, hiu, jkjaks, d, 
    //asdashh*hiu*jkjaks*d
  • 相关阅读:
    COOKIE和SESSION有什么区别?
    JSP中三大指令
    JSP中out.print()、out.println()以及out.write()的区别
    Linux实战教学笔记06:Linux系统基础优化
    Linux实战教学笔记05:远程SSH连接服务与基本排错(新手扫盲篇)
    Linux实战教学笔记04:Linux命令基础
    Linux实战教学笔记03:操作系统发展历程及系统版本选择
    Linux实战教学笔记02:计算机系统硬件核心知识
    Linux实战教学笔记01:计算机硬件组成与基本原理
    从零开始学Python第八周:网络编程基础(socket)
  • 原文地址:https://www.cnblogs.com/chenpi/p/5339265.html
Copyright © 2011-2022 走看看