• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • paul wheaton
  • Paul Clapham
  • Ron McLeod
Sheriffs:
  • Jeanne Boyarsky
  • Liutauras Vilda
Saloon Keepers:
  • Tim Holloway
  • Carey Brown
  • Roland Mueller
  • Piet Souris
Bartenders:

SCJP Brainteaser (11)

 
Ranch Hand
Posts: 1252
Spring Java Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Now enjoy this one too...







Place your declarations according the need.

Enjoy
[ November 14, 2006: Message edited by: Sharma Ji ]
 
Greenhorn
Posts: 24
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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 ]
 
Ranch Hand
Posts: 125
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
 
Ranch Hand
Posts: 72
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
My answer would be as follows :

 
Shaan Shar
Ranch Hand
Posts: 1252
Spring Java Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

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
Posts: 1252
Spring Java Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

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
 
Ranch Hand
Posts: 45
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
May be through Anonymous Constructors, i tried it, but i think i'm in wrong path.
 
Maneessh saxena
Ranch Hand
Posts: 125
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

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.
 
Ranch Hand
Posts: 32
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
 
Valentin Mone
Greenhorn
Posts: 24
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Daniel, I think he he wants us to make it work without making any change to the code....
 
Dan Polak
Ranch Hand
Posts: 32
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
OK, but my second solution is correct.
I didn't make any changes.
 
Saurabh Vyas
Ranch Hand
Posts: 72
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 1252
Spring Java Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

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.
 
Ranch Hand
Posts: 95
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
One possible solution through using reflection api as:





Regards,

Amit Goyal
 
Ranch Hand
Posts: 7729
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Problem with that is that the Reflection API is not within the scope of SCJP.
 
Ranch Hand
Posts: 106
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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?
 
Ranch Hand
Posts: 58
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 58
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 58
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
 
Ranch Hand
Posts: 104
2
Eclipse IDE Java Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Sharma Ji,

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

Omkar V S
 
Ranch Hand
Posts: 380
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
 
venkatesh pendharkar
Ranch Hand
Posts: 106
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Great explaination Franz Fountain, Sharmaji I hope this is the only solution to your problem.
 
Ranch Hand
Posts: 110
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thats Nice answer even it is not a final answer too...
Good one
 
Franz Fountain
Ranch Hand
Posts: 58
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 110
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 58
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 110
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 58
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
"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.
 
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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 ]
 
Ranch Hand
Posts: 91
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 58
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 110
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Now I am onto right path. Thanks for explanation
 
Consider Paul's rocket mass heater.
reply
    Bookmark Topic Watch Topic
  • New Topic