wood burning stoves 2.0*
The moose likes Programmer Certification (SCJP/OCPJP) and the fly likes SCJP Brainteaser (11) Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Certification » Programmer Certification (SCJP/OCPJP)
Bookmark "SCJP Brainteaser (11)" Watch "SCJP Brainteaser (11)" New topic
Author

SCJP Brainteaser (11)

Shaan Shar
Ranch Hand

Joined: Dec 27, 2005
Posts: 1249

Now enjoy this one too...







Place your declarations according the need.

Enjoy
[ November 14, 2006: Message edited by: Sharma Ji ]

The Best way to predict your future is to create it - Every great individual common man
Valentin Mone
Greenhorn

Joined: Nov 05, 2006
Posts: 24
this is a good one ... personally I don't think it's possible to get that output.
[ November 14, 2006: Message edited by: Valentin Mone ]
Maneessh saxena
Ranch Hand

Joined: Oct 03, 2006
Posts: 125
hi Mr. sharma ,
I am posting one of the possible solution . And waiting for the solution that you want .

class Dog extends Exception {
public static final Dog INSTANCE = new Dog();
private Dog() { }
public static Dog getInstance(){
return new Dog();
}
public String toString() {
return "Woof";
}
}

class CopyDog {
public static void main(String[] args) {
Dog newDog = Dog.getInstance();
System.out.println(newDog == Dog.INSTANCE);//false
System.out.println(newDog);//Woof
}

}

Regards


SCJP 1.4, SCWCD 1.5
Saurabh Vyas
Ranch Hand

Joined: Sep 02, 2003
Posts: 72
My answer would be as follows :

Shaan Shar
Ranch Hand

Joined: Dec 27, 2005
Posts: 1249

Originally posted by raunak saxena:
hi Mr. sharma ,
I am posting one of the possible solution . And waiting for the solution that you want .

class Dog extends Exception {
public static final Dog INSTANCE = new Dog();
private Dog() { }
public static Dog getInstance(){
return new Dog();
}
public String toString() {
return "Woof";
}
}

class CopyDog {
public static void main(String[] args) {
Dog newDog = Dog.getInstance();
System.out.println(newDog == Dog.INSTANCE);//false
System.out.println(newDog);//Woof
}

}

Regards


I appreciate your efforts but here you have changed some code. like you have added getInstance() method in Dog class.

So you are near about the solution, but still not perfect one.

Better luck next time.
[ November 14, 2006: Message edited by: Sharma Ji ]
Shaan Shar
Ranch Hand

Joined: Dec 27, 2005
Posts: 1249

Originally posted by Saurabh Vyas:
My answer would be as follows :



I appreciate your efforts, but it will not print the desired results. and the reason behind this is quite easy, you can easily have a idea, if you look carefully your code.

Better luck next time
Ganesh Pujar
Ranch Hand

Joined: Mar 22, 2006
Posts: 45
May be through Anonymous Constructors, i tried it, but i think i'm in wrong path.
Maneessh saxena
Ranch Hand

Joined: Oct 03, 2006
Posts: 125
Originally posted by Ganesh Pujar:
May be through Anonymous Constructors, i tried it, but i think i'm in wrong path.


dear Punjar,

there is no chance of Anonymous Constructors as Dog contructor is given private so we can't have Anonymous subclass of class Dog.

hope you understand that.
Dan Polak
Ranch Hand

Joined: Nov 06, 2006
Posts: 32
Hello


first solution

Object newDog = new Object() {
public String toString() {
return "Woof";
}
};

// This line should print false
System.out.println(newDog == Dog.INSTANCE);

// This line should print "Woof"
System.out.println(newDog);

----------------------------------------------------------------------
because it wasn't very fair i have the second one


Dog newDog = null;
try {

File f = new File("c:\\a");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));
oos.writeObject(Dog.INSTANCE);
ObjectInputStream iis = new ObjectInputStream(new FileInputStream(f));
newDog = (Dog)iis.readObject();
f.delete();

} catch (Exception e) {
e.printStackTrace();
}


// This line should print false
System.out.println(newDog == Dog.INSTANCE);

