질문: Java에서 문자열의 최대 길이는 length() 메서드입니다. 연산자 실행 순서. 물체는 무엇으로 구성되어 있나요?

한 줄이 얼마나 많은 메모리를 차지하는지 아시나요? 나는 이 질문에 대해 “모른다”부터 “2바이트 * 줄의 문자 수”까지 온갖 종류의 대답을 들었습니다. 그러면 얼마나 걸리나요? 빈 줄? Integer 클래스의 객체가 얼마나 걸리는지 아시나요? 세 개의 정수 필드가 있는 클래스 객체는 얼마나 걸리나요? 우스운 일이지만 제가 아는 Java 프로그래머 중 단 한 명도 이 질문에 대답할 수 없습니다... 예, 우리 대부분은 이것이 전혀 필요하지 않으며 실제 Java 프로젝트의 어느 누구도 이에 대해 생각하지 않을 것입니다. 그러나 이것은 당신이 운전하고 있는 자동차의 엔진 크기를 모르는 것과 같습니다. 당신은 훌륭한 운전자가 될 수 있으며 자동차의 숫자 2.4 또는 1.6이 무엇을 의미하는지조차 모를 수 있습니다. 하지만 이 숫자의 의미를 잘 모르는 사람은 거의 없을 것이라고 확신합니다. 왜 자바 프로그래머악기의 이 부분에 대해 아는 바가 거의 없나요?

정수 대 정수
우리 모두는 자바에서는 모든 것이 객체라는 것을 알고 있습니다. 아마도 기본 요소와 개체 자체에 대한 참조는 제외됩니다. 두 가지 일반적인 상황을 살펴보겠습니다.
//첫 번째 경우 int a = 300; //두 번째 경우 정수 b = 301;
이것들 중에서 단순한 선 JVM과 OOP 모두에서 그 차이는 엄청납니다. 첫 번째 경우에는 스택의 값을 포함하는 4바이트 변수만 있습니다. 두 번째 경우에는 참조 변수와 이 변수가 참조하는 개체 자체가 있습니다. 따라서 첫 번째 경우에 점유된 크기가 다음과 같다는 것을 확실히 알 수 있습니다.
크기(정수)
그런 다음 두 번째 :
sizeOf(참조) + sizeOf(정수)
앞으로 두 번째 경우에는 소비되는 메모리 양이 약 5배 더 많으며 JVM에 따라 다르다고 말씀드리겠습니다. 이제 차이가 왜 그렇게 큰지 알아 보겠습니다.
물체는 무엇으로 구성되어 있나요?
소비되는 메모리 양을 결정하기 전에 JVM이 각 객체에 대해 무엇을 저장하는지 이해해야 합니다.
  • 개체 제목;
  • 기본 유형에 대한 메모리;
  • 참조 유형을 위한 메모리;
  • 오프셋/정렬은 본질적으로 객체 자체의 데이터 뒤에 배치되는 사용되지 않은 몇 바이트입니다. 이는 메모리 주소가 항상 기계어의 배수가 되도록 보장하고, 메모리에서 읽는 속도를 높이고, 객체 포인터의 비트 수를 줄이고, 아마도 메모리 조각화를 줄이기 위해 수행됩니다. Java에서 모든 객체의 크기는 8바이트의 배수라는 점도 주목할 가치가 있습니다!
객체 헤더 구조
클래스의 각 인스턴스에는 헤더가 포함되어 있습니다. 대부분의 JVM(Hotspot, openJVM)의 각 헤더는 두 개의 헤더로 구성됩니다. 기계어. 만약에 우리 얘기 중이야약 32 비트 시스템, 헤더 크기는 8바이트이고, 64비트 시스템에 대해 말하면 그에 따라 16바이트입니다. 각 헤더에는 다음 정보가 포함될 수 있습니다.
  • 단어 표시 - 불행하게도 나는 이 정보의 목적을 결코 찾을 수 없었습니다. 나는 그것이 미래를 위해 예약된 헤더의 일부일 뿐이라고 생각합니다.
  • 해시 코드 - 각 개체에는 해시 코드가 있습니다. 기본적으로 Object.hashCode() 메서드 호출 결과는 메모리에 있는 객체의 주소를 반환합니다. 그러나 일부 가비지 수집기는 메모리에 있는 객체를 이동할 수 있지만 객체의 공간이 있기 때문에 해시 코드는 항상 동일하게 유지됩니다. 헤더는 원래 해시 코드 값을 저장하는 데 사용될 수 있습니다.
  • 쓰레기 수거 정보 - 모두 자바 객체메모리 관리 시스템에 필요한 정보를 담고 있습니다. 이는 종종 하나 또는 두 개의 플래그 비트이지만, 예를 들어 객체에 대한 참조 수를 저장하기 위한 비트의 조합일 수도 있습니다.
  • 유형 정보 블록 포인터 - 객체 유형에 대한 정보를 포함합니다. 이 블록에는 가상 메서드 테이블 정보, 유형을 나타내는 객체에 대한 포인터, 보다 효율적인 인터페이스 호출 및 동적 유형 검사를 위한 일부 추가 구조에 대한 포인터가 포함되어 있습니다.
  • 잠금 - 각 개체에는 잠금 상태에 대한 정보가 포함되어 있습니다. 이는 잠금 개체에 대한 포인터이거나 잠금의 직접적인 표현일 수 있습니다.
  • 배열 길이 - 객체가 배열인 경우 헤더는 배열 길이를 저장하기 위해 4바이트로 확장됩니다.
