Link to home
Start Free TrialLog in
Avatar of bharat_khillari
bharat_khillari

asked on

Java Objects

How many objects following snippets will create:

String a = "abc":
String b = "abc":
String c = new String("abc"):
String d = c;
Avatar of krakatoa
krakatoa
Flag of United Kingdom of Great Britain and Northern Ireland image

5 looks like.
3 String objects
Avatar of Webstorm
Webstorm

3 String instances and 4 String pointers (c & d are pointers to the same instance).
Vector v = new Vector();

String a = "abc";
String b = "abc";
String c = new String("abc");
String d = c;


v.add(a);
v.add(b);
v.add(c);
v.add(d);

System.out.println("Size of Vector v = "+v.size());
In fact, there may be 1 String instance because java build a string constant pool, string are immutable, so a,b,c,d may point to the same string instance.
bharat_khillari -

You need to ask yourself why you need to know this; is it the programming or 'technical' level. If it's the latter, then webstorm is right. But on the app. level you are working with 4 objects but have 5.
You will have 2 instanes of String.  When you do the call to
String c = new String("abc");
This creates an explicit copy of the passed in String.  Here's a test for you to prove it (it's mentioned in the API docs):

        String a = "abc";
        String b = "abc";
        String c = new String("abc");
        String d = c;
   
        System.err.println(a == b);
        System.err.println(a == c);
        System.err.println(a == d);
        System.err.println(b == c);
        System.err.println(b == d);
        System.err.println(c == d);
Quick explanation:
a == b
will only return true if it is the same instance of the object, where a.equals(b) will return true if it is the same instance, OR the values match.
It's a bit of a tautology what you wrote. The results are : true,false, false, false, false, true, but how does that tell you how many objects there are?

And the point is that they are not the same instances, but point to one value.
Because it proves that a and b are the same instance, and c and d are the same instance, therefore, 2 instances are created.
> And the point is that they are not the same instances

then why would it return true???
Because they point to the same reference, but they are not the same instances. How can they be - they have different names? ;)

Were they to be the same instances, then the test would be a bit pointless, since it would be tantamount to asking  : if(a == a).
A name isn't an instance, a name is a pointer.

So going by that are you saying that x in the following would be a different instance to v?

        Vector v = new Vector();
        Vector x = v;
       
        v.add("Hello from v");
       
        System.err.println(v.get(0));
        System.err.println(x.get(0));
Well, I once wrote a similar extract for a document.... lemme just paste it here. Might be helpful.

As for the above code:

>> String a = "abc":
>> String b = "abc":
>> String c = new String("abc"):
>> String d = c;

