25

Consider the following case:

class A {
  int x;
  int y;
}

class B extends A {
  int z;
}

Now, somewhere in the code this classes are used like this:

A objA = getAFromSomewhere();
B objB = null;

And in a certain situation I want to do something like

objB = objA; // can't do this
objB.z = someZ;

Of course the real objects are a bit more complicated, so it's not just about copying two ints. But they aren't overly complex either.

I know I can write a constructor for B like this:

public B(A anA) {
  this.a = anA.a;
  this.b = anA.b;

  this.z = 0;
}

But if that's really the only way, I prefer merging the additional members of B into A.

update considering the answers

My question was not clear enough. I understand that objB = objA; can't work (thus I asked for "something like", meaning something with comparable code complexity) and I know about the issues with shallow vs deep copies.
What I was looking for is a possibility to copy the members of a base class (let's say using clone()). You may understand that copying every member manually is a bad solution as it adds complexity and redundancy to the code. Thanks for your replies anyway!

didi_X8
  • 5,018
  • 10
  • 42
  • 46

10 Answers10

22

There's no trivial solution to this because there's no one-size-fits-all solution. Basically you don't have all the information within a B, so you can't guarantee you would have a "sensible" B object.

You probably just want to create a constructor in B which takes an A and copies all the A data into the new B.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • I've modified my question to take this into account. Looks like there really is no elegant solution – didi_X8 Aug 03 '11 at 10:31
  • 2
    @didi_X8: Indeed - but it's important that you understand *why* there's no general elegant solution. For example, what would it mean if I were to be able to write: `Object x = "Hello"; FileOutputStream stream = x;`? – Jon Skeet Aug 03 '11 at 10:34
  • 1
    "You probably just want to create a constructor in B which takes an A and copies all the A data into the new B." Yes, that's exactly what I wanted. But without mentioning every member of A seperately. – didi_X8 Aug 03 '11 at 10:49
  • 1
    @didi_X8: Right... unfortunately I don't believe there's a simple way of doing that. (In your case they're ints, but imagine if they were objects... shallow or deep copy? It becomes tricky, basically...) – Jon Skeet Aug 03 '11 at 10:53
  • 1
    In my case they are objects (just used ints in this example), but a shallow copy would be ok. Still there seems to be no way to shortcut with clone(). – didi_X8 Aug 03 '11 at 13:31
  • Couldn't the OP use inspection to copy everything from A to B in the constructor of B ? I think that would avoid requiring all members individually. – Steven De Groote Jul 29 '13 at 10:13
  • 1
    And I wanted to point to this related question that shows how... http://stackoverflow.com/questions/1667854/copy-all-values-from-fields-in-one-class-to-another-through-reflection – Steven De Groote Jul 29 '13 at 10:20
  • @AlexR: Please don't add entirely new code into an answer like this. If you want to provide more information, add a new answer. – Jon Skeet Oct 04 '20 at 06:51
5

If you're not scared of commons-beanutils you can use PropertyUtils

import org.apache.commons.beanutils.PropertyUtils;
class B extends A {
B(final A a) {
try {
        PropertyUtils.copyProperties(this, a);
    }
    catch (Exception e) {
    }
}
}
JTP
  • 231
  • 3
  • 5
  • what's the reason to be scared of commons-beanutils? – Arvind Sridharan Feb 10 '23 at 04:13
  • 1
    I think there are several reason to consider. It will eventually add a new dependency to your project, with the downsides that comes with. It relies on reflection which may have performance implications in applications running with limited resources or where performance is of the essence to mention a few. Latest version 1.9.4 is from 2019, but there seem to be some beanutils2 ongoing work at https://github.com/apache/commons-beanutils – JTP Feb 16 '23 at 20:04
4

There is a (relatively) trivial solution!

Implement a constructor in class B that takes an instance of class A and copies the fields.

One of the reasons there's no generic solution in the language itself is because of the problem of deep copying.

For example, if the source object contains further Objects, as opposed to plain types, what would the generic copy operator do? Just copy the reference (giving a shallow copy), or make real copies?

What then if one of those objects is a Collection? Should it also copy every element of the collection, too?

The only logical conclusion would be to perform a shallow copy, but then you haven't really got a copy at all.

Alnitak
  • 334,560
  • 70
  • 407
  • 495
1

Perhaps you could do this:

class A {
    int x;
    int y;

    A(A a) {
        this.x = a.x;
        this.y = a.y;
    }
}

class B extends A {
    int z;

    B(A a) {
        super(a);
        z = 0;
    }
}

You're still listing every field, but only once per class.

Gilbert Le Blanc
  • 50,182
  • 6
  • 67
  • 111
0

...not because this is what people should do but more because I felt like a challenge, here is some test code which does a simple copy of the objects (using setter and getter methods):

import java.lang.reflect.Method;
import org.junit.Test;

public class ObjectUtils {
    @Test
    public void test() {
        A a = new A();
        B b = new B();
        a.setX(1);
        a.setY(2);
        this.copyProperties(a, b);
    }
    private void copyProperties(Object obja, Object objb) {
        Method m[] = obja.getClass().getDeclaredMethods();
        for(int i=0;i<m.length;i++) {
            try {
                String name = m[i].getName();
                if(name.startsWith("get") || name.startsWith("is")) {
                    Class rtype = m[i].getReturnType();
                    String setter = name.replaceFirst("^(get|is)","set");
                    Class s = objb.getClass();
                    Method method = s.getMethod(setter,rtype);
                    Object[] args = new Object[1];
                    args[0] = m[i].invoke(obja);
                    method.invoke(objb,args[0]);
                }
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    }
    class A {
        int x;
        int y;
        /**
         * @return the x
         */
        public int getX() {
            return x;
        }
        /**
         * @param x the x to set
         */
        public void setX(int x) {
            this.x = x;
        }
        /**
         * @return the y
         */
        public int getY() {
            return y;
        }
        /**
         * @param y the y to set
         */
        public void setY(int y) {
            this.y = y;
        }       
    }
    class B extends A {
        int z;
        /**
         * @return the z
         */
        public int getZ() {
            return z;
        }
        /**
         * @param z the z to set
         */
        public void setZ(int z) {
            this.z = z;
        }
    }
}
user1098932
  • 243
  • 2
  • 4
  • 9
0

If you do not need full functionality of A, there is also an option to create class B, holding internal copy of A instance and implementing some minimal subset of methods via C interface by proxying them to instance.

class A implements IC {
  int x;
  int y;

  public C() {
  ...
  }
}

class B implements IC {
  private A _a;

  public B(A a) {
    _a = a;
  }

  public C() {
  _a.C();
  }
}
user3132194
  • 2,381
  • 23
  • 17
0

Assuming that your class A has a very neat and clean setter and getter method naming convention like setXXX(Object xxx) and corrresponding getXXX() which returns the same thing (Object xxx ) as a param passed to setXXX()

I have written a utility method using reflection

public static B createSubclassInstance(A a) throws SecurityException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
        Method[] aMethods = Class.forName("package.A").getDeclaredMethods();
        B b = new B(); 
        for (Method aMethod : aMethods) {
            String aMethodName = aMethod.getName();
            Class param = aMethod.getReturnType();
            if (methodName.startsWith("get")){
                String setterMethodName = methodName.replaceFirst("get", "set");
                Method bMethod = Class.forName("package.B").getMethod(setterMethodName);
                Object retValA = aMethod.invoke(a,null);
                bMethod.invoke(b,retValA);
            }

        }
        return b;
    }
Nostalgic
  • 300
  • 1
  • 4
  • 18
0

I am shocked too. :)

You really cannot do this: objB = objA;. Because Renault and BMW are cars but not all cars are BMW.

Thank about A as Car, B as BMW.

Now you say:

Car car = new Renault();
BMV bmv = car;  // you cannot do this. This is exactly your case. 
AlexR
  • 114,158
  • 16
  • 130
  • 208
  • 1
    I understand that I can't do this, that's not the problem. I just wondered if there's no straightforward way to say (in a constructor): copy all shared (base class) parts from the "source" obj (whatever it be) and separately initialize the additional (BMW) ones. – didi_X8 Aug 03 '11 at 10:33
-1

If you change your method to create B objects, you can just do what you want using:

objB = (B) objA;
objB.z = someZ;

This can even be inlined, but you need parentheses:

((B) objA).z = someZ;

If not, you have to go the long way using constructors:

objB = new B(objA);
objB.z = someZ;

In this case I would recommend to copy the fields of the superclass in the superclass. Else, if you add a field to that class later, you may forget to change the copying more easily.

class A {
    int x;
    int y;
    public A(A objA) {
        x = objA.x;
        y = objA.y;
    }
}

class B extends A {
    int z;
    public B(A objA) {
        super(objA);
    }
}

I prefer merging the additional members of B into A.

You can do this if your classes A and B share the same package or if the variables in your A class are declared as protected. Then you can just access the fields of the superclass.

class A {
  protected int x;
  protected int y;
}

class B extends A {
  int z;

  void merge(A a){
    super.x = a.x; 
    y = a.y;        // you do not *need* to use the super keyword, but it is a good hint to
                    // yourself if you read your program later and might wonder ‘where is
                    // that y declared?’
  }
}

Useage, of course, is:

objB = new B();
objB.merge(objA);
objB.z = someZ;
Matthias Ronge
  • 9,403
  • 7
  • 47
  • 63
-3

I think best way is to use a factory method to create B objects from A objects.

class BFactory
{
    public static B createB(A a)
    {
     B b = new B();
     copy(a,b);

     return b;
    }

    private static <X,Y> void copy(X src,Y dest) throws Exception
    {
        List<Field> aFields = getAllFields(src.getClass());
        List<Field> bFields = getAllFields(dest.getClass());

        for (Field aField : aFields) {
            aField.setAccessible(true);
            for (Field bField : bFields) {
                bField.setAccessible(true);
                if (aField.getName().equals(bField.getName()))
                {
                    bField.set(dest, aField.get(src));
                }
            }
        }
    }

    private static List<Field> getAllFields(Class type)
    {
        ArrayList<Field> allFields = new ArrayList<Field>();
        while (type != Object.class)
        {
            Collections.addAll(allFields, type.getDeclaredFields());
            type = type.getSuperclass();
        }
        return allFields;
    }
}
Low Flying Pelican
  • 5,974
  • 1
  • 32
  • 43
  • 2
    Downvoted because the answer doesn't take into account the question: the question is basically saying "how can I avoid mentioning every single member A and B have in common? – acorello Mar 07 '13 at 11:46