Java编程思想学习笔记——字符串

前言

字符串操作是计算机程序设计中最常见的行为。

不可变String

String对象是不可变的

重载"+"与StringBuilder

String对象是不可变的,可以给String对象加任意多得别名。
String对象具有只读特性,所以指向它的任何引用都不可能改变它的值。

String a = "a";
String b = a;
System.out.println("first: a=" + a + " b=" + b);
b = "b";
System.out.println("second: a=" + a + " b=" + b);

运行结果:

first: a=a b=a
second: a=a b=b

String对象的不可变性会带来一定的效率问题。
比如为String对象重载的"+"操作符。

重载:一个操作符在应用于特定类时,被赋予特殊的意义。Java中,用于String的"+"与"+="是仅有的两个重载过的操作符。Java不允许程序员重载任何操作符。

public class Connection {
    public static void main(String[] args) {
        String str = "hello";
        String anotherStr = "abc" + str + "def" + 123;
        System.out.println(anotherStr);
    }
}
Compiled from "Connection.java"
public class Connection {
  public Connection();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String hello
       2: astore_1
       3: new           #3                  // class java/lang/StringBuilder
       6: dup
       7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      10: ldc           #5                  // String abc
      12: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      15: aload_1
      16: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: ldc           #7                  // String def
      21: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      24: bipush        123
      26: invokevirtual #8                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      29: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      32: astore_2
      33: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
      36: aload_2
      37: invokevirtual #11                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      40: return
}

无意识的递归

Java中的每个类从根本上都是继承自Object。

public class Object {
  ...
  //Object类的toString方法
  public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
   ...
}

标准容器类同样是继承自Object类,因此容器类都有toString()方法,并且覆写了这个方法来表达容器本身和它所包含的对象。
比如ArrayList.toString()方法,查看源代码可知,ArrayList类继承自AbstractList类,而AbstractList类覆写了toString()方法。
它会遍历AbstractList中所包含的所有对象,并调用每个元素上的toString方法。


public abstract class AbstractCollection<E> implements Collection<E> {
  ...
 public String toString() {
        Iterator<E> it = iterator();
        if (! it.hasNext())
            return "[]";

        StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (;;) {
            E e = it.next();
            sb.append(e == this ? "(this Collection)" : e);
            if (! it.hasNext())
                return sb.append(']').toString();
            sb.append(',').append(' ');
        }
    }
...
}

想打印对象的内存地址,应该调用super.toString()方法,也就是基类Object的toString()方法。

class A{
   public static void main(String [] args){
    System.out.println(new A());
  }
  @Override
  public void toString(){
     // return "A:"+this;//会造成递归调用,导致栈溢出。
      return "A:"+super.toString();
  }
}

正则表达式

解决各种字符串处理相关的问题:匹配,选择,编辑以及验证。

基础

以某种方式来描述字符串

Java中,\表示:插入一个正则表达式的反斜线,它后面的字符具有特殊的意义。

数字:\\d
反斜线:\\\\

String类中的,正则匹配方法:
1.匹配matches()方法。查看源代码,可以知道该方法实际上是调用了Pattern类的matches()方法来实现正则表达式的匹配功能的。
2.分隔split()方法,这个方法能将字符串从正则表达式匹配的地方切开。
3.替代replaceAll(),replaceFirst()方法

 ...
 public boolean matches(String regex) {
        return Pattern.matches(regex, this);
    }
 public String[] split(String regex, int limit) {
        /* fastpath if the regex is a
         (1)one-char String and this character is not one of the
            RegEx's meta characters ".$|()[{^?*+\\", or
         (2)two-char String and the first char is the backslash and
            the second is not the ascii digit or ascii letter.
         */
        char ch = 0;
        if (((regex.value.length == 1 &&
             ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
             (regex.length() == 2 &&
              regex.charAt(0) == '\\' &&
              (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
              ((ch-'a')|('z'-ch)) < 0 &&
              ((ch-'A')|('Z'-ch)) < 0)) &&
            (ch < Character.MIN_HIGH_SURROGATE ||
             ch > Character.MAX_LOW_SURROGATE))
        {
            int off = 0;
            int next = 0;
            boolean limited = limit > 0;
            ArrayList<String> list = new ArrayList<>();
            while ((next = indexOf(ch, off)) != -1) {
                if (!limited || list.size() < limit - 1) {
                    list.add(substring(off, next));
                    off = next + 1;
                } else {    // last one
                    //assert (list.size() == limit - 1);
                    list.add(substring(off, value.length));
                    off = value.length;
                    break;
                }
            }
            // If no match was found, return this
            if (off == 0)
                return new String[]{this};

            // Add remaining segment
            if (!limited || list.size() < limit)
                list.add(substring(off, value.length));

            // Construct result
            int resultSize = list.size();
            if (limit == 0) {
                while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
                    resultSize--;
                }
            }
            String[] result = new String[resultSize];
            return list.subList(0, resultSize).toArray(result);
        }
        return Pattern.compile(regex).split(this, limit);
    }
    public String replaceFirst(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
    }
    public String replaceAll(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceAll(replacement);
    }
 ...

创建正则表达式

[http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html]

量词

1.贪婪型
2.占有型
3.勉强型

CharSequence
接口CharSequence从CharBuffer,String,StringBuffer,StringBuilder类之中抽象出字符序列的的一般化定义:

interface CharSequence{
   charAt(int i);
   length();
   subSequence(int start,int end);
   toString();
}

Pattern和Matcher

String类功能有限,我们可以自己构造强大的正则表达式对象。
导入java.util.regex包,使用静态方法Pattern.compile()来编译正则表达式。

  public static Pattern compile(String regex) {
        return new Pattern(regex, 0);
    }

compile()方法返回一个Pattern对象,表示编译后的正则表达式。

  public Matcher matcher(CharSequence input) {
        if (!compiled) {
            synchronized(this) {
                if (!compiled)
                    compile();
            }
        }
        Matcher m = new Matcher(this, input);
        return m;
    }

对于已编译正则表达式的Pattern对象的matcher()方法,加上要被匹配的字符串,返回一个Matcher对象。
使用Matcher对象的各种方法,我们就能判断各种不同类型的匹配是否成功。

boolean matches() //判断整个字符串是否匹配
boolean lookingAt()//判断字符串的起始部分是否能够匹配
boolean find()
boolean find(int start)

原文地址:http://www.cnblogs.com/JohnTsai/p/4796328.html

时间: 2024-10-27 01:34:21

Java编程思想学习笔记——字符串的相关文章

Java编程思想学习笔记——一切都是对象

前言 Java是基于C++的,但Java是一种更加纯粹的面向对象程序设计语言. C++和Java都是混合/杂合型语言.杂合型语言允许多种编程风格. 用引用操纵对象 每种编程语言都有自己操纵内存中元素的方式. 直接操纵元素 用某种基于特殊语法的间接表示(C和C++里的指针) 用引用操纵对象(Java) 在Java中,一切都被视为对象.操纵的标识符实际上是对象的一个引用. 类比为遥控器(引用)来操纵电视机(对象) 只要把握这个遥控器,就能保持与电视机的连接 改变频道或减小音量,实际操纵的是遥控器(引

Java编程思想学习笔记——类型信息

前言 运行时类型信息(RTTI:Runtime Type Information)使得我们可以在程序运行时发现和使用类型信息. Java在运行时识别对象和类的信息的方式: (1)一种是RTTI,它假定我们在编译时已经知道了所有的类型. (2)另一种是反射机制,它允许我们在运行时发现和使用类的信息. 为什么需要RTTI 以使用了多态的类层次结构的例子举例: 如上图,泛型是基类Shape,而派生出来的具体类有Circle,Square和Triangle. 这是一个类层次结构图,基类位于顶部,而派生类

Java编程思想学习笔记——注解

前言 在Android开发的过程中,我们为了减少重复代码的编写,会使用类似ButterKnife,AndroidAnnotations 这类依赖注解库.代码示例如下: //不使用 Button btn = (Button)findViewById(R.id.btn); //使用ButterKnife @Bind(R.id.btn) Button btn; //使用AndroidAnnotations @ViewById(R.id.btn) Button btn; 可以看出通过注解,我们能大量减少

Java编程思想学习笔记——枚举类型

前言 关键字enum可以将一组具名的值有限集合创建一种为新的类型,而这些具名的值可以作为常规的程序组件使用. 正文 基本enum特性 调用enum的values()方法可以遍历enum实例,values()方法返回enum实例数组,且数组中元素保持在enum声明时的顺序. public class TestEnum { public static void main(String[] args) { Fruit[] values = Fruit.values(); for (Fruit frui

Java编程思想学习笔记——初始化与清理

初始化 构造器保证初始化 构造器采用与类相同的名称. 默认构造器(default constructor):不接受任何参数的构造器,也叫无参构造器. 构造器也能带有形式参数,就能在初始化对象时提供实际参数. class Foo{ Foo(){ System.out.println("Foo's no-arg Constructor Foo()"); } Foo(int i){ System.out.println("Foo's arg Constructor Foo (&qu

Java编程思想学习笔记——接口

1.抽象类和抽象方法 抽象方法:不完整的,仅有声明而没有方法体. abstract void f(); 抽象类:包含抽象方法的类.(若一个类包含一个或多个抽象方法,则该类必须限定为抽象的.) 1.用抽象类直接创建对象是不安全的,因为这个抽象类是不完整的.编译器通过这种方式保证了 抽象类的纯粹性. public abstract class Person { public abstract void eat(); public abstract void pee(); public abstrac

Java编程思想学习笔记——初始化与清理(二)

成员初始化 Java尽力保证:所有变量在使用前都能得到适当的初始化. 方法的局部变量:未初始化,编译错误. void f(){ int i; // System.out.println(i);//编译错误 } 类的数据成员(字段)是基本类型:保证都会有一个初始值. public class InitialValues { boolean bl; char c; byte bt; short s; int i; long l; float f; double d; InitialValues re

Java编程思想学习笔记——复用类

前言 复用代码是Java众多引人注目的功能之一. 达到复用代码的方法有: 组合:新的类由现有类的对象所组成.(复用现有代码的功能,而非它的形式) 继承:按照现有类的类型组建新类.(不改变现有类的形式,复用现有类的形式并在其中添加新代码).面向对象程序设计的基石 正文 1.组合语法 将对象引用置于新类中即可(非基本类型:在新类中放置引用,基本类型:直接添加就可以了) /** * 引擎 */ class Engine{ /** * 功率 */ double power; /** * 品牌 */ St

Java编程思想学习笔记——访问权限修饰词

几种访问权限修饰词 public,protected,private,friendly(Java中并无该修饰词,即包访问权限,不提供任何访问修饰词) 使用时,放置在类中成员(域或方法)的定义之前的,仅仅控制它所修饰的特定定义的访问权. 包访问权限 是默认访问权限,没有任何关键字 对于同一包中的所有其他类对这个成员都有访问权限,对于包之外的所有其他类,则没有访问权限. 取得对某成员访问访问权的途径有如下方式: 用public修饰成员,任何人在任何地方都有访问权限 不加访问权限修饰词,并将其他类放在