It will create 4 references but only 2 objects, as far as I can tell. 'a' and 'b' will be references to the same String object "abc" allocated in the String pool, and 'c', 'd' will refer to the other "abc" allocated using the new operator ( -> this might have been said before, sorry I didn't go through all the comments).

Here goes the extract:

.... String Pool in Java:

.... There are plenty of questions regarding memory allocation. Well, there is a lot of difference in between memory allocation in C++ and in Java. Let’s consider the following question:
 
String a = “Hello” ;
String b = “Hello” ;
 
if ( a.equals ( b ) )
  System.out.println ( “Equal. ” ) ; // end if
else
  System.out.println ( “Not equal. ” ) ; // end else
 
if ( a == b )
  System.out.println ( “Same. ” ) ; // end if
else
  System.out.println ( “Not same. ” ) ; // end else

One might expect to see:
 
Equal.
Not same.
 
But it prints:
 
Equal.
Same.
 
Here, the concept of String-pool in Java comes into play. Its got to do with Java’s memory-optimization techniques. Objects are always allocated dynamically in Java, using the ‘new’ operator (unlike in C++, where declaring an object like:
 
Classname objectName ;
 
- allocates memory for the object too). In Java, this does not happen. Writing the above statement in Java simply declares that ‘objectName’ is a reference to an object of the type ‘Classname’ and that it can refer to any instance of ‘Classname’. But no memory has yet been allocated for it yet. If we print it using:
 
System.out.println ( objectName ) ;

- the JVM will use the class Object’s toString () method to print:
 
null
 
But when we allocate memory using ‘new’, like in:
 
objectName = new Classname () ; // …. (1)
 
- then only is memory allocated somewhere in the heap, and ‘objectName’ becomes a reference to this newly allocated memory location.

If we write:
 
Classname anotherObject = objectName ;
objectName = null ;
 
- then, ‘objectName’ is null, but ‘anotherObject’ is still a reference to the initially allocated memory in (1). And it can be used to refer to that object.  The ‘objectName’ can still be made as a reference to another object using:
 
objectName = new Classname () ; // …. (2)
 
Now, we have 2 (allocated) objects of this class, one referred to by ‘anotherObject’ (which was allocated in (1) and initially, ‘objectName’ was a reference to this), and the other referred to by ‘objectName’ (allocated in (2)). Assigning ‘objectName = <something>’ does not change that memory location but unhooks ‘objectName’ from the previous memory location where it was referring to, and hooks it to the memory location of <something>. Unhooking ‘objectName’ from the first memory location does not affect the contents of that location. And if there are no other reference variables referring to it, then it will be automatically de-allocated. This is how Java also overcomes the problem of destructors – it has automatic garbage-collection.
 
So much for dynamic memory allocation. Coming back to the String question. So, it can be made out that memory is always allocated explicitly for objects in Java when you use the ‘new’ operator (though it is not the case in case of primitives like ‘int’, ‘byte’, etc.). However, the only exception to this, where memory is allocated implicitly without specifying a ‘new’ operator is in the case of String constants. When we write:
 
String a = “Hello. ” ;
 
Please note that we are not specifying:
 
String a = new String ( “Hello. ” ) ;
 
There is a difference between the two, of course. In the first case, the memory is allocated implicitly from the String-pool, because Java converts string constants like “Hello. ” to ‘String’ objects. And that is what it does here, while putting ‘a’ as a reference to that object. But in order to optimize the memory allocated, if it sees:
 
String b = “Hello. ” ;
 
- after the first line, it puts ‘b’ as a reference to the same memory location, because here, the user is not explicitly allocating memory for a new object using the ‘new’ operator. Java optimizes memory usage this way. The allocation is implicit, and the JVM optimizes the allocation by using the already allocated memory where ‘a’ is referring. Please note that this is *not* a disadvantage, because changing ‘a’ will not change ‘b’ or vice-versa, like we’ve seen in the ‘objectName’ and ‘anotherObject’ example above. Hereafter, if we assign:
 
b = “Hi. ” ;
 
Then, ‘b’ becomes a reference to this newly allocated memory for “Hi. ”, and ‘a’ still refers to the “Hello. ” allocated initially. It is *not* that “Hi. ” over-writes the “Hello. ” at the same location which is being referred to by ‘b’ (and by ‘a’ too), unlike it is in C++. References will be changed on subsequent assignments, not the initially allocated object. Hence, this is not a disadvantage, but just to be safe, if we want to allocate two different locations initially, then the correct approaches are:
 
String a = “Hello. ” ;
String b = new String ( “Hello. ” ) ;

Or:
 
String b = “Hello. ” ;
String a = new String ( “Hello. ” ) ;
 
Or:
 
String a = new String ( “Hello. ” ) ;
String b = new String ( “Hello. ” ) ;
 
But more the number of new instantiations, more the performance is affected. I would still suggest that people should use StringBuffers as much as possible because the String class is immutable.
>> A name isn't an instance, a name is a pointer.


then why did you say it was?
grim_toaster's answer seems to be correct to me....
>> In fact, there may be 1 String instance because java build a string constant pool, string are immutable,
>> so a,b,c,d may point to the same string instance.

No. 'a' and 'b' will be pointing to the same one, and 'c', 'd' to the other one (because this one is specifically allocated to a different memory location using the new operator - it is not allocated from the normal String pool).
mayankeagle:

Points taken and well expounded. However, given that Java housekeeps all that for us behind the scenes for want of a better expression, at 'programming' level, would it not make more sense to simply say there are four String objects here, (abcd), and one (new String("abc")) which is just using up resources for no reason (just providing an argument to the instantiated String).

How else can you explain that you can store abc and d in a vector if they are not String objects? I never saw anywhere in the docs acknowledgement of it being possible to store a 'reference' in a Vector? ;)
Well, I didn't want to go into discussion beyond the scope of this question ;-)