자바 사양
Java의 기본 유형에는 미리 정의된 크기가 있는 것으로 알려져 있으며 이는 코드 이식성 사양에서 필요합니다. 따라서 위 링크에 모든 것이 완벽하게 설명되어 있으므로 기본 요소에 대해서는 다루지 않을 것입니다. 사양은 객체에 대해 무엇을 말합니까? 모든 개체에는 제목이 있다는 점 외에는 아무것도 없습니다. 즉, 클래스 인스턴스의 크기는 JVM마다 다를 수 있습니다. 실제로 프레젠테이션의 단순화를 위해 32비트 Oracle HotSpot JVM에 대한 예를 제시하겠습니다. 이제 가장 많이 사용되는 클래스인 Integer와 String을 살펴보겠습니다.
정수와 문자열
이제 Integer 클래스의 객체가 32비트 HotSpot JVM에서 얼마나 많은 부분을 차지할지 계산해 보겠습니다. 이를 위해서는 클래스 자체를 조사해야 합니다. 우리는 정적으로 선언되지 않은 모든 필드에 관심이 있습니다. 이 중 int 값은 하나만 표시됩니다. 이제 위의 정보를 바탕으로 다음을 얻습니다.
헤더: 8바이트 Int 필드: 4바이트 8의 배수 정렬: 4바이트 총계: 16바이트
이제 문자열 클래스를 살펴보겠습니다.
비공개 최종 문자 값; 개인 최종 int 오프셋; 비공개 최종 정수 개수; 비공개 int 해시;
그리고 크기를 계산해 봅시다:
헤더: 8바이트 Int 필드: 4바이트 * 3 == 12바이트 배열 객체 참조 변수: 4바이트 전체: 24바이트
글쎄, 그게 전부는 아닙니다... 문자열에는 문자 배열에 대한 참조가 포함되어 있으므로 실제로 우리는 두 가지 다른 개체, 즉 개체를 다루고 있습니다. 클래스 문자열문자열을 저장하는 배열 자체입니다. 이는 OOP 관점에서는 맞는 것 같지만, 메모리 측면에서 보면 결과 크기에 문자에 할당된 배열의 크기를 더해야 한다. 그리고 이는 배열 객체 자체에 대한 또 다른 12바이트 + 문자열의 각 문자에 대한 2바이트입니다. 그리고 물론 8바이트의 배수에 대한 정렬을 추가하는 것을 잊지 마세요. 결국, 단순해 보이는 문자열 new String("a") 의 결과는 다음과 같습니다.
new String() 헤더: 8바이트 필드 int: 4바이트 * 3 == 12바이트 배열 객체에 대한 참조 변수: 4바이트 총계: 24바이트 new char 헤더: 8바이트 + 배열 길이용 4바이트 == 12바이트 기본 문자: 2바이트 * 1 == 2바이트 다중성을 위한 정렬 8: 2바이트 총계: 16바이트 총계, new String("a") == 40바이트
new String("a") 과 new String("aa") 은 동일한 양의 메모리를 차지한다는 점에 유의하는 것이 중요합니다. 이것을 이해하는 것이 중요합니다. 전형적인 예이 사실을 활용하는 것은 String 클래스의 해시 필드입니다. 거기에 없으면 문자열 개체는 정렬로 인해 어떤 식으로든 24바이트를 차지하게 됩니다. 그리고 이 4바이트는 매우 가치 있는 용도로 사용되는 것으로 나타났습니다. 훌륭한 솔루션이지 않나요?
링크 크기
참조 변수에 대해 조금 유보하고 싶습니다. 원칙적으로 JVM의 링크 크기는 비트 깊이에 따라 달라지며 최적화 목적으로 의심됩니다. 따라서 32비트 JVM에서는 링크 크기가 일반적으로 4바이트이고 64비트 JVM에서는 8바이트입니다. 이 조건은 필요하지 않지만.
필드 그룹화
또한 JVM은 객체의 필드를 사전 그룹화한다는 점에 유의해야 합니다. 이는 클래스의 모든 필드가 선언된 순서가 아닌 특정 순서로 메모리에 배치됨을 의미합니다. 그룹화 순서는 다음과 같습니다.
  • 1. 8바이트 유형(더블 및 롱)
  • 2. 4바이트 유형(int 및 float)
  • 3. 2바이트 유형(short 및 char)
  • 4. 단일 바이트 유형(부울 및 바이트)
  • 5. 참조변수
이게 다 뭐죠?
때로는 사전과 같은 특정 개체를 저장하기 위한 대략적인 메모리 양을 추정해야 하는 상황이 발생합니다. 이 작은 도움은 길을 빨리 찾는 데 도움이 될 것입니다. 또한 이는 잠재적으로 가능한 방법특히 설정에 액세스할 수 없는 환경에서는 최적화됩니다.
결론
Java의 메모리 주제는 매우 흥미롭고 광범위합니다. 이 기사를 쓰기 시작했을 때 결론과 함께 몇 가지 예에 적용할 것이라고 생각했습니다. 그러나 더 깊이 파고들수록 더 흥미로워집니다. 일반적으로 객체에 메모리가 할당되는 방식을 아는 것은 매우 중요합니다. 유용한 것, 메모리를 절약하는 데 도움이 되므로

