Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How do I genericly clone() objects?

Status
Not open for further replies.

cpjust

Programmer
Sep 23, 2003
2,132
US
Hi,
I'm trying to write a function that takes a collection of generic types and copies (i.e. clones) each element of the collection into a new collection. The problem is, clone() is protected and the Cloneable interface doesn't even make it public... I was thinking of using something like this, but of course the compiler doesn't like the call to clone().
Code:
public static <T extends Cloneable>
void Copy( Collection<T> lhs, Collection<T> rhs )
{
   lhs.clear();
   Iterator<T> it = rhs.iterator();

   while ( it.hasNext() == true )
   {
      lhs.add( it.next().[b]clone()[/b] );
   }
}
How can I create a generic function that only accepts collections where T.clone() is public?

Also, what's the point of Cloneable? If it doesn't define clone() as public, what's the point of implementing it?
 
The Cloneable interface is a 'tagging' interface. It is implemented to signal that the clone() method is available for a particular class. I've not progressed onto Java5 yet so I'm not fully aware of the generics syntax. On Java1.4 I would just call the clone method on Object instances from the rhs iterator, dealing with any CloneNotSupportedException's thrown on the way.

Your iterating over a collection of Cloneable instances, which as you say, won't compile since the clone() method isn't actually declared in the interface.



Tim
 
timw said:
I would just call the clone method on Object instances from the rhs iterator
But how would you do that if Object.clone() isn't public?

To be honest, I don't really care how I copy the objects (whether is be with a clone() function or whatever), but I just want a completely independent copy of the object. Is there any other ways you can think of to do this in Java?
 
Sorry, you're absolutely right. You have to know the class of object and cast it to access the concrete implementation of this method. Doesn't help much if the collection contains objects of arbitrary types. You'd probably have to use instanceof to detect whether the tagging 'cloneable' interface is present and then use introspection. Yuk.

Tim
 
Why introspection? Can´t you just cast to Cloneable?

Anyway, I don't think cloning is a good practice. I'd say you cannot clone a generic object unless you know the class has implemented that method (and that wouldn't be generic at all).

Cheers,
Dian
 
You can't use a cast to Cloneable because it doesn't contain the clone() method...

Tim
 
... but it does seem polymorphically reasonable to ask an arbitrary instance to clone itself though.

Tim
 
I think I found a non-clone solution. It compiles, but I haven't tested it yet.
Code:
public final static <T>
void CopyCollection( Collection<T>  lhs,
                     Collection<T>  rhs,
                     	  Class<T>  cType ) throws SecurityException,
                     	  						   NoSuchMethodException,
                     	  						   IllegalArgumentException,
                     	  						   InstantiationException,
                     	  						   IllegalAccessException,
                     	  						   InvocationTargetException
{
	// First make sure lhs is empty.
	lhs.clear();
	Iterator<T> it	= rhs.iterator();
	Constructor<T> con = cType.getConstructor( cType );

	while ( it.hasNext() == true )
	{
		lhs.add( con.newInstance( it.next() ) );
	}
}
 
But doesn't that require that you know the type of the objects within the rhs collection since you need to pass it as a parameter? Looks like it would work, though as I say, my Java5 generics knowledge is embryonic :)

Tim
 
Humm, regex and generics are making me a Java ignorant.

Anyway, I think you don't need to pass de Class<T>, you can get class from any Object.

Appart from that, you cannot guarantee every class has a constructor that accepts an object of the same class as parameter and you cannot guarantee that, even exisiting, it will clone the object.

Btw, why do you want to clone a collection?

Cheers,
Dian
 
Yes, I know the Collection type at the calling site, but I don't want the CopyCollection() function to have to know the type since the rest of the code would be the same...

I tried T.class first, but I got an error. :-(

I would have preferred to use compile-time checks to ensure a valid type is passed, but the more I use Java, the more I'm realizing it's a run-time oriented language. So if a bad type (i.e. no public copy constructor) is passed, I simply throw an exception.

The reason I'm making a copy of objects is because I want to compare the objects before and after I do an operation to ensure that the state wasn't modified.
 
Use getClass() instead of .class.

I don't think Java is a runtime language. I think runtime validations are neccesary only when - please no offense here - the OOP design is not clear enough.

I've myself used runtime functionalities as reflection, instanceof and so on, but everytime I did that I assumed a not-so-good design.

I imagine your case has more complexity behind what about:

- ensure the operation doesn't change the state by correctly code the operation?

- design the Objects to be immutable?

Cheers,
Dian
 
What's wrong with .class? I've never used .class or getClass() before, so I just used what I saw in some examples.

I'm pretty certain that my operations don't explicitly change the object's state, but since my object represents a User account on a mainframe, and the operation calls a 3rd party library to query & run user commands, I need to be sure that neither the Java object, nor the User account on the mainframe were modified.
My User object's comparison functions compare the object member variables as well as querying the User status on the remote system.
 
I'm not sure about how are you using .class, but getClass() is part of the signature for Object class so it should be accepted.

.class is AFAIK just part of class Class.

Cheers,
Dian
 
Here's an example of how I'm calling CopyCollection():
Code:
...
Set<String> clone = new LinkedHashSet<String>();
Util.CopyCollection( clone, rhs.m_ConnectedGroups, [b]String.class[/b] );

I can't find any mention of .class in the documentation for Object or Class... The Auto-Completion help in Eclipse shows .class as a static member variable in every class I try it with.
 
I believe what that link is saying is that .class is intended to be used at the class level (i.e. String.class), whereas .getClass() is used at the object level (i.e. str.getClass()).

I know Strings are immutable in Java, but the references to those strings can still be changed.
 
No, they can't.

Code:
class Hola 
{
	public void changeString(final String a) {
		a="2";
	}
	public static void main(String[] args) 
	{			
                String b = "1";
		System.out.println(b);
	}
}

Try this test: the second method gets a local copy of the reference. The original one remains.

You can always use the final keyword in a method signature.

Cheers,
Dian
 
Sorry, that won't even compile. Remove final keyword to do the test.

Cheers,
Dian
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top