Like I said - Java handles it in such a way that you need not actually worry about whether 2 objects are allocated in memory, or 4. But I thought that is what the question aims to capture - so the exact answer would be 3, not 4.

Personally, while working, I don't prefer to use new String ( "abc" ) everytime because I know that if I use just "abc", then Java will handle it for me.... and I would also be saving more 'new' instantiations.

In a Vector, well.... even the Vector 'actually' stores just references to the objects. Here is another extract from the same document which  I wrote ;-)

Reference problem with no new instantiations:

This is another problem which arises when there is confusion regarding memory-allocation and references in Java. Let’s take the example of a Vector:
 
class MyClass
{
  private int iIntVal ;
  private float fFloatVal ;
 
  public int getIntVal ()
  {
    return iIntVal ;
 
  } // end of getIntVal ()
 
  public void setIntVal ( int iIntVal )
  {
    this.iIntVal = iIntVal ;
 
  } // end of setIntVal ()
 
  public float getFloatVal ()
  {
    return fFloatVal ;
 
  } // end of getFloatVal ()
   
  public void setFloatVal ( float fFloatVal )
  {
    this. fFloatVal = fFloatVal ;
 
  } // end of setFloatVal ()
 
} // class definition over
 
Let’s say that we have a loop where we are making objects of this class and adding them to a Vector, like:
 
java.util.Vector vList = new java.util.Vector () ; // make a new Vector
MyClass object = new MyClass () ; // make a new object
int iValue = 0 ;
 
while ( iValue < 10 )
{
  object.setIntVal ( iValue ++ ) ; // store 0, 1, 2, …., 9, one by one
  object.setFloatVal ( 3.14159F ) ; // store 3.14159F each time
  vList.add ( object ) ; // add the object to the Vector
 
} // end while
 
If we happen to print the values of the objects in this Vector, like:
 
for ( int iCount = 0, iSize = vList.size () ; iCount < iSize ; iCount ++ )
{
  object = ( MyClass ) vList.get ( iCount ) ;
  System.out.println ( “Int Value = ” + object.getIntVal () + “, Float Value = ” +
      object.getFloatVal () ) ;
 
} // end for
We would get the output:
 
Int Value = 9, Float Value = 3.14159
Int Value = 9, Float Value = 3.14159
Int Value = 9, Float Value = 3.14159
Int Value = 9, Float Value = 3.14159
…. (10 times)
So where did the values which we stored in the loop disappear? We wrote: object.setIntVal ( iValue ++ ) ; where ‘iValue’ started from 0, so why aren’t we getting the values from 0 to 8 for the ‘Int Value’? It happens because we are not instantiating a new object every time. The same object gets its ‘iIntVal’ and ‘fFloatVal’ replaced in the loop by the setIntVal () and setFloatVal () methods and a reference to it gets added to the Vector. Effectively, the Vector holds 10 references to the same object. So, outside the while loop, all of them are referring to ‘object’, the object which now stores 9 and 3.14159F in its ‘iIntVal’ and ‘fFloatVal’. Changes in these values will be reflected throughout, because the all the references in the Vector refer to this object only.

So the correct way of doing it is to instantiate a new object everytime we add it to the Vector:
 
java.util.Vector vList = new java.util.Vector () ; // make a new Vector
MyClass object = null ; // MyClass object = new MyClass () ; ******** this line will go inside the loop
int iValue = 0 ;
 
while ( iValue < 10 )
{
  object = new MyClass () ; // make a new object
  object.setIntVal ( iValue ++ ) ; // store 0, 1, 2, …., 9, one by one
  object.setFloatVal ( 3.14159F ) ; // store 3.14159F each time
  vList.add ( object ) ; // add the object to the Vector
 
} // end while
 
And now, our ‘for’ loop will print:
 
