I have an assert statement to check the equal method in a class. below is the 2 statements
Assert.assertTrue(a.equals(new VideoObj(title, year, director)));
Assert.assertTrue(a.equals(new VideoObj(new String(title), year, director)));
what is the difference in the two statements? and why does the 2nd assert statement have new String(title), can someone tell me what is the difference in doing so?
And also could you provide with a tutorial for me to learn writing test class for Java?
thanks
new String() explicitly creates a new object of String.
And:
Assert.assertTrue(a.equals(new VideoObj(title, year, director)));
reuses existing String object (which can give you different results depending on equals method implementation in VideoObj), or uses some other object like byte[] as there is a constructor for new String(byte[]). Of course there are many others (see Java API).
...edit
Check this out:
String s1=new String("abcxyz");
String s2=new String("abc"+"xyz");
String s3=s1+s2;
String s4="abcxyz"; // string literal will go to string pool
String s5="abc"+"xyz"; // string literal will go to string pool
System.out.println(s1==s2);
System.out.println(s2==s3);
System.out.println(s3==s4);
System.out.println(s4==s5); // TRUE (the rest are false)
System.out.println(s2==s4);
System.out.println(s2==s5);
System.out.println(s3==s1);
System.out.println(s3==s5);
The new String() statement creates a new String object with the content of the original String. That gives you two String objects (the original one and the one that was newly created with the new String(originalString) statement) that have equal content, but are two different Java objects. If you compare these two objects with the == operator, this comparison will return false, because it's two different objects. Whereas a comparison with the String's equals() method will still return true, because these two strings have the same text stored inside them.
So I assume the intention of this assertion in the test is to make sure that the equals() method of "a" really uses the equals() method of the title string to check for equality, and does not just do a simple == comparison of the two title strings. Without that assertion, such an invalid implementation of a's equals() method could remain unnoticed because the two title strings in the compared object could be references to the same String object, which would then also give you the expected result when using the (wrong) == operator to test them for equality.
The difference is this:
If in VideoObj's the equals() method has been overridden and is using the String that is passed in via the constructor as title, it's checking to make sure it works if the String isn't a literal
If in equals() someone did this:
...
if (otherObj.getTitle() == this.title) {
...
The first assertion would succeed while the second would fail if title was a string literal. String literals in Java are interned into a pool meaning that you end up with multiple references to the same literal if it's used multiple times;
String a = "This is a string";
String b = "This is a string";
// a and b will both be the same reference
String c = new String("This is a string");
// c will *not* be the same reference
Edit: Note this is assuming that title in your first assertion is indeed a String
If title is not a String, then the second assert statement might be invoking a different VideoObj constructor. Without more info about title and about the VideoObj class, it's hard to say more.
Do a web search for junit tutorial to get lots of resources for learning how to write test classes.
EDIT From your comment to the answer by #BrianRoach, I gather that your VideoObj.equals(Object) method is implemented as follows:
public boolean equals(Object thatObject) {
if (!(thatObject instanceof VideoObj)) return false;
VideoObj that = (VideoObj) thatObject;
return ((_title.equals(that.title()))
|| (_director.equals(that.director()))
|| (_year == that.year()));
}
If that's right, then the problem is that your return statement should be using && instead of || operators. That would explain why your asserts are not complaining.
Java does some optimization. If you have two strings with the same value it is most probably the same object. This can be done because strings are immutable. But if you explicitly create a new String with a constructor call, a new object is created.
There should be no difference between the 2 statements, provided that 'title' is a String.
title can either be a String, a StringBuffer, a StringBuilder, a char[] or a byte[]. If it's a String, it'll run the same constructor as the other call, but in all other cases it may run a totally different, overloaded, constructor.
Without seeing the type of title, it's impossible to tell which.
Edit: Since the type is String, the reason for the new String is most likely to make sure that the underlying code does not compare strings using == (reference-equals) by mistake. If it did, the first test may pass (string constants with the same value may indeed reference the same String object and the test may use constants for setup and test) while the second one would break since == would no longer match with a freshly created String.
Related
This question already has answers here:
How do I compare strings in Java?
(23 answers)
Compare two objects with .equals() and == operator
(16 answers)
Closed 7 years ago.
I looked it up in a book, which is usually more thorough in terms of explanations than a website.
Take this for ex.:
if (nickname == "Bob")
The condition will be true only if nickname is referring to the same String object.
Here is a sentence I found confusing, can anyone please explain to why this is the case:
For efficiency, Java makes only one string object for every string constant.
The book points out that the way of assembling the object "Bob" also affects whether the condition will be true of not, which confuses me the most.
For ex.:
String nickname = "Bob";
...
if (nickname == "Bob") //TRUE
But if "Bob" is created from .substring() method, condition will be FALSE.
String name = "Robert";
String nickname = name.substring(0,3);
...
if (nickname == "Rob")//FALSE
Why is this so?
Edit: in the end of the book's explanation, I found a sentence which also confuses me a lot:
Because string objects are always constructed by the compiler, you never have an interest in whether two strings objects are shared.
Doesn't everything we write get constructed by the compiler?
You need to understand 2 things
1)
String a = "Bob";
String b = "Bob";
System.out.println(a.equals(b));
System.out.println(a == b);
How do you think? What the output?
true
true
What doing this? First string created in string pool in permanent generation memory. Second string get existing object from pool.
String a = "Bob"; // create object in string pool(perm-gen)
String b = "Bob"; // getting existing object.
How right you noticed :
For efficiency, Java makes only one string object for every string constant.
2)
String nickname = name.substring(0,3);
As String is immutable object name.substring(0,3); created new String("Rob") in heap memory, not in perm-gen.
Note :
In Java 8 String pool is created in PermGen area of Heap, garbage collection can occur in perm space but depends upon JVM to JVM. By the way from JDK 1.7 update, String pool is moved to heap area where objects are created.
Read more here.
String literals are internally handled by the JVM so that for every unique String literal, it always refers to the same object if it has the same value. For example, a string literal "test" in class A will be the exact same object as a string literal "test" in class B.
Doesn't everything we write get constructed by the compiler?
The compiler simply adds a the string literal to the classes constant pool upon compilation and loads it with a special instruction called LDC, the rest is handled by the JVM, which loads the string constant from a special string constant pool that never removes / garbage-collects any objects (previously permgen).
However, you can get the 'internal' version of any string (as if it was a string literal) using String#internal(), which would cause the == operator to work again.
It's about objects.
Since these aren't primitives == doesn't compare what they are. == compares where they are (in heap memory).
.equals() should (if implemented) compare what's contained in that memory.
This is a detail that is easily forgotten because small strings and boxed numbers often don't get new memory when created because it's more optimal to instead point you to cached version of the same thing. Thus you can ask for a new "Bob" over and over and just get handed a reference (memory address) to the same "Bob". This tempts us to compare them like primitives since that seems to work the same way. But not every object will have this happen to it so it's a bad habit to let yourself develop.
This trick works only when 1) a matching object already exists, 2) it's immutable so you can't surprise users of other "copies" by changing it.
To abuse an old metaphor, if two people have the same address it's a safe bet that they keep the same things at home, since it's the same home. However, just because two people have different addresses doesn't mean they don't keep exactly the same things at home.
Implementing .equals() is all about defining what we care about when comparing what is kept in these objects.
So only trust == to compare values of primitives. Use .equals() to ask an object what it think's it's equal to.
Also, this isn't just a java issue. Every object oriented language that lets you directly handle primitives and object references/pointers/memory address will force you to deal with them differently because a reference to an object is not the object it self.
The objects value is not the same as it's identity. If it was there would only ever be one copy of an object with the same contents. Since the language can't perfectly make that happen you're stuck having to deal with these two concepts differently.
If I write this code :
String s = new String("TestString");
I understand how s refers to a string created dynamically. s is not an object in itself, but refers to one.
But I am not able to figure out what this means :
String s = "TestString";
Q1. If it would have been some primitive data type I would understand, but what does this signify for a class type ?
Q2. Is this kind of initialization allowed for user created classes as well ?
Java Level : Beginner
Q1. If it would have been some primitive data type I would understand, but what does this signify for a class type ?
In this case, "TestString" is a string literal. A string literal also serves as a reference to an instance of String. This is per the language specification, §3.10.5. So, in your particular case "TestString" is a reference to an instance of String, and you are assigning that same reference to your variable s.
Now, there are some rather special things about Strings that are referred to by literals. Two string literals with the same value (logically, as strings) always refer to the same instance of String. This is due to the "interning" of string literals.
However, when you say
String s = new String("TestString");
it is still the case that "TestString" refers to an instance of String, in fact to an instance in the string intern pool, but it is not the case that s refers to this same string. Instead, s is initialized to have its value equal to "TestString", but it is in fact a new reference. That is:
String s = new String("TestString");
String t = "TestString";
System.out.println(s == t);
This will print false.
Q2. Is this kind of initialization allowed for user created classes as well ?
No.
String s = "TestString";
Is the normal way to create a String. In fact when you do:
String s = new String("TestString");
What you're doing is create a string first, then passing it as an argument to new String(); So the question is not why the first one exists, but why the second one does. The answer is pretty subtle and you probably won't ever care: The first way creates a String literal that doesn't get garbage collected, and is shared on all the VM. The second one, instead, does. This means, for performance reasons, there are cases when you want to use the second form, like when working with very very large strings.
You can read more about it here:
http://kjetilod.blogspot.com.es/2008/09/string-constructor-considered-useless.html
From the Oracle Documentation:
The most direct way to create a string is to write:
String greeting = "Hello world!";
In this case, "Hello world!" is a string literal—a series of
characters in your code that is enclosed in double quotes. Whenever it
encounters a string literal in your code, the compiler creates a
String object with its value—in this case, Hello world!.
As with any other object, you can create String objects by using the
new keyword and a constructor.
Q1. If it would have been some primitive data type I would understand,
but what does this signify for a class type ?
No, this is special case, in case of String literals, String s = "someString" statement means we are referring to someString which is stored in string constant pool. someString will be an instance of String class but will be stored in string literal pool.
The special thing about String literal pool will be.
String s = "someString";
String s1 = "someString";
Here, s == s1' will returntrue` as they will refer to the same object in string literal pool.
String s2 = new String("someString");
String s3 = new String("someString");
Here, s2 == s3 will return false as both string will be created in non-constant pool memory.
You can find a good tutorial regarding strings here
http://www.thejavageek.com/2013/06/19/the-string-constant-pool/
http://www.thejavageek.com/2013/06/17/string-immutability-in-java/
Q2. Is this kind of initialization allowed for user created classes as
well ?
No we can't.
String s1 = new String("string");
String s2 = new String("string");
String s3 = "string";
String s4 = "string";
System.out.println(s1 == s2); //FALSE
System.out.println(s2.equals(s1)); //TRUE
System.out.println(s3 == s4); //TRUE
System.out.println(s3.equals(s4)); //TRUE
What is the difference between creation of s1 and s3 ?
Please let me know
In String we are having only String object then why it treats this two differently.
s1 and s2 are having different memory address while s3 and s4 has same memory address.
why it works based on new operator.?
The String objects that represent string literals in your Java source code are added to a shared String pool when the classes that defines them are loaded1. This ensures that all "copies" of a String literal are actually the same object ... even if the literal appears in multiple classes. That is why s3 == s4 is true.
By contrast, when you new a String, a distinct new String object is created. That is why s1 == s2 is false. (This is a fundamental property of new. It is guaranteed to create and return a new object ... if it completes normally.)
However, in either case, the strings will have the same characters, and that is why equals is returning true.
While it is important to understand what is going on, the real lesson is that the correct way to compare Java strings is to use equals and not ==.
If you want to arrange that your String objects can be tested for equality using ==, you can "intern" them using the String.intern method. However, you have to do this consistently ... and interning is an expensive process in various respects ... so it is generally not a good idea.
1 - Actually, it is a bit more complicated than that. They objects get added to the pool at some time between class loading and first use of the literals. The precise timing is unspecified and JVM implementation dependent. However it is guaranteed to happen just once, and before any application code sees the String object reference corresponding to the literal.
s1 is a new String object that does not belong to a part of any pooled instance. s3 is an instance of a string that comes from a pool. Lookup java String pool. Take a look at the related intern() method on String.
The concept is not unique to java. String interning is supported in other languages. On that related note, pooling frequently used objects follows the flyweight pattern and is not limited to Strings. Take a look at Integer.valueOf(). Integers have a constant pool of their own too.
The JVM has an automatic optimisation. Unless you specifically create a new String object, and another String object already exists with the same value, the JVM automatically assumes that a new object is not a necessity, and will assign you a pointer to the equal String object that already exists.
Essentially, when you use the second option, this is what happens:
Step 1
First Object is created no problem.
Step 2
Before the second object is created, the String pool is checked for a value.
If that value currently exists, then there is no need to create a new object. It just returns the reference to the String object.
Step 3
Instead of being assigned a new Object, it is simply given a reference to the object made in step 1. This is to save memory.
This happens because the new operator forces creation of a new instance of String, while in the second case, as String is an immutable class, the JVM provides you with the same String instance for both variables to save memory. As there is no chance one of such objects will change causing the second one change as well (immutable, remember?) this is OK.
In java String can be created in 2 ways given below
String foo="Test";
String fooobj=new String("Test");
Everywhere it is mentioned about difference between these 2 ways of creating String. I want to know more about What are appropriate scenario's ,
where we should go for
String foo="Test";
And when to go for
String fooobj=new String("Test"); ?
The short answer: If you're in any doubt, you don't want new String("literal here"). If you need it, you'll know you need it, and why.
The long answer:
Essentially the only time you want to use new String("literal here") is if you want to ensure that the resulting string object is not == any other string object. Literals get interned automatically; strings created via new String("literal here") are not.
So why would you want that? The answer is you almost never would, because String instances are immutable, so you don't care if you're sharing a String instance with something else. Just about the only scenario I can imagine is if you had an API that accepted a String and you wanted to have a flag value other than null, and you wanted to check that flag/marker value via ==, like this:
public static final String MARKER = new String("Marker");
public void someFictionalMethod(String arg) {
if (arg == MARKER) {
// Take action on the marker
}
else {
// Take action on the string
}
}
...and even then I'd tend to find it a bit suspect and would explore other ways to do it.
It is never necessary to create a new String object with
String fooobj = new String("Test");
So, you should never do this. Just write String fooobj = "Test"; instead.
Class String is immutable. That means that the content of a String object cannot be changed after it has been constructed. It's never necessary to create an explicit copy of a string literal.
You should never use new String(). Anytime you create string in this way, new object in memory is created. If you write String s = "aaa", then there is a chance such object was already created in a given JVM, it is stored in string pool and thanks to that your variable will be just reference to that existing object - you safe memory in this way.
When you use the second approach, you actually rely on the first approach to initialize the constructor arguments.
So the question is if you could create the String object via first approach, why you spend extra effort to use the second approach ?
I don't see any scenary to use the second constructor style, so always insist in using the first approach.
There is a subtle differences between String object and string literal.
String s = "abc"; // creates one String object and one reference variable
In this simple case, "abc" will go in the pool and s will refer to it.
String s = new String("abc"); // creates two objects,and one reference variable
In this case, because we used the new keyword, Java will create a new String object in normal (non-pool) memory, and s will refer to it. In addition, the literal "abc" will be placed in the pool.
Strings are constant; their values cannot be changed after they are created. String buffers support mutable strings. Because String objects are immutable they can be shared. For example:
String str = "abc";
is equivalent to:
String str = new String("abc");
You should avoid the second way to declare a string, for reasons explained into other answers
I am writing an app for J2ME devices and pretty much care about unnecessary String creation.
As working with Strings is built-in, i.e. it is not necessary to create them explicitly, I am not sure if I understand it right.
For instance returning a String (just by using the double quotes) creates the string when it is being returned, i.e. if I have several return statements returning different Strings, only one of the would be created. Is that right?
Also when using Strings for printing messages with Exceptions, these Strings never get created, if the Exception doesn't get thrown, right?
Sorry to bother you with such a newbie question.
I'm not at all sure about the answers you've received so far. If you're just returning a string literal, e.g.
return "foo";
then those values are embedded into the class file. The JVM makes sure that only one instance of that string is ever created (from the literal) - but I don't think there's any guarantee that it won't create strings for all the constants in a class when the class itself is loaded.
Then again, because the string will only be created once (per string constant) it's unlikely to be an issue.
Now, if your code is actually more like this:
return "foo" + new Date();
then that is dynamically creating a string - but it will only be created if the return statement is actually hit.
The answer is a bit more complicated than some of the other answers suggest.
The String value that corresponds to a String literal in your source code gets created once, when the class is loaded. Furthermore, these Strings are automatically "interned", which means that if the same literal appears at more than one place in any class, only one copy of the String will be kept. (Any other copies, if they were created will get garbage collected.)
When the application calls new String(...), when it evaluates a String concatenation expression (i.e. the + operator), or when it calls one of the many library methods that create Strings under the hood, a new String will be created.
So to answer your questions:
1 - The following will not actually create a String at all. Rather it will return a String that was created when the class was loaded:
return "some string";
2 - The following will create two Strings. First it will call someObject.toString(), then it will concatenate that with the literal to give another String.
return "The answer is :" + someObject;
3 - The following will not create a String; see 1.
throw new Exception("Some message");
4 - The following will create two Strings when it is executed; see 2.
throw new Exception(someObject + "is wrong");
(Actually, 3 and 4 gloss over the fact that creating an exception causes details of the current thread's call stack to be captured, and those details include a method name, class name and file name for each frame. It is not specified when the Strings that represent these things actually get created, or whether they are interned. So it is possible that the act of creating an Exception object triggers creation of a number of Strings.)
Right
Right
Yes. If an expression that creates an instance either by invoking a constructor or if (for Strings) evaluating a literal is not executed, then nothing is created.
And furtheron, compilers do some optimization. String objects based on String literals will be created only once and interned afterwards. like here:
public String getHello() {
return "Hello";
}
public void test() {
String s = getHello(); // String object created
String t = getHello(); // no new String object created
}
The JVMS has a different 'opinion':
A new class instance may be implicitly created in the following situations:
Loading of a class or interface that contains a String literal may create a new String object (§2.4.8) to represent that literal. This may not occur if the a String object has already been created to represent a previous occurrence of that literal, or if the String.intern method has been invoked on a String object representing the same string as the literal.
So the above example is incorrect (I'm learning something new every day). The VM checks during classloading if "Hello" has to be created or not (and will create a String instance if not existing yet).
So now it is my understanding, that the VM creates a String instance for each unique String literal (on byte code level!), regardless whether it is used or not.
(on byte code level because compilers may optimize concatenations of String literals to one literal, like: the expression "one"+"two" will be compiled to "onetwo")
Strings (and other objects) only get created when you call them.
So to answer your questions:
Yes, only the String that gets returned will get created
Yes, only when the exception is thrown, this String will get created
The main concept here is that the heap allocation(what you say creation) for any String or in more general terms for any object doesn't take place until your logic-flow makes the interpreter executes that line of compiled code.