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
  • 相关阅读:
    Leetcode 811. Subdomain Visit Count
    Leetcode 70. Climbing Stairs
    Leetcode 509. Fibonacci Number
    Leetcode 771. Jewels and Stones
    Leetcode 217. Contains Duplicate
    MYSQL安装第三步报错
    .net 开发WEB程序
    JDK版本问题
    打开ECLIPSE 报failed to load the jni shared library
    ANSI_NULLS SQL语句
  • 原文地址:https://www.cnblogs.com/chenpi/p/5339265.html
Copyright © 2011-2022 走看看