안에 자바, 무엇인가요 최대 크기 String 객체는 참조하는 length() 메소드 호출을 가질 수 있습니까?

나는 length()가 String의 크기를 char로 반환한다는 것을 알고 있습니다.


2018-05-03 02:35

배열은 int 값으로 색인화되어야 합니다.

따라서 극한은 실제로 2^31 - 1이라는 것이 밝혀졌습니다. 최대값음수가 아닌 정수의 경우 비용.

그러나 할당된 배열의 최대 크기와 같은 다른 제한 사항이 있을 수 있습니다.


2018-05-03 02:34

따라서 int의 최대값은 2147483647 ,

문자열은 내부 문자 배열로 간주되므로 최대 범위 내에서 인덱싱이 수행됩니다. 이는 2147483648번째 멤버를 인덱싱할 수 없음을 의미합니다. 따라서 Java의 최대 문자열 길이는 2147483647입니다.

기본 유형 int 데이터는 Java에서 4바이트(32비트)입니다. 1비트(MSB)를 사용하므로 서명 비트,범위는 다음으로 제한됩니다. -2^31에서 2^31-1(-2147483648에서 2147483647까지). 인덱싱에는 음수 값을 사용할 수 없습니다. 분명히 우리가 사용할 수 있는 범위는 0부터 2147483647까지입니다.


나는 8GB의 2010 iMac을 가지고 있습니다. 랜덤 액세스 메모리, Eclipse Neon.2 릴리스(4.6.2) 실행 자바를 사용하여 1.8.0_25. VM 인수 -Xmx6g를 사용하여 다음 코드를 실행했습니다.

StringBuilder sb = new StringBuilder(); for (int i = 0; i< Integer.MAX_VALUE; i++) { try { sb.append("a"); } catch (Throwable e) { System.out.println(i); break; } } System.out.println(sb.toString().length());

이것은 다음을 인쇄합니다:

요청한 배열 크기가 VM 제한 1207959550을 초과합니다.

따라서 최대 배열 크기는 ~1207,959,549인 것 같습니다. 그런 다음 우리는 Java에서 메모리 부족에 관심이 없다는 것을 깨달았습니다. 우리는 단지 배열의 최대 크기(상수로 정의된 것으로 나타남)를 찾고 있을 뿐입니다. 그래서:

