자바 문자열 : "String s = new String ("silly ");"
저는 Java를 배우는 C ++ 사람입니다. 저는 Effective Java를 읽고 있는데 뭔가 혼란 스러웠습니다. 다음과 같은 코드를 작성하지 말라고합니다.
String s = new String("silly");
불필요한 String
물건을 만들기 때문입니다. 그러나 대신 다음과 같이 작성해야합니다.
String s = "No longer silly";
지금까지는 괜찮아요 ...하지만이 수업이 주어지면 :
public final class CaseInsensitiveString {
private String s;
public CaseInsensitiveString(String s) {
if (s == null) {
throw new NullPointerException();
}
this.s = s;
}
:
:
}
CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
String s = "polish";
첫 번째 진술은 왜 괜찮습니까? 그럴까요?
CaseInsensitiveString cis = "Polish";
어떻게해야합니까
CaseInsensitiveString
처럼 행동String
때문에 위의 문 (와 연장없이 OK입니다String
)? 리터럴을 그대로 전달할 수 있도록하는 것은 String에 대해 무엇입니까? 내 이해에서 Java에는 "복사 생성자"개념이 없습니까?
String
언어의 특수 내장 클래스입니다. 말을 피해야 하는 String
수업 만을 위한 것입니다.
String s = new String("Polish");
리터럴 "Polish"
은 이미 유형 String
이고 불필요한 개체를 추가로 생성하고 있기 때문입니다 . 다른 수업의 경우
CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
해야 할 올바른 일입니다 (이 경우에만).
리터럴 형식 (즉, new String ( "foo")이 아닌 "foo")을 사용할 때의 주요 이점은 모든 문자열 리터럴이 VM에 의해 '인턴'된다는 것입니다. 즉, 동일한 문자열을 생성하는 다른 코드가 새 인스턴스를 생성하는 대신 풀링 된 문자열을 사용하도록 풀에 추가됩니다.
설명을 위해 다음 코드는 첫 번째 줄에는 true를, 두 번째 줄에는 false를 인쇄합니다.
System.out.println("foo" == "foo");
System.out.println(new String("bar") == new String("bar"));
문자열은 자바에서 약간 특별하게 취급되며 불변이므로 참조 계수로 처리하는 것이 안전합니다.
쓰면
String s = "Polish";
String t = "Polish";
그러면 s와 t는 실제로 동일한 객체를 참조하고 s == t는 "=="객체에 대해 true를 반환합니다. "is the same object"라는 객체를 읽습니다 (또는 어쨌든 이것이 다음의 일부인지 확실하지 않습니다. 실제 언어 사양 또는 단순히 컴파일러 구현의 세부 사항-따라서 이것에 의존하는 것이 안전하지 않을 수 있습니다).
쓰면
String s = new String("Polish");
String t = new String("Polish");
그런 다음 s! = t (명시 적으로 새 문자열을 만들었으므로) s.equals (t)는 true를 반환하지만 (문자열이이 동작을 같음에 추가하기 때문에).
당신이 쓰고 싶은 것은
CaseInsensitiveString cis = "Polish";
따옴표가 객체에 대한 일종의 단락 생성자라고 생각하기 때문에 작동하지 않습니다. 사실 이것은 평범한 오래된 java.lang.Strings에서만 작동합니다.
String s1="foo";
리터럴은 풀에 들어가고 s1은 참조합니다.
String s2="foo";
이번에는 "foo"리터럴이 StringPool에서 이미 사용 가능하거나 현재 존재하지 않으므로 s2가 동일한 리터럴을 참조하는지 확인합니다.
String s3=new String("foo");
"foo"리터럴은 먼저 StringPool에 생성 된 다음 string arg 생성자를 통해 String Object가 생성됩니다. 즉, new 연산자를 통한 객체 생성으로 인해 힙에 "foo"가 생성되고 s3가이를 참조합니다.
String s4=new String("foo");
s3와 동일
그래서 System.out.println(s1==s2);// **true** due to literal comparison.
과 System.out.println(s3==s4);// **false** due to object
비교 (s3 및 s4는 힙의 다른 위치에 생성됨)
String
s는 Java에서 특별 String
합니다. 불변이며 문자열 상수는 자동으로 객체 로 변환 됩니다.
귀하의 SomeStringClass cis = "value"
예제를 다른 클래스에 적용 할 방법은 없습니다 .
으로 String
선언 되었기 때문에 확장 할 수도 final
없습니다. 이는 하위 클래스가 허용되지 않음을 의미합니다.
Java 문자열은 흥미 롭습니다. 응답이 몇 가지 흥미로운 점을 다룬 것 같습니다. 여기 내 2 센트입니다.
문자열은 변경할 수 없습니다 (변경할 수 없음).
String x = "x";
x = "Y";
- 첫 번째 줄은 문자열 값 "x"를 포함 할 변수 x를 만듭니다. JVM은 문자열 값 풀에서 "x"가 있는지 확인하고, 존재하는 경우 변수 x를 가리키고, 존재하지 않으면 생성 한 다음 할당을 수행합니다.
- 두 번째 줄은 "x"에 대한 참조를 제거하고 "Y"가 문자열 값 풀에 있는지 확인합니다. 존재하는 경우 할당하고 그렇지 않은 경우 먼저 할당 한 다음 할당합니다. 문자열 값의 사용 여부에 따라 문자열 값 풀의 메모리 공간이 회수됩니다.
문자열 비교는 비교 대상에 따라 다릅니다.
String a1 = new String("A");
String a2 = new String("A");
a1
같지 않다a2
a1
와a2
객체 참조는- 문자열이 명시 적으로 선언되면 새 인스턴스가 생성되고 해당 참조는 동일하지 않습니다.
대소 문자를 구분하지 않는 클래스를 사용하려는 것이 잘못된 길에 있다고 생각합니다. 현은 그대로 두십시오. 정말로 관심있는 것은 값을 표시하거나 비교하는 방법입니다. 다른 클래스를 사용하여 문자열 형식을 지정하거나 비교합니다.
즉
TextUtility.compare(string 1, string 2)
TextUtility.compareIgnoreCase(string 1, string 2)
TextUtility.camelHump(string 1)
클래스를 구성하고 있으므로 원하는대로 비교를 수행 할 수 있습니다. 텍스트 값을 비교합니다.
당신은 할 수 없습니다. Java에서 큰 따옴표로 묶인 것은 컴파일러에 의해 특별히 문자열로 인식되며, 불행히도이를 재정의 할 수 없습니다 (또는 확장 java.lang.String
-선언되었습니다 final
).
질문에 답하는 가장 좋은 방법은 "문자열 상수 풀"에 익숙해지는 것입니다. 자바에서 문자열 객체는 불변 (즉, 초기화 된 값은 변경할 수 없음)이므로 문자열 객체를 편집 할 때 이전 객체가 특수 메모리에서 떠 다니는 새로운 편집 된 문자열 객체를 생성하게됩니다. 상수 풀 ". 새로운 문자열 객체 생성
String s = "Hello";
풀에 문자열 객체 만 생성하고 참조는이를 참조하지만
String s = new String("Hello");
두 개의 문자열 개체를 만듭니다. 하나는 풀에 있고 다른 하나는 힙에 있습니다. 참조는 힙의 개체를 참조합니다.
-CaseInsensitiveString이 String처럼 동작하도록하려면 어떻게하면 위의 문장이 괜찮을까요 (String 확장 여부에 관계없이)? 리터럴로 전달할 수 있도록하는 것은 String에 대해 무엇입니까? 내 이해에서 Java에는 "복사 생성자"개념이 없습니까?
첫 번째 요점부터 충분하다고 말했습니다. "Polish"는 문자열 리터럴이며 CaseInsentiviveString 클래스에 할당 할 수 없습니다.
이제 두 번째 요점 에 대해
새 리터럴을 만들 수는 없지만 "유사한"접근 방식으로 해당 책의 첫 번째 항목을 따를 수 있으므로 다음 진술이 참입니다.
// Lets test the insensitiveness
CaseInsensitiveString cis5 = CaseInsensitiveString.valueOf("sOmEtHiNg");
CaseInsensitiveString cis6 = CaseInsensitiveString.valueOf("SoMeThInG");
assert cis5 == cis6;
assert cis5.equals(cis6);
여기에 코드가 있습니다.
C:\oreyes\samples\java\insensitive>type CaseInsensitiveString.java
import java.util.Map;
import java.util.HashMap;
public final class CaseInsensitiveString {
private static final Map<String,CaseInsensitiveString> innerPool
= new HashMap<String,CaseInsensitiveString>();
private final String s;
// Effective Java Item 1: Consider providing static factory methods instead of constructors
public static CaseInsensitiveString valueOf( String s ) {
if ( s == null ) {
return null;
}
String value = s.toLowerCase();
if ( !CaseInsensitiveString.innerPool.containsKey( value ) ) {
CaseInsensitiveString.innerPool.put( value , new CaseInsensitiveString( value ) );
}
return CaseInsensitiveString.innerPool.get( value );
}
// Class constructor: This creates a new instance each time it is invoked.
public CaseInsensitiveString(String s){
if (s == null) {
throw new NullPointerException();
}
this.s = s.toLowerCase();
}
public boolean equals( Object other ) {
if ( other instanceof CaseInsensitiveString ) {
CaseInsensitiveString otherInstance = ( CaseInsensitiveString ) other;
return this.s.equals( otherInstance.s );
}
return false;
}
public int hashCode(){
return this.s.hashCode();
}
// "assert"키워드를 사용하여 클래스 테스트
public static void main( String [] args ) {
// Creating two different objects as in new String("Polish") == new String("Polish") is false
CaseInsensitiveString cis1 = new CaseInsensitiveString("Polish");
CaseInsensitiveString cis2 = new CaseInsensitiveString("Polish");
// references cis1 and cis2 points to differents objects.
// so the following is true
assert cis1 != cis2; // Yes they're different
assert cis1.equals(cis2); // Yes they're equals thanks to the equals method
// Now let's try the valueOf idiom
CaseInsensitiveString cis3 = CaseInsensitiveString.valueOf("Polish");
CaseInsensitiveString cis4 = CaseInsensitiveString.valueOf("Polish");
// References cis3 and cis4 points to same object.
// so the following is true
assert cis3 == cis4; // Yes they point to the same object
assert cis3.equals(cis4); // and still equals.
// Lets test the insensitiveness
CaseInsensitiveString cis5 = CaseInsensitiveString.valueOf("sOmEtHiNg");
CaseInsensitiveString cis6 = CaseInsensitiveString.valueOf("SoMeThInG");
assert cis5 == cis6;
assert cis5.equals(cis6);
// Futhermore
CaseInsensitiveString cis7 = CaseInsensitiveString.valueOf("SomethinG");
CaseInsensitiveString cis8 = CaseInsensitiveString.valueOf("someThing");
assert cis8 == cis5 && cis7 == cis6;
assert cis7.equals(cis5) && cis6.equals(cis8);
}
}
C:\oreyes\samples\java\insensitive>javac CaseInsensitiveString.java
C:\oreyes\samples\java\insensitive>java -ea CaseInsensitiveString
C:\oreyes\samples\java\insensitive>
즉, CaseInsensitiveString 개체의 내부 풀을 만들고 거기에서 해당 인스턴스를 반환합니다.
This way the "==" operator returns true for two objects references representing the same value.
This is useful when similar objects are used very frequently and creating cost is expensive.
The string class documentation states that the class uses an internal pool
The class is not complete, some interesting issues arises when we try to walk the contents of the object at implementing the CharSequence interface, but this code is good enough to show how that item in the Book could be applied.
It is important to notice that by using the internalPool object, the references are not released and thus not garbage collectible, and that may become an issue if a lot of objects are created.
It works for the String class because it is used intensively and the pool is constituted of "interned" object only.
It works well for the Boolean class too, because there are only two possible values.
And finally that's also the reason why valueOf(int) in class Integer is limited to -128 to 127 int values.
In your first example, you are creating a String, "silly" and then passing it as a parameter to another String's copy constructor, which makes a second String which is identical to the first. Since Java Strings are immutable (something that frequently stings people who are used to C strings), this is a needless waste of resources. You should instead use the second example because it skips several needless steps.
However, the String literal is not a CaseInsensitiveString so there you cannot do what you want in your last example. Furthermore, there is no way to overload a casting operator like you can in C++ so there is literally no way to do what you want. You must instead pass it in as a parameter to your class's constructor. Of course, I'd probably just use String.toLowerCase() and be done with it.
Also, your CaseInsensitiveString should implement the CharSequence interface as well as probably the Serializable and Comparable interfaces. Of course, if you implement Comparable, you should override equals() and hashCode() as well.
Just because you have the word String
in your class, does not mean you get all the special features of the built-in String
class.
CaseInsensitiveString
is not a String
although it contains a String
. A String
literal e.g "example" can be only assigned to a String
.
CaseInsensitiveString and String are different objects. You can't do:
CaseInsensitiveString cis = "Polish";
because "Polish" is a String, not a CaseInsensitiveString. If String extended CaseInsensitiveString String then you'd be OK, but obviously it doesn't.
And don't worry about the construction here, you won't be making unecessary objects. If you look at the code of the constructor, all it's doing is storing a reference to the string you passed in. Nothing extra is being created.
In the String s = new String("foobar") case it's doing something different. You are first creating the literal string "foobar", then creating a copy of it by constructing a new string out of it. There's no need to create that copy.
when they say to write
String s = "Silly";
instead of
String s = new String("Silly");
they mean it when creating a String object because both of the above statements create a String object but the new String() version creates two String objects: one in heap and the other in string constant pool. Hence using more memory.
But when you write
CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
you are not creating a String instead you are creating an object of class CaseInsensitiveString. Hence you need to use the new operator.
If I understood it correctly, your question means why we cannot create an object by directly assigning it a value, lets not restrict it to a Wrapper of String class in java.
To answer that I would just say, purely Object Oriented Programming languages have some constructs and it says, that all the literals when written alone can be directly transformed into an object of the given type.
That precisely means, if the interpreter sees 3 it will be converted into an Integer object because integer is the type defined for such literals.
If the interpreter sees any thing in single quotes like 'a' it will directly create an object of type character, you do not need to specify it as the language defines the default object of type character for it.
Similarly if the interpreter sees something in "" it will be considered as an object of its default type i.e. string. This is some native code working in the background.
Thanks to MIT video lecture course 6.00 where I got the hint for this answer.
In Java the syntax "text" creates an instance of class java.lang.String. The assignment:
String foo = "text";
is a simple assignment, with no copy constructor necessary.
MyString bar = "text";
Is illegal whatever you do because the MyString class isn't either java.lang.String or a superclass of java.lang.String.
First, you can't make a class that extends from String, because String is a final class. And java manage Strings differently from other classes so only with String you can do
String s = "Polish";
But whit your class you have to invoke the constructor. So, that code is fine.
I would just add that Java has Copy constructors...
Well, that's an ordinary constructor with an object of same type as argument.
In most versions of the JDK the two versions will be the same:
String s = new String("silly");
String s = "No longer silly";
Because strings are immutable the compiler maintains a list of string constants and if you try to make a new one will first check to see if the string is already defined. If it is then a reference to the existing immutable string is returned.
To clarify - when you say "String s = " you are defining a new variable which takes up space on the stack - then whether you say "No longer silly" or new String("silly") exactly the same thing happens - a new constant string is compiled into your application and the reference points to that.
I dont see the distinction here. However for your own class, which is not immutable, this behaviour is irrelevant and you must call your constructor.
UPDATE: I was wrong! Based on a down vote and comment attached I tested this and realise that my understanding is wrong - new String("Silly") does indeed create a new string rather than reuse the existing one. I am unclear why this would be (what is the benefit?) but code speaks louder than words!
String is one of the special classes in which you can create them without the new Sring part
it's the same as
int x = y;
or
char c;
It is a basic law that Strings in java are immutable and case sensitive.
String str1 = "foo";
String str2 = "foo";
Both str1 and str2 belongs to tha same String object, "foo", b'coz Java manages Strings in StringPool, so if a new variable refers to the same String, it doesn't create another one rather assign the same alerady present in StringPool.
String str1 = new String("foo");
String str2 = new String("foo");
Here both str1 and str2 belongs to different Objects, b'coz new String() forcefully create a new String Object.
Java creates a String object for each string literal you use in your code. Any time ""
is used, it is the same as calling new String()
.
Strings are complex data that just "act" like primitive data. String literals are actually objects even though we pretend they're primitive literals, like 6, 6.0, 'c',
etc. So the String "literal" "text"
returns a new String object with value char[] value = {'t','e','x','t}
. Therefore, calling
new String("text");
is actually akin to calling
new String(new String(new char[]{'t','e','x','t'}));
Hopefully from here, you can see why your textbook considers this redundant.
For reference, here is the implementation of String: http://www.docjar.com/html/api/java/lang/String.java.html
It's a fun read and might inspire some insight. It's also great for beginners to read and try to understand, as the code demonstrates very professional and convention-compliant code.
Another good reference is the Java tutorial on Strings: http://docs.oracle.com/javase/tutorial/java/data/strings.html
참고URL : https://stackoverflow.com/questions/334518/java-strings-string-s-new-stringsilly
'development' 카테고리의 다른 글
JPA를 사용하여 인덱스 (비 고유 키) 지정 (0) | 2020.09.17 |
---|---|
터미널에서 내 Git 사용자 이름을 변경하는 방법은 무엇입니까? (0) | 2020.09.17 |
.NET의 문자열에서 큰 따옴표 제거 (0) | 2020.09.17 |
문장에서 파이썬 분할 텍스트 (0) | 2020.09.17 |
작성기를 통해 laravel 설치 프로그램을 설치할 수 없습니다. (0) | 2020.09.17 |