// This line should print "Woof"
System.out.println(newDog);

bye


<a href="http://www.dantheman.pl" target="_blank" rel="nofollow">http://www.dantheman.pl</a>
Valentin Mone
Greenhorn

Joined: Nov 05, 2006
Posts: 24
Daniel, I think he he wants us to make it work without making any change to the code....
Dan Polak
Ranch Hand

Joined: Nov 06, 2006
Posts: 32
OK, but my second solution is correct.
I didn't make any changes.
Saurabh Vyas
Ranch Hand

Joined: Sep 02, 2003
Posts: 72
Sharma Ji what is the actual answer !!!
I am egar to know that. I feel i am running out of ideas to make it work
Shaan Shar
Ranch Hand

Joined: Dec 27, 2005
Posts: 1249

Originally posted by Saurabh Vyas:
Sharma Ji what is the actual answer !!!
I am egar to know that. I feel i am running out of ideas to make it work


Well too early for reply, You can also think about Java Libraries.

Just think about it. and let us know about your thoughts..

Enjoy.
Amit Goyal
Ranch Hand

Joined: Feb 21, 2006
Posts: 95
One possible solution through using reflection api as:





Regards,

Amit Goyal
Barry Gaunt
Ranch Hand

Joined: Aug 03, 2002
Posts: 7729
Problem with that is that the Reflection API is not within the scope of SCJP.


Ask a Meaningful Question and HowToAskQuestionsOnJavaRanch
Getting someone to think and try something out is much more useful than just telling them the answer.
venkatesh pendharkar
Ranch Hand

Joined: Apr 29, 2006
Posts: 106
can it work if we use clone() method??
eg.Dog newDog=(Dog)(Dog.INSTANCE).clone(); when i tried this it gave compie time error saying clone() has protected access in Object.
I thought this should have worked cause it will give a copy of Dog object & so newDog==Dog.INSTANCE will be false.
can anyone tell me whats problem in this?
Franz Fountain
Ranch Hand

Joined: Nov 15, 2006
Posts: 58
I noticed that you created to public classes which requires to separate files. Is this a requirement for this to work?
Franz Fountain
Ranch Hand

Joined: Nov 15, 2006
Posts: 58
Can you give a hint?
Does the solution have anything to do with inner classes?
Does it require creating a method on the fly that returns a Dog?
Does it require creating a class on the fly that extends Dog?
Does it require causing a Dog exception that will get caught and returned to newDog?

The only thing that even remotely works right now is:
Dog newDog = Dog.INSTANCE;
Of course this prints "true Woof" not "false Woof"

Anything like:
Dog newDog = (Dog) new Exception();
causes a ClassCastException

Dog newDog = null;
prints "false null" instead of "false Woof"

Right now I'm howling at the moon? (Get it... dog... moon)
Franz Fountain
Ranch Hand

Joined: Nov 15, 2006
Posts: 58
public class Dog extends Exception {
public static final Dog INSTANCE = new Dog();
private Dog() { }

public String toString() {
return "Woof";
}
}

A little more thought on this reveals that this is a Singleton.

There's no access to the constructor from outside so anything like:
new Dog();
won't work.

Also anything that tries to extend Dog runs into the same problem with the constructor being public so anything like:
class Puppy extends Dog {
}
won't work.