Int Value = 0, Float Value = 3.14159
Int Value = 1, Float Value = 3.14159
Int Value = 2, Float Value = 3.14159
Int Value = 3, Float Value = 3.14159
Int Value = 4, Float Value = 3.14159
Int Value = 5, Float Value = 3.14159
Int Value = 6, Float Value = 3.14159
Int Value = 7, Float Value = 3.14159
Int Value = 8, Float Value = 3.14159
Int Value = 9, Float Value = 3.14159
 
Now before I post the entire document ;-) , I guess this question is worth PAQing, bharat_khillari :-)
>> so the exact answer would be 3, not 4.

Sorry: so the exact answer would be 2, not 4.
Given that Java will destroy objects that aren't being pointed to by anything, I suppose the acid test would be to see, somehow and dont ask me now how, whether after 2 of the alleged 4 Strings were nullified, how many the JVM thought it was looking at? ;)
I'd agree though that for 50 $, this Q's given quite a ride for its money. ;)
As for Strings being immutable .....

String a = "abc";
String b = "abc";
String c = new String("abc");
String d = c;

a="Adams";
b="Bush";
c= new String("Coolidge");
d=c;

System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
But I know what you mean. ;)
Yeah, references are not immutable, the String objects are. a, b, c, d are not immutable. The "abc" is. Anyways ;-)
Ya. The trouble with Strings is in fact that they are androgenous entities - neither pure objects, nor primitives. If they were objects, then, for eg, a concatenation routine would need to call a method, whereas you can do this simply by saying : a = a+"Bush"; But hey.;)
> The trouble with Strings is in fact that they are androgenous entities - neither pure objects, nor primitives.

thar *are* pure objects.
>> thar *are* pure objects ..

er, no, - they're most definitely **not**.
Well how can anyone argue with that logic :-D
>> Well how can anyone argue with that logic :-D ...

If I knew what you were talking about, I might be able to answer that. :))
>> a = a+"Bush";
In fact, when javac compile a String contatenation, it use StringBuffer object and call the append method, and finally convert it back to String object.
>> In fact, when javac compile a String contatenation, it use StringBuffer ...

where did you come by that piece of info., Webstorm?
> where did you come by that piece of info., Webstorm?

Please tell us how 'you' think String concatenation is achieved.
>> Please tell us how 'you' think String concatenation is achieved. ...

Let's hear from Webstorm first, shall we, then perhaps you'd care to enlarge on your assertion that Strings are pure Objects; then we can deal with this.
> Let's hear from Webstorm first

we already have.

> then perhaps you'd care to enlarge on your assertion that Strings are pure Objects

you're the one saying they are not.
This is a childish exchange, cluttering up the airwaves. I already made my points and I am not 'in the dock' here, so let me make it crsytal for you:

* Strings are not pure objects;
* Webstorm can speak for himself; on what, Webstorm, do you base your assertion that Strings are concatenated in the way you described in your last.
> * Strings are not pure objects;

Then what are they? Back up your claims.
>>You will have 2 instanes of String

Correct (but not the spelling ;-))
People who live in glasshouses shouldn't thrown stones; it was *you* who was the first to make the most unsubstantiated flame-inducing ouverture to this nonsense, when you said (sic) : "thar *are* pure objects."

What do *YOU* mean by that.

But, as usual, you ahve not read the full expanse of the present thread anyway, because I already *did* explain how a thread would need to behave vis-s-vis concatenation if it were exclusively an object, in my comment above starting "Ya. The trouble ... "

Read that if you want to know what I think. I am not here to answer your questions, but to comment on that of the Asker, and I shall limit myself to doing that if you dont mind.
public final class String
extends Object
>> extends Object  ...

so ? I didnt say it was *not* an object; I said it was not a pure object. It has qualities that, if it were a pure object, it would not be able to implement, such as concatenation of a+"Bush"+"Baby";// where a was previously "Dont Beat About The".

IF a String were purely and simply an object, then it would need to not only make repeated method calls to perform that concatenation above, but it would furthermore *not* be permissible to to do the concatenation in any other way.

If you have int x, and you want to add it to int y, you can say for eg int z = x+y;

