12

I'm coming from the C++ world and I can't find what is the Java alternative (if any) to the following:

struct SomeStruct
{
    SomeStruct(){}
    SomeStruct(const SomeStruct& rhs)
    {
        *this = rhs;
    }
};

The reason why I need this is that I have a cache of existing objects, so I don't want to create another instance but just to 'clone' the existing one, something like this:

public class SomeObject
{
    private static Hashtable _objects;
    SomeObject()
    {
        SomeObject obj = _objects.get(some_key);
        if (obj != null) {
            // *this = obj;
            // instead of: 
            // this.something = obj.something;
            // this.something1 = obj.something1;
            // this.something2 = obj.something2;
            // a zillion fields....
        }
    }
};

EDIT:

Sorry, I confused some things (still need to learn both Java and C++).

Thank You

HotHead
  • 229
  • 1
  • 7
  • See http://stackoverflow.com/questions/869033/how-do-i-copy-an-object-in-java – Winston Ewert Feb 21 '11 at 16:45
  • 12
    Do people really implement copy constructors in C++ that way? And not get fired? – Thomas Edleson Feb 21 '11 at 16:49
  • 2
    It sounds like you simply want a reference to a cached object. See my answer if that's the case. – someguy Feb 21 '11 at 16:56
  • 3
    I don't get it, you have a "cache" of these objects, and you want to "clone" an instance, without "creating a new instance"??? I'm sorry, but "clone" and "not create new instance" are orthogonal. "Clone" implies you've created a new instance and copied the attributes... Why don't you simply use the instance in your cache? – Nim Feb 21 '11 at 16:57
  • Right, so if all you want is a shallow copy from an object pool, see my answer ;-). – someguy Feb 21 '11 at 17:04
  • I'm assuming you're not allocating any dynamic memory? If so, *this = rhs; is useless - you're going to get a memberwise copy. In any case, you forgot the Rule of 3! (Copy Constructor, Assignment Operator, Destructor) – RageD Feb 22 '11 at 05:44
  • 1
    @Thomas: Yes, people really implement copy constructors that way. It's a convenient way to reduce code duplication between the copy constructor and `operator=`. – dan04 Feb 22 '11 at 13:14
  • 2
    @dan04- You should be wary of implementing copy constructors in terms of assignment operators because a good assignment operator will free existing resources before doing the copy. The problem is that in the constructor you haven't necessarily set up any of those resources, so you could easily be reading bad data. It's generally better to implement the assignment operator in terms of the copy constructor and destructor, since the assignment operator really is "tear this object down, then build it back up." – templatetypedef Feb 23 '11 at 10:19

7 Answers7

7

The closest is Object.clone() but read the relevant section from Effective Java first.

There are probably simpler ways to do what you want if you remove some of your requirements. For example, if you make your objects immutable then you don't need to copy the data into another object. Instead you can return a reference to the original object. This is much faster than a memberwise copy, and has lots of other benefits too, such as making it easier to write thread-safe code.

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • `*this = rhs;` in c++ performs a shallow copy of all members by default, it doesn't create a new instance. java has no equivalent. – Erik Feb 21 '11 at 16:48
  • 1
    @Erik: The compiler-generated assignment operator performs a member-wise copy. – Thomas Edleson Feb 21 '11 at 16:52
  • @Thomas: Yes, a shallow copy. – Erik Feb 21 '11 at 16:53
  • @Erik: No. It does exactly whatever "copy" means for each data member. For some types that will be what some call a "deep copy". – Thomas Edleson Feb 21 '11 at 17:00
  • 1
    @Erik: No, it recursively applies the assignment operator on all members. It's supposed to perform a deep copy, though a bad programmer may write it otherwise. – Benjamin Lindley Feb 21 '11 at 17:01
  • @Thomas: But then that wouldn't be a compiler generated op=. A deep copy would copy more than the minimum possible within the language constraints. But we're arguing terms, looks like we both know how it works- – Erik Feb 21 '11 at 17:03
  • @Erik: No, that is the compiler-generated assignment operator. struct Example { vector v; }; Example's compiler-generated assignment operator will copy the v data member. "Deep copy" and "shallow copy" are horribly ambiguous terms. – Thomas Edleson Feb 21 '11 at 17:46
  • @PigBen: It's *supposed* to copy the object. For some types this means new allocations for resources pointed-to by pointer data members. For other types it does not mean that. The language assumes the latter(because of C compatibility), but it is impossible for the language to generate correct code for the former. – Thomas Edleson Feb 21 '11 at 17:51
  • @Thomas: If you by shallow mean bitwise, and I by shallow mean not traversing pointers, then we can't agree :) But yes, it's ambiguous, yet serves to emphasize that it isn't a deep copy without knowing the memberwise term used in the standard. – Erik Feb 21 '11 at 17:53
  • 1
    @Erik: I don't use "shallow copy". Bitwise implies memcpy-like, so that is incorrect too. If by "shallow" you mean "copies each member", then just say that. :) – Thomas Edleson Feb 21 '11 at 17:59