INSTANCE is a static so there is only one for the whole class no matter how many instances of Dog are created. (If you could create one, which you can't.) So anything like:
newerDog = Dog.INSTANCE;
just returns the same old dog-gone instance of Dog.

It seems you can't teach a newDog an old trick! So what's the catch? What am I missing?

Well you can say:
Dog newDog = null;
But that dog won't hunt, or "Woof".

I even tried throwing newDog and catching him as an Exception but he just came back home. Same old newDog.

The only sniff of hint that we have been given is something regarding Java Libraries. The only "Library" that I can think of that will apply is something having to do with Exception. Looking at Exception I see that it implements Serializable.

So I think that the solution is already in this thread which is to serialize and then de-serialize the newDog Object as suggested by Daniel Charczynski. When it's serialized, the static variable is not saved because it isn't part of the state of the instance. (It's part of the state of the class, but the state of the class isn't saved by serialization.) So when it's de-serialized the static variables doesn't get assigned a value.

But there's more to this story. When INSTANCE is called it returns the same copy of Dog that it always return. That is the Dog Class's one and only INSTANCE copy. But what's different is that the deserialization process has created a brand new copy of Dog WITHOUT USING A CONSTRUCTOR. When you de-serialize you don't run any constructors because that would affect the state of the saved object - effectively resetting the object. And that's not what you want with de-serialization. You want to get back the state of the object just as you saved it.

So now there is a new Dog object. It wasn't created through a constructor. So we've broken the Singleton pattern that it looks like we were trying to achieve. Oh well. Our Dog now has a twin. Still I don't think this a "bug" in this code, it's more like a "feature".

One change I would make to Daniel Charczynski's solution just to make it clear that we aren't pulling any dogs out of the hat:

Dog newDog = Dog.INSTANCE; // *** change from null
try {

File f = new File("c:\\a");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));
oos.writeObject(newDog); // *** change from Dog.INSTANCE

Cheers
Omkar Shetkar
Ranch Hand

Joined: Jun 22, 2006
Posts: 42

Hi Sharma Ji,

I tried to solve your brain teaser but in vain... can you uncover the problem...

Omkar V S


http://mynotesontech.wordpress.com/
Shivani Chandna
Ranch Hand

Joined: Sep 18, 2004
Posts: 380
Franz Fountain - what a lovely explained - i had a great time reading it

We could have done with Cloning had it implemented the Cloneable interface

Good Fun !

Shivani


/** Code speaks louder than words */
venkatesh pendharkar
Ranch Hand

Joined: Apr 29, 2006
Posts: 106
Great explaination Franz Fountain, Sharmaji I hope this is the only solution to your problem.
Hareesh Ram Chanchali
Ranch Hand

Joined: Jan 31, 2005
Posts: 110
Thats Nice answer even it is not a final answer too...
Good one


Hareesh Ram Chanchali
SCJP 5.0, IBM Certified Solution Designer
Franz Fountain
Ranch Hand