A String is the same in this respect, and is not, repeat not, 'simply' an Object, but carries some 'primitive' attributes. This is what makes it such a crossbreed.

By the way - this is not some figment of my own flight of fancy on the subject - it is in the literature and recognised that a String has these mixed (up) features.
Seeing as Webstorm does not want to substantiate his earlier claim, I'll say this: a+"Bush" does not happen via a StringBuffer or anything of the kind. Java takes the value at a, adds the new String "Bush" to it, and concatenates the references.
> Java takes the value at a, adds the new String "Bush" to it, and concatenates the references.

That'd be done by your 'magic' object type I assume :)
Ints and other primitives can be operated on without moving their references, because they are fixed length entities, so int p++; can stay where it is. But you cant do that with Strings, because (up to a cetain limit) you dont know how long the next concatentation will be. So there has to be an optimised way of making the concatenated String longer without wasting memory space all the time, so that is why it's done like that.

As for what you mean by my 'magic object type', to be honest you are on the edge of making this yet another instance of having to ask a Moderator to come take a look, because you are pushing this way out of the arena of a professional conversation. Why dont you just stick to the development of the discussion, instead of making inflammatory remarks?? WOuld you perhaps be in a position to answer *that* question at least???
I am simply pointing out for the benefit of others reading this question in the future that your understanding is incorrect. As it is not related to the question this is not the place to discuss further.
You haven't pointed out anything, and what you have said is wrong. Sorry. That is probable going to benefit others more I would think.
If you have String s = "Sugar" and String t = "Tea" you have memory allocated for Sugar and Tea. If you then say String  u = s+t, a third area of memory will hold two concatenated references to a and t (that's partly why string operations are slow, because they have to keep pasting bits of RAM together).
 
(The use of a StringBuffer is precisley to avoid this allocation nightmare.)
Please stop posting off-topic comments to this thread. This is not an open discussion forum, it is for answering specific questions.

Well, plenty of action already happened last night ;-)

bharat_khillari, I think its high time you accepted an answer or split points, otherwise people might end up discussing the whole of Java here :-)

As for saying that String is an object or not, I did not wish to discuss any further because I have already mentioned in one of my previous posts that this Q is going beyond topic (not to mention that I am definitely enjoying discussing over it with all of you).

It might be different in other languages, but well, in Java, String is definitely an object. It might be that the JVM treats it in a special way.... you don't always need a 'new' to allocate memory for it (unlike other objects), concatenation is slightly trivial, etc. But well, in Java, that is the way that strings are implemented - as an object, with methods.

Let's not mix it up with the strings in other languages.

Cheers.
>> Correct (but not the spelling ;-))
I was hopeing no-one would notice! ;)

I'm quite amazed at how this thread's come along now though!  Anyway, I'm gonna stick my oar in now (again)...

>>I'll say this: a+"Bush" does not happen via a StringBuffer or anything of the kind
Look at the byte code generated, if you're after examples, open another thread.  I am not continuing here.  Perhaps a thread in the lounge if people want to start being aggressive ;-)
I dont think the discussion is "off-topic" - it's been at the heart of what this is all about. As fro aggression and the lounge, what's the problem really here, I mean let's *not* be oversensitive under mild criticism. I suggest that charity begins at home, and that folks like objects should not, as I already said, chuck their weight around.