7

There's no direct equivalent. Object.clone() is the closest, but it creates a new instance and performs a shallow copy. You could write something generic using reflection though.

Erik
  • 88,732
  • 13
  • 198
  • 189
3
public class SomeObject
{
    private static Hashtable _objects;

    public static SomeObject getInstance(SomeKey some_key)
    {
        return _objects.get(some_key);
    }
}
someguy
  • 7,144
  • 12
  • 43
  • 57
  • I'm guessing this is what the OP wants too, but probably needs to understand how Java handles object passing... – Nim Feb 21 '11 at 16:59
2

It is unclear from your question whether you are trying to achieve a pure cache of immutable objects, or keep a cache of 'template' objects, and return copies that can then be mutated by the client. I am going to assume the latter.

Assuming that you do want to return copies of originals. there is no really nice way to implement a copy constructor in Java. Clone is marginally nicer, so you should hide the constructor behind a static factory method:

public static SomeObject getInstance(...) {
  SomeObject cached = ...;
  if (cached != null) {
    return cached.clone();
  }
  ...
}

Perhaps in your particular case you can separate the immutable and stateful parts of the objects? If so, some changes to your object model can lead to cleaner (and more efficient) code?

Dilum Ranatunga
  • 13,254
  • 3
  • 41
  • 52
1

In Java, if you want to have a constructor corresponding to a copy constructor, you have to implement it yourself. In some cases, this means you have to copy fields from one object instance into another, while in other cases it means you have to implement a full deep copy - recursively iterate through the reference fields of the parameter in the copy ctor.

This depends on what you want - should the objects hashtable be copied as well? Or should both objects share the reference to it? For more info, see this question.

Community
  • 1
  • 1
axel22
  • 32,045
  • 9
  • 125
  • 137
0

I don't know of any generic way to copy all the contents of fields from one object to another existing without using;

  • reflections
  • generated code.
  • copy using the Unsafe class.

Reflections is easier to use at runtime, but not as efficient as generated code. (But pretty close) I generate my data model so I use this option.

The Unsafe class is faster than reflection, but not cross platform and unsafe. It is almost as fast as generated code. ;)

In terms of speed, if generated code is 1x, Unsafe is 1.5 - 2x and reflection is 2 - 4x slower for highly cached data. For poorly cached data you won't see a difference.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
-1

You should use the Singleton pattern. You create a static instance of SomeObject and work with that instance.

   private static class SingletonHolder { 
     public static final SomeObject INSTANCE = new SomeObject();
   }

   public static SomeObject getInstance() {
     return SingletonHolder.INSTANCE;
   }

But don't fall in the Singleton trap, limit calls to getInstance()!

JPelletier
  • 2,049
  • 16
  • 23
  • Keep in mind by doing this you will have the same object referenced multiple times, and doing Object.clone() you will create another object. – André Costa Feb 21 '11 at 16:48
  • the question indicates that there is more than one instance of SomeObject, and that they are different. So perhaps your idea is better expressed as a singleton factory? – Dilum Ranatunga Feb 21 '11 at 16:48
  • Effectively, it needs a more complex logic like a Singleton Factory. – JPelletier Feb 21 '11 at 16:54