Joined: Nov 15, 2006
Posts: 58
What would you do if your manager came to you and told you to fix this "bug" in the Singleton code? (I would probably first tell the manager it's not a bug.) I have an idea, but I'm curious to see how other people would "fix" it to satisfy the manager.

Just to be clear as to what the "bug" is, the Singleton pattern should not allow to instances of the Dog class to be created. So how would you prevent a new instance from being created in this case?
Hareesh Ram Chanchali
Ranch Hand

Joined: Jan 31, 2005
Posts: 110
Hi,

We can have a static variable of type class Dog and can code like below

public class Dog extends Exception {

private static Dog uniqueInstance;
private Dog() { }

public static Dog getInstance()
{
if (uniqueInstance == null) {
uniqueInstance = new Dog();
}
return uniqueInstance

}

}

The above code will only allow only one instance..i.e. Singleton...
Franz Fountain
Ranch Hand

Joined: Nov 15, 2006
Posts: 58
This solution doesn't actually solve the problem of serializing/de-serializing. When the Dog is de-serialized it will still create a new Dog which is different from the one that was saved. (I tried it to verify this.)

Since Dog extends Exception and Exception implements Serializable there is no way to "turn off" serialization directly. That is a subclass can't unimplement an interface. My solution is to override the writeObject() and readObject() methods in Dog to something like:



What do the more experienced Java programmers think of this solution? How would you solve the serialization/de-serialization problem with a Singleton that implements serializable?
Hareesh Ram Chanchali
Ranch Hand

Joined: Jan 31, 2005
Posts: 110
we can use "synchronized" before the method which will allow only one thread to execute the body of the method. I think this will solve the problem.
Franz Fountain
Ranch Hand

Joined: Nov 15, 2006
Posts: 58
"synchronized " will have no effect on this problem.

The problem is that de-serialization will create a new Dog object that is independent of the original. It does this by re-constituting the saved Dog from the disk file. This Dog clone can be re-constituted on any system. It will be a unique Object, but it will be an exact copy of the origninal Dog - a clone. It could also be de-serialized multiple times on the same system. Each time creating a new clone that exists as a separate entity on the heap.

Just take a look at this line:
newDog = (Dog)iis.readObject();
It creates a new Dog object, even though the point of a Singleton is to only allow one object to exist. Yes, the getInstance will return the same Dog, but that doesn't change the fact that there are now 2 Dogs in the system.
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
Well, the two solutions I could think of were using serialization or reflection, both of which have been suggested already. So I'm curious to see what else Sharma may be thinking of.

As a minor refinement to Daniel's solution, we can use a byte array rather than a file. That way there's no need to worry about whether the file path we use is legal on a given system. (Also, it's most likely faster.)


[Franz]:

One change I would make to Daniel Charczynski's solution just to make it clear that we aren't pulling any dogs out of the hat:

Dog newDog = Dog.INSTANCE; // *** change from null


I really can't see why this change would matter at all. What was unclear about Daniel's original solution?

[Franz]: My solution is to override the writeObject() and readObject() methods in Dog to something like:

This is a minor point, but technically you aren't overriding anything here. There is no readObject() anywhere in any superclass, and the writeObject() in Throwable is private, therefore it can't be overridden; it's ignored. This is an unusual situation - normally there would be no point at all to creating a private method in a class if that method isn't called from within that class. But Java's serialization mechanism uses reflection to access these private methods, bending some of the usual rules here. Anyway, I still wouldn't call this "overriding".

Incidentally, when throwing an exception just to make a method unusable, a more common choice would be to use UnsupportedOperationException rather than NoSuchMethodException. Semantically it's a little more accurate (because the method does exist, you're just not supposed to use it) and it has the advantage of being unchecked, which means you can insert a throw UOE into just about any method call you want to. Of course, other coders won't always appreciate this, but that's the risk you take.

So, is there any other way to make a Serializable class a singleton? (Subject to the usual limitations on what "singleton" means; there are always loopholes if you have multiple classloaders, but ignoring that...) It might be nice if deserializing didn't throw an exception, but instead simply returned the same INSTANCE that is supposed to be the only one in existence. The API for Serializable tells us how we can do this. Just add this method to the Dog class:

[ November 18, 2006: Message edited by: Jim Yingst ]

"I'm not back." - Bill Harding, Twister
Tilo Hemp
Ranch Hand

Joined: Nov 21, 2005
Posts: 91
Here is another correct solution

It is based on the idea to redefine System.out.println(Object o)
This method is redefined to always print "Woof".

The newDog variable is assigned null, so the redefined System.out.println is actually called with null, but prints "Woof", because it is redefined.

The redefinition has to be wrapped into one statement that returns null (as we are only allowed to insert something into the line Dog newDog = ...;

The full code looks like this (it works, I tried it)





[ November 18, 2006: Message edited by: Tilo Hemp ]
[ November 18, 2006: Message edited by: Tilo Hemp ]
Franz Fountain
Ranch Hand

Joined: Nov 15, 2006
Posts: 58
Hi Sherrif Jim,

Thanks for the help! I removed the writeObject and readObject methods from Dog and added readResolve as you suggested. Here's how I implemented it. (The println was just to make sure the method was being called.)



It works like a charm!

The comment regarding overriding with regards to writeObject and readObject is right on. This is a good point and an important one to understand serialization.

Regarding my change to Daniel's code, to me at least this slight change demonstrates a little more clearly what is happening in the serialization/de-serialization process.

1. save newDog object
2. recover newDog through serialization, but it drives home the point that the newDog that is recovered from serialization is not the same newDog that went in.

To me it makes it clearer, but for someone else it may just confuse the issue or be irrelevant. That's OK. I'm cool with that either way.

I also appreciated the advice regarding throwing a UnsupportedOperationException.

That's just the sort of feedback I was looking for. (I wasn't comfortable with NoSuchMethodException, it's clearly not the appropriate choice.)
Hareesh Ram Chanchali
Ranch Hand

Joined: Jan 31, 2005
Posts: 110
Now I am onto right path. Thanks for explanation
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: SCJP Brainteaser (11)