(int i = 0; i< 1_000; i++) { try { char array = new char; Arrays.fill(array, "a"); 문자열 문자열= 새로운 문자열(배열); System.out.println(string.length()); ) catch (Throwable e) ( System.out.println(e.getMessage()); System.out.println("마지막: " + (Integer.MAX_VALUE - i)); System.out.println("마지막: " + 나);

인쇄 내용:

요청한 배열 크기가 VM 제한을 초과함 마지막: 2147483647 마지막: 0 요청한 배열 크기가 VM 제한을 초과함 마지막: 2147483646 마지막: 1 Java 힙 공간 마지막: 2147483645 마지막: 2

따라서 max는 Integer.MAX_VALUE - 2 또는 (2^31) - 3인 것 같습니다.

내 StringBuilder의 최대값은 1207959550인 반면 내 문자의 최대값은 (2^31)-3인 이유를 잘 모르겠습니다. AbstractStringBuilder는 내부 문자의 크기를 두 배로 늘려서 크기를 늘리는 것 같으니 아마도 문제일 것입니다.


이 장에서는 도구에 대해 설명합니다. 자바 언어문자열 작업용. C 및 C++ 언어에는 문자열과 같은 개체에 대한 기본 지원이 없습니다. 필요한 경우 바이트 시퀀스의 주소를 전송하며, 그 내용은 0바이트가 나타날 때까지 문자로 처리되어 행의 끝을 표시합니다. java.lang 패키지에는 문자열에 해당하는 데이터 구조를 캡슐화하는 클래스가 내장되어 있습니다. 이 클래스는 는 불변 문자 배열의 객체 표현에 지나지 않습니다. 이 클래스에는 문자열을 비교하고 검색하고 특정 문자와 부분 문자열을 추출할 수 있는 메서드가 있습니다. . 수업 문자열 버퍼문자열을 생성한 후 수정해야 할 경우에 사용됩니다.

주목

String과 StringBuffer는 모두 final로 선언되었습니다. 즉, 두 클래스 모두 하위 클래스로 분류할 수 없습니다. 이는 문자열 처리 작업을 수행할 때 성능을 높이기 위해 특정 유형의 최적화를 적용할 수 있도록 수행되었습니다.

생성자

다른 클래스와 마찬가지로 new 연산자를 사용하여 String 유형의 객체를 생성할 수 있습니다. 빈 문자열을 만들려면 매개변수 없는 생성자를 사용하세요.

문자열 s = 새 문자열():

다음 코드 조각은 문자 배열의 매개변수로 생성자에 전달된 세 문자의 문자열로 초기화하여 String 유형의 객체를 생성합니다.

char 문자 = ("a", "b", "c"):

문자열 s = 새로운 문자열(문자);

System.out.println(들):

이 코드 조각은 "abc"라는 문자열을 출력합니다. 따라서 이 생성자에는 3개의 매개변수가 있습니다.

String(char chars, intitialIndex, int numberCharacters);

다음 예에서는 이 초기화 방법을 사용합니다.

char chars = ("a", "b", "c", "d", "e", "f" ):

문자열 s = 새로운 문자열(문자,2,3);

System.out.println(s);

이 스니펫은 "cde"를 출력합니다.

문자열 작업을 위한 특수 구문

Java에는 프로그래머가 문자열 작업을 수행하는 데 도움이 되도록 설계된 몇 가지 유용한 구문 추가 기능이 포함되어 있습니다. 이러한 작업에는 String 객체 생성, 여러 문자열 병합, 기타 데이터 유형을 문자 표현으로 변환 등이 포함됩니다.

문자열 만들기

Java에는 이 작업에 대한 표준 약칭, 즉 문자열의 내용을 쌍으로 묶는 리터럴 표기법이 포함되어 있습니다. 큰따옴표. 다음 코드 조각은 문자열이 char 유형의 배열로 초기화된 이전 코드 조각과 동일합니다.

문자열 s = "abc";

System.out.println(s);

다음 중 하나 일반적인 방법 String 객체와 함께 사용되는 길이 메서드는 문자열의 문자 수를 반환합니다. 다음 조각에는 사용된 문자열에 3개의 문자가 포함되어 있으므로 숫자 3을 표시합니다.

문자열 s = "abc";

System.out.println(s.length);

Java의 흥미로운 점은 각 문자열 리터럴에 고유한 문자열 클래스 대표가 있으므로 참조 변수뿐만 아니라 문자열 리터럴에서 직접 해당 클래스의 메서드를 호출할 수 있다는 것입니다. 다음 예에서는 숫자 3도 표시합니다.

System.out.println("abc".길이 () );

문자열 병합

즉시

문자열 s = "아님" + 나이 + "세.";

+ 연산자를 사용하여 세 줄을 하나로 결합한 경우 첫 번째 예에서 암시적으로 사용된 바로 그 메서드를 명시적으로 호출하여 작성된 해당 항목보다 확실히 읽고 이해하기가 더 쉽습니다.

String s = new StringBuffer("그는 ").append(age);

s.append("세.").toString();

정의에 따르면 String 클래스의 모든 개체는 수정할 수 없습니다. 기존 문자열에 새 문자를 삽입하거나 해당 문자열의 일부 문자를 다른 문자로 변경할 수 없습니다. 그리고 한 줄을 다른 줄 끝에 추가할 수도 없습니다. 따라서 Java 변환기는 String 객체의 수정처럼 보이는 작업을 관련 StringBuffer 클래스에 대한 작업으로 변환합니다.

논평

이 모든 것이 당신에게는 불합리하게 복잡해 보일 수 있습니다. String 클래스 하나만 사용하여 StringBuffer와 거의 동일한 방식으로 동작하도록 허용할 수 없는 이유는 무엇입니까? 그것은 성능에 관한 것입니다. Java String 객체가 불변이라는 사실로 인해 변환기는 이를 사용한 작업에 다양한 최적화를 적용할 수 있습니다.

연산자 실행 순서

마지막 예를 다시 살펴보겠습니다.

String s = "" + 나이 + " 세가 아닙니다.";

age가 문자열이 아니라 int 유형의 변수인 경우 이 코드 줄에는 더 많은 변환기 마법이 포함됩니다. 정수값 정수 변수 StringBuffer 클래스의 추가 메소드에 전달되어 다음으로 변환됩니다. 텍스트 보기그리고 이를 객체에 포함된 문자열의 끝에 추가합니다. 전체 표현식과 문자열 연결을 함께 사용할 때는 주의해야 합니다. 그렇지 않으면 결과가 예상한 것과 다를 수 있습니다. 다음 줄을 살펴보십시오.

문자열 s = "4: " + 2 + 2;

아마도 s에 "four: 4"라는 문자열이 포함될 것이라고 기대하고 계십니까? 당신의 추측이 옳지 않다면 진술의 실행 순서가 당신에게 잔인한 농담을 한 것입니다. 결과는 "4:22" 입니다. .

정수 추가를 먼저 수행하려면 괄호를 사용해야 합니다.

문자열 = "4: " + (2 + 2);

문자열 변환

각 String 클래스에는 자체 구현이거나 Object 클래스에서 상속된 기본 구현인 toString 메서드가 있습니다. 다음 예제의 클래스는 상속된 toStrring 메소드를 자체 메소드로 대체하여 객체의 변수 값을 표시할 수 있습니다.

클래스 포인트(

정수 x, y;

포인트(int x, int y) (

this.x = x;

this.y = y;

}

공개 문자열 toString() (

"점[" + x + ", " + y + "]"를 반환합니다.

} }

클래스 toStringDemo(

포인트 p = new Point(10, 20);

System.out.println("p = " + p);

} }

아래는 이 예제를 실행했을 때 얻은 결과입니다.

C:\>Java toStringDemo
p = 포인트

문자 추출

문자열에서 단일 문자를 추출하려면 charAt 메서드를 사용하여 문자열에 있는 문자의 인덱스를 직접 참조할 수 있습니다. 한 번에 여러 문자를 추출하려면 getChars 메소드를 사용할 수 있습니다. 다음 조각은 String 객체에서 문자 배열을 추출하는 방법을 보여줍니다.

클래스 getCharsDemo(

공개 정적 무효 메인(문자열 인수) (

String s = "이것은 getChars 메소드의 데모입니다.";

int 시작 = 10;

int 끝 = 14;

char buf = 새 문자;

s.getChars(시작, 끝, buf, 0);

System.out.println(buf);

} }

getChars 메소드는 출력 버퍼에 인덱스 끝이 있는 문자를 포함하지 않는다는 점에 유의하십시오. 이는 예제의 출력에서 ​​명확하게 볼 수 있습니다. 출력 문자열은 4자로 구성됩니다.

C:\> 자바 getCharsDemo

데모

사용 편의성을 위해 String에는 전체 문자열을 출력 char 배열로 반환하는 toCharArray라는 또 다른 함수가 있습니다. 동일한 메커니즘의 대체 형식을 사용하면 문자열의 내용을 바이트 배열에 기록하고 높은 바이트 값을 삭제할 수 있습니다. ​16비트 문자입니다. 해당 메소드는 getBytes라고 하며 해당 매개변수는 getChars의 매개변수와 동일한 의미를 갖지만 유일한 차이점은 바이트 유형의 배열을 세 번째 매개변수로 사용해야 한다는 것입니다.

비교

두 문자열이 동일한지 알고 싶다면 String 클래스의 equals 메소드를 사용해야 합니다. 이 방법의 대체 형식은 비교 시 대소문자 차이를 무시하는 equalsIgnoreCase입니다. 다음은 두 가지 방법의 사용을 보여주는 예입니다.

클래스 EqualDemo(

공개 정적 무효 메인(문자열 인수) (

문자열 s1 = "안녕하세요";

문자열 s2 = "안녕하세요";

문자열 s3 = "안녕하세요";

문자열 s4 = "안녕하세요";

System.out.println(s1 + " 같음 " + s2 + " -> " + s1.equals(s2));

System.out.println(s1 + " 같음 " + s3 + " -> " + s1.equals(s3));

System.out.println(s1 + " 같음 " + s4 + " -> " + s1.equals(s4));

System.out.println(s1 + " equalsIgnoreCase " + s4 + " -> " +

s1.equalsIgnoreCase(s4));

} }

이 예제를 실행한 결과는 다음과 같습니다.

C:\>java equalsDemo

Hello는 Hello -> true와 같습니다.

안녕하세요는 작별 인사와 같습니다 -> 거짓

Hello는 HELLO -> false와 같습니다.

안녕하세요 같음IgnoreCase HELLO -> true

String 클래스는 그룹을 구현합니다. 서비스 방법는 equals 메소드의 특수 버전입니다. RegionMatches 메서드는 소스 문자열의 하위 문자열을 매개변수 문자열의 하위 문자열과 비교하는 데 사용됩니다. startWith 메소드는 주어진 하위 문자열이 메소드에 매개변수로 전달된 조각으로 시작하는지 여부를 확인합니다. endWith 메소드는 문자열의 끝이 매개변수와 일치하는지 확인합니다.

평등

equals 메소드와 == 연산자는 완전히 다른 두 가지 테스트를 수행합니다. 같음 메서드가 문자열 내의 문자를 비교하는 반면 == 연산자는 두 개체 참조 변수를 비교하여 해당 변수가 다른 개체를 가리키는지 아니면 동일한 개체를 가리키는지 확인합니다. 다음 예에서 이는 명확하게 볼 수 있습니다. 두 문자열의 내용은 동일하지만 그럼에도 불구하고 이들은 서로 다른 개체이므로 동일 및 ==는 서로 다른 결과를 제공합니다.

클래스 EqualsNotEqualTo(

공개 정적 무효 메인(문자열 인수) (

문자열 s1 = "안녕하세요";

문자열 s2 = 새 문자열(s1);

System.out.println(s1 + " 같음 " + s2 + " -> " + s1.equals(s2));

System.out.println(s1 + " == " + s2 + ", -> " + (s1 == s2));

} }

이 예제를 실행한 결과는 다음과 같습니다.

C:\>java EqualsNotEqualTo

Hello는 Hello -> true와 같습니다.
안녕하세요 == 안녕하세요 -> 거짓

주문

단순히 두 문자열이 동일한지 여부를 아는 것만으로는 충분하지 않은 경우가 많습니다. 정렬이 필요한 애플리케이션의 경우 두 문자열 중 어느 문자열이 다른 문자열보다 작은지 알아야 합니다. 이 질문에 답하려면 String 클래스의 CompareTo 메서드를 사용해야 합니다. 메서드에서 반환된 정수 값이 음수인 경우 메서드가 호출된 문자열은 매개변수 문자열보다 작습니다. 양수인 경우 더 큽니다. CompareTo 메서드가 0을 반환하면 행이 동일한 것입니다. 다음은 문자열 배열을 버블 정렬하고 CompareTo 메서드를 사용하여 문자열을 비교하는 프로그램입니다. 알파벳 순서문자열 목록.

클래스 SortString(

static String arr = ("지금", "is", "the", "time", "for", "all",

"좋은", "남자", "에", "와서", "에", "the",

"원조", "의", "그들의", "국가" );

공개 정적 무효 메인(문자열 인수) (

for (int j = 0; i< arr.length; j ++) {

for (int i = j + 1; 나< arr.length; i++) {

if (arr[i].compareTo(arr[j])< 0) {

문자열 t = arr[j];

arr[j] = arr[i];

arr[i] = t;

}

}

System.out.println(arr[j]);

}

} }

indexOf 및 lastIndexOf

String 클래스에는 특정 문자나 하위 문자열 검색에 대한 지원이 포함되어 있습니다. 이를 위해 indexOf와 lastIndexOf라는 두 가지 메서드가 있습니다. 이러한 각 메서드는 찾으려는 문자의 인덱스 또는 검색된 하위 문자열의 시작 부분의 인덱스를 반환합니다. 어떤 경우든 검색에 실패하면 메서드는 -1을 반환합니다. 또 다른 예는 이러한 검색 방법의 다양한 변형을 사용하는 방법을 보여줍니다.

클래스 indexOfDemo(

공개 정적 무효 메인(문자열 인수) (

String s = "지금은 모든 선한 사람들을 위한 시간입니다. " +

"그들의 나라를 돕기 위해 " +

"그리고 정당한 세금을 지불합니다.";

System.out.println(s);

System.out.println("indexOf(t) = " + s.indexOf("f'));

System.out.println("lastlndexOf(t) = " + s.lastlndexOf("f'));

System.out.println("indexOf(the) = " + s.indexOf("the"));

System.out.println("lastlndexOf(the) = " + s.lastlndexOf("the"));

System.out.println("indexOf(t, 10) = " + s.indexOf("f' , 10));

System.out.println("lastlndexOf(t, 50) = " + s.lastlndexOf("f' , 50));

System.out.println("indexOf(the, 10) = " + s.indexOf("the", 10));

System.out.println("lastlndexOf(the, 50) = " + s.lastlndexOf("the", 50));

} }

아래는 이 프로그램의 출력입니다. 행의 인덱스는 0부터 시작합니다.

보낸 사람:> java indexOfDemo

이제 모든 선한 사람들이 조국을 돕기 위해 나서야 할 때입니다

그리고 그들의 합당한 세금을 지불하십시오.

indexOf(t) = 7

lastIndexOf(t) = 87

indexOf(the) = 7

lastIndexOf(the) = 77

index0f(t, 10) = 11

lastlndex0f(t, 50) = 44

index0f(the, 10) = 44

lastlndex0f(the, 50) = 44

복사할 때 문자열 수정

String 객체는 수정할 수 없기 때문에 문자열을 수정하고 싶을 때마다 이를 StringBuffer 객체에 복사하거나 생성하는 다음 String 클래스 메서드 중 하나를 사용해야 합니다. 새 사본행을 변경합니다.

하위 문자열

메소드를 사용하여 String 객체에서 부분 문자열을 추출할 수 있습니다. 하위 문자열. 이 메서드는 호출 시 지정한 원본 문자열의 인덱스 범위에서 새 문자 복사본을 만듭니다. 원하는 하위 문자열의 첫 번째 문자의 인덱스만 지정할 수 있습니다. 그러면 지정된 문자부터 시작하여 문자열의 끝으로 끝나는 모든 문자가 복사됩니다. 시작 인덱스와 끝 인덱스를 모두 지정할 수도 있습니다. 이 경우에는 새 줄지정된 첫 번째 문자부터 시작하여 끝 색인으로 지정된 문자까지(포함하지 않음) 모든 문자가 복사됩니다.

"Hello World".substring(6) -> "세계"

"Hello World".substring(3,8) -> "lo Wo"

문자열 병합 또는 연결은 concat 메서드를 사용하여 수행됩니다. 이 메소드는 원래 문자열의 내용을 복사하고 메소드 매개변수에 지정된 문자열을 추가하여 새 String 객체를 생성합니다.

"Hello".concat(" World") -> "Hello World"

바꾸기 메소드는 두 문자를 매개변수로 사용합니다. 첫 번째 문자와 일치하는 모든 문자는 문자열의 새 복사본에서 두 번째 문자로 대체됩니다.

"안녕하세요".replace("l" , "w") -> "휴워"

toLowerCase 및 toUpperCase

이 메소드 쌍은 원래 문자열의 모든 문자를 소문자로 변환하고 대문자, 각각.

"안녕하세요".toLowerCase() -> "안녕하세요"

"안녕하세요".toUpperCase() -> "안녕하세요"

마지막으로 Trim 메서드는 소스 문자열에서 모든 선행 및 후행 공백을 제거합니다.

“Hello World“.trirn() -> "Hello World"

가치

데이터 유형을 다루고 해당 유형의 값을 사람이 읽을 수 있는 형식으로 출력하려면 먼저 해당 값을 텍스트 문자열로 변환해야 합니다. 이에 대한 valueOf 메소드가 있습니다. 이러한 정적 메서드는 기존의 모든 메서드에 대해 정의됩니다. 자바 유형데이터(이러한 모든 메서드는 결합되어 있습니다. 즉, 동일한 이름을 사용합니다). 이를 통해 모든 유형의 값을 문자열로 쉽게 변환할 수 있습니다.

문자열 버퍼

StringBuffer는 문자열 작업 시 일반적으로 필요한 많은 기능을 제공하는 String 클래스의 쌍입니다. String 클래스의 객체는 수정할 수 없는 고정 길이 문자열입니다. StringBuffer 유형의 객체는 확장 및 수정이 가능한 문자 시퀀스입니다. Java에서는 두 클래스를 모두 광범위하게 사용하지만 많은 프로그래머는 + 연산자를 사용하여 String 개체로만 작업하는 것을 선호합니다. 그러나 Java는 뒤에서 StringBuffer를 사용하여 필요한 모든 작업을 수행합니다.

생성자

StringBuffer 객체는 매개변수 없이 생성될 수 있으며 문자열 길이를 변경할 수 없는 16자용 공간이 예약되어 있습니다. 필요한 버퍼 크기를 명시적으로 지정하기 위해 생성자에 정수를 전달할 수도 있습니다. 마지막으로 생성자에 문자열을 전달할 수 있습니다. 생성자는 해당 문자열을 객체에 복사하고 추가로 16자를 위한 공간을 추가로 예약합니다. StringBuffer의 현재 길이는 메소드를 호출하여 확인할 수 있습니다. 길이, StringBuffer 객체의 문자열용으로 예약된 전체 공간을 확인하려면 다음 메서드를 사용해야 합니다. 용량. 아래는 이를 설명하는 예입니다.

클래스 StringBufferDemo(

공개 정적 무효 메인(문자열 인수) (

System.out.println("버퍼 = " + sb);

System.out.println("length = " + sb.length());

시스템아웃. println("용량 = " + sb.capacity());

} }

다음은 이 프로그램의 출력입니다. 이는 String-Buffer 개체에 문자열 조작을 위해 예약된 추가 공간이 있음을 보여줍니다.

C:\>자바 StringBufferDemo

버퍼 = 안녕하세요

길이 = 5

용량 = 21

보장용량

StringBuffer 객체를 생성한 후 특정 문자 수에 대한 공간을 확보하려는 경우 다음을 수행할 수 있습니다. 을 위한메소드를 사용하여 버퍼 크기를 설정하십시오. 용량 보장. 이는 버퍼에 작은 줄을 많이 추가해야 한다는 것을 미리 알고 있을 때 유용합니다.

길이 설정

갑자기 버퍼의 문자열 길이를 명시적으로 설정해야 하는 경우 setLength 메서드를 사용하세요. 객체에 포함된 문자열의 길이보다 큰 값을 지정하는 경우 이 메서드는 새로 확장된 문자열의 끝을 null 문자로 채웁니다. 아래 setCharDemo 프로그램은 sstLength 메소드를 사용하여 버퍼를 줄입니다.

charAt 및 setCharAt

메소드를 사용하여 StringBuffer 객체에서 단일 문자를 추출할 수 있습니다. 문자. 또 다른 방법 setCharAt줄의 특정 위치에 원하는 문자를 쓸 수 있습니다. 이 두 가지 방법의 사용은 다음 예에서 설명됩니다.

클래스 setCharAtDemo(

공개 정적 무효 메인(문자열 인수) (

StringBuffer sb = new StringBuffer("안녕하세요");

System.out.println("버퍼 이전 = " + sb);

System.out.println("charAt(1) before = " + sb.charAt(1));

sb.setCharAt(1, "i");

sb.setLength(2);

System.out.println("버퍼 이후 = " + sb);

System.out.println("charAt(1) after = " + sb.charAt(1));

} }

다음은 이 프로그램을 실행할 때 얻은 출력입니다.

C:\> 자바 setCharAtDemo

이전 버퍼 = 안녕하세요

= e 이전의 charAt(1)

이후 버퍼 = 안녕

charAt(1) 이후 = i

추가

방법 추가 StringBuffer 클래스는 일반적으로 문자열 표현식에서 + 연산자를 사용할 때 암시적으로 호출됩니다. 각 매개변수에 대해 String.valueOf 메소드가 호출되고 해당 결과가 현재 StringBuffer 객체에 추가됩니다. 또한 추가 메서드가 호출될 때마다 호출된 StringBuffer 개체에 대한 참조를 반환합니다. 이를 통해 다음 예제와 같이 연속적인 메서드 호출을 연결할 수 있습니다.

클래스 추가데모(

공개 정적 무효 메인(문자열 인수) (

문자열 s;

정수 a = 42;

StringBuffer sb = new StringBuffer(40);

s = sb.append("a = ").append(a).append("!").toString();

System.out.println(s);

} }

이 예제의 출력은 다음과 같습니다.

C:\> Java 추가 데모

a = 42!

끼워 넣다

방법 끼워 넣다각각에 대해 다음과 같은 점에서 추가 방법과 동일합니다. 가능한 유형데이터에는 이 방법을 결합한 자체 버전이 있습니다. 그러나 추가와 달리 String.valueOf 메서드에서 반환된 문자를 StringBuffer 객체의 끝에 추가하지 않고 특정 장소버퍼에서 첫 번째 매개변수로 지정됩니다. 다음 예에서는 "hello"와 "world!" 사이에 문자열 "There"가 삽입됩니다.

클래스 insertDemo(

공개 정적 voidmain(문자열 인수) (

StringBuffer sb = new StringBuffer("안녕하세요!");

sb.insert(6,"거기");

System.out.println(sb);

} }

이 프로그램을 실행하면 다음 줄이 출력됩니다.

C:\>java insertDemo

안녕 세상아!

선 없이는 할 수 없습니다

Java 프로그래밍의 거의 모든 측면에는 어느 시점에서 String 및 StringBuffer 클래스의 사용이 포함됩니다. 디버깅할 때, 텍스트로 작업할 때, 파일 이름을 지정할 때 필요합니다. URL메소드에 대한 매개변수로. Java에서 대부분의 문자열의 모든 두 번째 바이트는 null입니다(유니코드 아직 거의 사용되지 않음). Java에서 두 번 필요한 문자열 더 많은 메모리일반 ASCII보다 별로 무섭지 않습니다. 효율적인 작업편집기 및 기타의 텍스트 포함 유사한 응용 프로그램거대한 문자 배열로 직접 작업할 필요가 없습니다.

이는 2^31 - 1(또는 약 20억)과 같습니다.

배열의 길이 및 인덱싱(예: String 의 내부 데이터를 나타내는 방법인 char 등)과 관련하여 10장: 배열 Java 언어 사양, Java SE 7 Edition에서는 다음과 같이 설명합니다.

배열에 포함된 변수에는 이름이 없습니다. 대신 음수가 아닌 정수 값 인덱스를 사용하는 배열 액세스 표현식을 참조합니다. 이러한 변수를 배열 구성요소라고 합니다. 배열에 n개의 구성 요소가 있는 경우 n은 배열의 길이라고 합니다. 배열의 구성 요소는 0부터 n - 1까지의 정수 인덱스를 사용하여 참조됩니다.

또한 인덱싱에는 섹션 10.4에 지정된 대로 int 값이 있어야 합니다.

배열은 int 값으로 색인화되어야 합니다.

따라서 한계는 실제로 2^31 - 1 입니다. 이는 음수가 아닌 int 값의 최대값이기 때문입니다.

그러나 할당된 배열의 최대 크기와 같은 다른 제한 사항이 있을 수 있습니다.

String 클래스의 length() 메서드의 반환 유형 정수.

따라서 int의 최대값은 2147483647 .

문자열은 내부 char 배열로 간주되므로 최대 범위 내에서 인덱싱이 수행됩니다. 이는 2147483648번째 멤버를 인덱싱할 수 없음을 의미합니다. 따라서 Java의 최대 문자열 길이는 2147483647입니다.

Java에서는 기본 데이터 유형 int가 4바이트(32비트)입니다. 부호 비트는 1비트(MSB)입니다. 범위는 -2^31 ~ 2^31-1(-2147483648 ~ 2147483647)로 제한됩니다. 인덱싱에는 음수 값을 사용할 수 없습니다. 분명히 우리가 사용할 수 있는 범위는 0부터 2147483647까지입니다.

저는 Java 1.8.0_25와 함께 Eclipse Neon.2 릴리스(4.6.2)를 실행하는 8GB RAM의 2010 iMac을 가지고 있습니다. VM 인수 -Xmx6g를 사용하여 다음 코드를 실행했습니다.

StringBuilder sb = new StringBuilder(); for (int i = 0; i< Integer.MAX_VALUE; i++) { try { sb.append("a"); } catch (Throwable e) { System.out.println(i); break; } } System.out.println(sb.toString().length());

인쇄물:

요청한 배열 크기가 VM 제한 1207959550을 초과합니다.

따라서 최대 배열 크기는 ~1207,959,549인 것 같습니다. 그런 다음 우리는 Java에서 메모리 부족에 관심이 없다는 것을 깨달았습니다. 우리는 단지 배열의 최대 크기(상수로 정의된 것으로 나타남)를 찾고 있을 뿐입니다. 그래서:

(int i = 0; i< 1_000; i++) { try { char array = new char; Arrays.fill(array, "a"); String string = new String(array); System.out.println(string.length()); } catch (Throwable e) { System.out.println(e.getMessage()); System.out.println("Last: " + (Integer.MAX_VALUE - i)); System.out.println("Last: " + i); } }

인쇄 내용:

요청한 배열 크기가 VM 제한을 초과함 마지막: 2147483647 마지막: 0 요청한 배열 크기가 VM 제한을 초과함 마지막: 2147483646 마지막: 1 Java 힙 공간 마지막: 2147483645 마지막: 2

따라서 max는 Integer.MAX_VALUE - 2 또는 (2^31) - 3인 것 같습니다.

추신 왜 내 StringBuilder가 1207959550으로 최대치를 기록했고 내 문자가 (2^31)-3 표시를 초과했는지 잘 모르겠습니다. AbstractStringBuilder가 내부 문자의 크기를 두 배로 늘려서 더 크게 만드는 것 같습니다. 이로 인해 문제가 발생할 수 있습니다.



질문이 있으신가요?

오타 신고

편집자에게 전송될 텍스트: