>Java >java지도 시간 >Java 개선(13) -----문자열

Java 개선(13) -----문자열

黄舟
黄舟원래의
2017-02-10 11:22:301140검색

문자열 연산은 컴퓨터 프로그래밍에서 가장 일반적인 동작임이 입증되었습니다.


1. 문자열

우선 String은 기본 데이터 타입이 아니라 객체이고, 불변 객체라는 점을 분명히 해야 합니다. 소스 코드를 보면 String 클래스가 최종 클래스라는 것을 알 수 있고(물론 상속될 수 없음) JDK 문서를 보면 String 객체를 수정하는 거의 모든 작업이 실제로 새로운 객체를 생성한다는 것을 알 수 있습니다. 문자열 객체.

문자열은 객체이므로 초기화하기 전에는 해당 값이 null입니다. 여기서는 "", null, new String()을 언급해야 합니다. 셋 사이. null은 문자열이 아직 새롭지 않음을 의미합니다. 즉, 개체에 대한 참조가 아직 생성되지 않았으며 해당 개체에 메모리 공간이 할당되지 않았음을 의미합니다. 그러나 "" 및 new String()은 새 문자열임을 나타냅니다. , 내부적으로는 비어 있지만 생성되었습니다. 객체에 대한 참조에는 메모리 공간 할당이 필요합니다. 예를 들어, 빈 유리잔에는 내부에 공기가 있기 때문에 그 안에 아무것도 없다고 말할 수 없습니다. 물론 진공 상태로 만들 수도 있습니다. null 및 " ", new String()의 차이점은 진공과 공기와 같습니다.

                                                                ~                                                  . 문자열 객체를 생성할 때마다 먼저 동일한 액면가를 갖는 문자열이 있는지 확인합니다. 문자열 풀에 있는 경우 해당 개체를 생성하지 않고 개체에 대한 참조를 다시 문자열 풀에 직접 넣습니다. 그렇지 않은 경우 이를 생성한 다음 문자열 풀에 넣고 새로 생성된 개체에 대한 참조를 반환합니다. 이 메커니즘은 효율성을 높이고 메모리 공간 사용량을 줄일 수 있기 때문에 매우 유용합니다. 따라서 문자열 s="aa"와 같은 직접 할당을 사용하는 것이 좋습니다. s = 새로운 문자열("aa")).

문자열 사용은 다음 측면에 지나지 않습니다.

1. 문자열 비교

   equals() ------ 내용이 동일한지 확인합니다.

      compareTo() ------ 문자열의 크기 관계를 확인합니다.

       compareToIgnoreCase(String int) ------비교 시 대소문자를 무시합니다.

                                                                                                                                         

equalsIgnoreCase() ------ 대소문자를 무시하고 내용이 동일한지 판단합니다.

ReagionMatches () ------ 문자열 내용 중 일부가 동일한지 비교합니다. (자세한 내용은 API를 참고하세요.)

2. 문자열 검색

charAt(int index ) ------지정된 인덱스 인덱스 위치에 있는 문자를 반환하며, 인덱스 범위는 0부터 시작됩니다.

                                                                                                                                      ​ .

indexOf(String str, int fromIndex) ------- 문자열의 fromIndex 문자부터 시작하여 str을 검색합니다.

                                                                                                            lastIndexOf(String str)------마지막으로 나타나는 위치를 찾습니다.

lastIndexOf(String str, int fromIndex)----문자열의 fromIndex 번째 문자에서 마지막으로 나타나는 위치를 찾습니다.

starWith(String prefix, int toffset)------지정된 인덱스에서 시작하는 이 문자열의 하위 문자열이 지정된 접두사로 시작하는지 테스트합니다.

starWith(String prefix)------이 문자열이 지정된 접두사로 시작하는지 테스트합니다.

              endsWith(String suffix)------이 문자열이 지정된 접미사로 끝나는지 테스트합니다.

3. 문자열 가로채기

public String subString(int BeginIndex)------이 문자열의 하위 문자열인 새 문자열을 반환합니다.

public String subString(int BeginIndex, int endIndex)------반환된 문자열은 BeginIndex에서 시작하여 endIndex-1까지의 문자열입니다.

4. 문자열 교체

공용 문자열 교체(char oldChar, char newChar).

public String replacement(CharSequence target, CharSequence replacement)------원래 etarget 하위 시퀀스를 교체 시퀀스로 바꾸고 새 문자열을 반환합니다.

    public String replacementAll(String regex, String replacement)------정규식을 사용하여 문자열을 일치시킵니다. 참고로 replacementAll의 첫 번째 매개변수는 정규식인데, 나는 이로 인해 큰 어려움을 겪었습니다.

5. 더 많은 메소드는 API를 참고하세요


2. StringBuffer

StringBuffer와 String은 모두 문자열을 저장하는 데 사용되지만 내부 구현이 다르기 때문에 사용하는 범위가 다릅니다. StringBuffer의 경우 문자열을 처리할 때 이를 수정하면 새로운 문자열 개체를 생성하지 않습니다. 이므로 메모리 사용량 측면에서 String보다 낫습니다.

실제로 메소드를 사용할 때 StringBuffer의 많은 메소드는 String 클래스의 메소드와 유사하며 이들이 나타내는 함수는 거의 동일합니다. StringBuffer는 수정될 때 자체적으로 수정되는 반면, String 클래스는 새 객체를 생성하는데, 이것이 두 객체 사이의 가장 큰 차이점입니다.

동시에 StringBuffer는 =를 사용하여 초기화할 수 없습니다. StringBuffer 인스턴스를 생성해야 합니다. 즉, 생성 방법을 통해 초기화해야 합니다.

StringBuffer 사용 측면에서는 추가, 수정, 삭제 등 문자열 변경에 더 중점을 둡니다.

 1.append(): 문자열 연결과 유사하게 현재 StringBuffer 객체의 끝에 지정된 내용을 추가합니다. 여기서 StringBuffer 객체의 내용이 변경됩니다.

2. insert: 이 메소드는 주로 StringBuffer 객체에 내용을 삽입합니다.

3. delete: 이 메서드는 주로 StringBuffer 개체의 내용을 제거하는 데 사용됩니다.


3. StringBuilder

StringBuilder도 가변 문자열 개체와 다릅니다. StringBuffer는 스레드에 안전하지 않다는 점을 바탕으로 일반적으로 StringBuffer보다 속도가 빠릅니다. StringBuffer와 마찬가지로 StringBuider의 주요 작업도 추가 및 삽입 메서드입니다. 두 방법 모두 주어진 데이터를 효과적으로 문자열로 변환한 다음 해당 문자열의 문자를 문자열 생성기에 추가하거나 삽입합니다.

위에서는 String, StringBuffer, StringBuilder에 대해 간략하게 소개했을 뿐입니다. 사실 이 세 가지에 대해서만 보이는 차이점에 더 주목해야 합니다. 차이점을 명확히 하면 더 잘 사용할 수 있습니다.


  4. String, StringBuffer, 를 올바르게 사용하세요. StringBuilder

먼저 다음 표를 살펴보겠습니다.



여기서는 String이 스레드로부터 안전한지 여부가 명확하지 않습니다. 이유: String은 다음과 같습니다. 불변이므로 모든 작업을 통해 값을 변경할 수 없습니다. 스레드 안전성이 있는지 말하기 어렵습니다. 그러나 스레드가 안전한지 여부를 고집한다면 콘텐츠는 변경할 수 없기 때문에 항상 안전합니다.

사용상 String은 수정될 때마다 새로운 객체를 생성해야 하므로 자주 필요한 문자열은 StringBuffer나 StringBuilder를 선택하는 것이 가장 좋습니다. StringBuffer의 경우 각 작업은 StringBuffer 개체 자체에서 수행되며 새 개체를 생성하지 않으므로 StringBuffer는 문자열 내용이 자주 변경되는 상황에 특히 적합합니다.

그러나 모든 문자열 문자열 작업이 StringBuffer보다 느린 것은 아닙니다. 일부 특별한 경우에는 문자열 문자열 연결이 JVM에 의해 StringBuilder 개체 접합으로 구문 분석됩니다. 이 경우 String은 StringBuffer보다 빠릅니다. 예:

 문자열 이름 = ”I ” + ”am ” + ”chenssy ” ;

StringBuffer 이름 = new StringBuffer(”I”).append(” am ”).append(” chenssy ”);

 이 두 가지에 대해 방법을 사용하면 첫 번째 방법이 두 번째 방법보다 훨씬 빠르며 여기서는 StringBuffer의 장점이 사라집니다. 실제 이유는 JVM이 일부 최적화를 수행했기 때문입니다. 실제로 JVM의 관점에서는 String name = "I am chenssy"입니다. , JVM의 경우 실제로 시간이 걸리지 않습니다. 그러나 여기에 String 개체를 추가하면 JVM은 원래 사양에 따라 String 개체를 구성합니다.

이 세 가지가 사용되는 시나리오는 다음과 같이 요약됩니다(참조: "품질 코드 작성: Java 프로그램 개선을 위한 151가지 제안"):

1, String: 상수 선언, 소량의 변수 연산 등 문자열이 자주 변경되지 않는 장면에서 String 클래스를 사용할 수 있습니다.

2. StringBuffer: 문자열 연산(연결, 교체, 삭제 등)을 자주 수행하고 멀티 스레드 환경에서 실행하는 경우 고려할 수 있습니다. XML 구문 분석, HTTP 매개변수 구문 분석 및 캡슐화 등과 같은 StringBuffer를 사용합니다.

3. StringBuilder: 문자열 작업(연결, 교체, 삭제 등)을 자주 수행하고 멀티 스레드 환경에서 실행하는 경우 고려할 수 있습니다. SQL 문의 어셈블리, JSON 캡슐화 등은 StringBuffer를 사용합니다. (이 둘에는 |StringBuffer도 사용하는 것 같습니다.)

두 가지의 차이점에 대한 자세한 내용은 http://www.php.cn/을 참조하세요. 불필요한 불필요한 사치를 추가하지 않겠습니다.

 5. 문자열 접합 방법

문자열의 경우 종종 어셈블해야 합니다. java에는 +, concat() 및 append() 메서드 세 가지 어셈블리 메서드가 추가되었습니다. 이 세 가지의 차이점은 무엇입니까? 먼저 다음 예를 살펴보세요.

public class StringTest {
    
    /**
     * @desc 使用+、concat()、append()方法循环10W次
     * @author chenssy
     * @data 2013-11-16
     * @param args
     * @return void
     */
    public static void main(String[] args) {
        //+
        long start_01 = System.currentTimeMillis();
        String a = "a";
        for(int i = 0 ; i < 100000 ; i++){
            a += "b";
        }
        long end_01 = System.currentTimeMillis();
        System.out.println("  +   所消耗的时间:" + (end_01 - start_01) + "毫米");
        
        //concat()
        long start_02 = System.currentTimeMillis();
        String c = "c";
        for(int i = 0 ; i < 100000 ; i++){
            c = c.concat("d");
        }
        long end_02 = System.currentTimeMillis();
        System.out.println("concat所消耗的时间:" + (end_02 - start_02) + "毫米");
        
        //append
        long start_03 = System.currentTimeMillis();
        StringBuffer e = new StringBuffer("e");
        for(int i = 0 ; i < 100000 ; i++){
            e.append("d");
        }
        long end_03 = System.currentTimeMillis();
        System.out.println("append所消耗的时间:" + (end_03 - start_03) + "毫米");
    }
}

------------
Output:
  +   所消耗的时间:19080毫米
concat所消耗的时间:9089毫米
append所消耗的时间:10毫米



public class StringTest {    
    /**
     * @desc 使用+、concat()、append()方法循环10W次
     * @author chenssy
     * @data 2013-11-16
     * @param args
     * @return void     */
    public static void main(String[] args) {        //+
        long start_01 = System.currentTimeMillis();
        String a = "a";        for(int i = 0 ; i < 100000 ; i++){
            a += "b";
        }        long end_01 = System.currentTimeMillis();
        System.out.println("  +   所消耗的时间:" + (end_01 - start_01) + "毫米");        
        //concat()
        long start_02 = System.currentTimeMillis();
        String c = "c";        for(int i = 0 ; i < 100000 ; i++){
            c = c.concat("d");
        }        long end_02 = System.currentTimeMillis();
        System.out.println("concat所消耗的时间:" + (end_02 - start_02) + "毫米");        
        //append
        long start_03 = System.currentTimeMillis();
        StringBuffer e = new StringBuffer("e");        for(int i = 0 ; i < 100000 ; i++){
            e.append("d");
        }        long end_03 = System.currentTimeMillis();
        System.out.println("append所消耗的时间:" + (end_03 - start_03) + "毫米");
    }
}------------Output:  +   所消耗的时间:19080毫米
concat所消耗的时间:9089毫米
append所消耗的时间:10毫米

위의 실행 결과를 보면, Append()가 가장 빠르고, concat(), +가 가장 느린 것을 알 수 있습니다. 이유는 아래 분석을 참조하세요.


우리는 StringBuilder의 추가() 메서드를 사용하여 처리되는 +를 컴파일러가 최적화한다는 것을 앞서 알고 있습니다. StringBuilder의 속도가 StringBuffer가 더 빠르다는 것을 알고 있는데 왜 여전히 같은 속도로 실행됩니까? 주로 컴파일러는 toString()을 사용하여 이를 추가하고 문자열로 변환하기 위해 add() 메서드를 사용하기 때문입니다. 즉, str +="b"는 🎜>str = new StringBuilder(str).append("b").toString();

 느린 주요 이유는 여기서는 new StringBuilder()와 toString(), 100,000개의 StringBuilder 객체가 생성되는데, 매번 String으로 변환해야 하는데 느리지 않나요?

(2) 문자열을 연결하는 concat() 메서드  

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


이것은 concat()의 소스 코드입니다. 디지털 복사 형식인 것처럼 보입니다. 배열 처리가 매우 빠르다는 것을 알고 있지만 메서드가 다음과 같이 끝나기 때문입니다. return new String(0, count + otherLen, buf) 이것은 또한 10W 문자열 객체를 생성합니다. 속도 저하의 근본 원인.


(3) 문자열을 연결하는 추가() 메서드

public synchronized StringBuffer append(String str) {    super.append(str);        return this;
    }

StringBuffer의 Append() 메소드는 상위 클래스 AbstractStringBuilder의 Append() 메소드를 직접 사용하는 것이다.

public AbstractStringBuilder append(String str) {
    if (str == null) str = "null";
        int len = str.length();
    if (len == 0) return this;
    int newCount = count + len;
    if (newCount > value.length)
        expandCapacity(newCount);
    str.getChars(0, len, value, count);
    count = newCount;
    return this;
    }

 
concat() 메소드와 유사 , 문자 배열도 처리합니다. 길이를 늘린 다음 복사하지만 결국 새 문자열을 반환하지 않고 자체적으로 반환한다는 점에 유의하세요. .

위의 분석을 통해 적절한 위치에 적절한 문자열 접합 방법을 선택해야 하지만, 반드시 추가()와 연결()을 선택할 필요는 없습니다. ) 메서드를 사용하는 이유는 + 프로그래밍 습관에 따라 시스템 효율성에 실제로 도움이 될 수 있는 경우에만 add() 및 concat() 메서드 사용을 고려할 것이기 때문입니다. 어떤 생각이든 concat() 메서드를 사용했습니다.

위는 Java 개선편(13)의 내용입니다.----문자열 관련 내용은 PHP 중국어 홈페이지(www.php.cn)를 참고해주세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.