Strings a crossbreeds - it's important to know that. Concatenation procedures are anything but trivial issues, and it is a published fact in the literature that they are not pure objects. Let's leave it at that and second what mayank has said that this question needs closing.
wilco :(.
bharat_khillari,

If you check the output of the code which grim had posted:

>> System.out.println ( a == b ) ;
>> etc

you will realize that there are not 3 but 2 objects instantiated.

Mayank.
Avatar of bharat_khillari

ASKER

Hi mayankeagle,

You try printing the value of d after making c = null. It's prints value "abc"

String a = "abc":
String b = "abc":
String c = new String("abc"):
String d = c;

System.out.println(c);
System.out.println(d);

Bharat
Bharat,

If you had read my first comment, you will know that I have already told that before.

The initial question was:

>> String a = "abc":
>> String b = "abc":
>> String c = new String("abc"):
>> String d = c;

If you print:

System.out.println ( a == b ) ; // TRUE
System.out.println ( c == d ) ; // TRUE
System.out.println ( a == c ) ; // FALSE

The above 3 lines form the minimal set of statements required to prove that there are only 2 objects instantiated.

As for making 'c' null, yes -> 'a' and 'b' are referring to the same object. And 'c' and 'd' are referring to another object (both to the same one). Which means - 2  objects are instantiated.

Now you make 'c' null. So 'c' refers to null, and 'd' continues to refer to the same old object it was referring to. Where did the third object come from?

You're probably expecting c = null ; to make 'd' also refer to null. But that is not the way that it is in Java. I would again recommend that you read my first comment. Its long, but it will tell you how it is handled in Java. As for this case, there is no third object instantiated in the above line of code.

Mayank.
The correct answer has been provided by grim_toaster, and the complete explanation by mayankeagle.
Sorry, AnnieMod, I was answering to Bharat_khillari. I guess he was expecting it to behave the way it is in C++, but got surprised with what happens in Java. However, his realization and understanding of the concept does not seem to be correct.

We will wait till he responds.

Cheers.

mayankeagle,

I have already gone through your comments. Please can you explain me - When I make c = null and after printing the value of d it's prints "abc". Now you tell me that c is null and you are saying that d will continue to refer the old c. Her thing is that if c is only one for the piece of code then how can after making c null it will continue to refer old c. I mean where it will be??

You mean to say that there will be two values for c i.e. null and "abc" also.

I might be wrong also, Please explain me??

Bharat
No.

What you are not understanding is - 'c' and 'd' are not objects. They are references, like the pointers in C++.

If you say c = "Hello", then "Hello" is allocated and 'c' refers to that memory location. Now you say d = c, so 'd' refers to the same memory location.

When you say c = null, 'c' is unhooked from that memory location and refers to nothing. But 'd' is still referring to the same memory location.

Its not lie C++, that if you say c = "Hi", then the original "Hello" will be overwritten by "Hi" in the same memory location. "Hi" will be allocated in a different memory location and 'c' will now start referring to (or pointing to - if you understand that better) that new location.

Is it clear now?

Mayank.
>> Its not lie C++,

Its not *like* C++
>> Her thing is that if c is only one for the piece of code then how can after making c null it will continue to refer old c.
>> I mean where it will be??

'c' will not continue to refer to the old 'c'. 'd' will continue to refer to the same memory location. Because you said c = null, but not d = null. You did not change 'd'. So it will continue to refer to the same location, and 'c' will be null.

'd' and 'c' are not *permanently* attached, that they will always be referring to the same location, and that changing 'c' will also change 'd'.

>> You mean to say that there will be two values for c i.e. null and "abc" also

No, at a time, it refers to only one.

Initially, it refers to  "abc", then 'd' refers to the same memory location. Then you say c = null, so then 'c' becomes null (and 'd' still refers to the "abc"). At a time, 'c' refers to only one thing.
And note that the reference 'c' is not attached to one memory location. And its not that changing 'c = "Hi"' will over-write that memory location. Same for the other references....
ASKER CERTIFIED SOLUTION
Avatar of Mayank S
Mayank S
Flag of India image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Bharat,

Is it still unclear?

Mayank.
AnnieMod,

It is really displeasing when you spend so much of time and effort trying to explain something to the questioner, and he does not even care to respond back. Can you please take care of this?

Rgds,
Mayank.
Mayank,

I agree with you, I ready to accept your answer and sorry for dealy. Thanks for your time and efforts for explaining the answer.

Bharat
Its all right. You can ask AnnieMod to reopen this question for you.
Aaarrghh!!! :)
AnnieMod,

Can you reopen this question for me. I would like to reject the answer which I have already accepted, I would like to change it.

Bharat
Alternatively, you can post a 0-point Question in Community Support, giving a link to this question and requesting to re-open it.
>> you can post a 0-point Question in Community Support, giving a link to this question and requesting to re-open it

Perhaps you can try doing that only.
Can we have it closed now, Bharat?