Hi everyone!
We've covered all kinds of methods to create Java class instances.
What if we want to create an instance that's just like the one over there.
We just want a copy.
And that's what we're covering.
The copy constructor in Java, coming up next.
So here's the situation.
We need a copy of an object.
We have A, and after copying our object we have a second object that is the same in every
way as A, but is not A.
One example of why we'd want to do this is, say we have an enemy in a video game.
It has a number of hit points, a weapon it's carrying, a tool belt full of tools, and a
name.
This baddie has the ability to duplicate itself.
So when it duplicates, we need to create a copy of the enemy so there are two, each with
their own hit points, own weapon, own tools, etc.
The first thought might be to create a new instance like this.
We have enemy one, and we create enemy two and assign it to the first enemy.
Done.
This really didn't work.
We just have two enemy variables pointing to the same enemy.
This didn't copy anything, and we still have one instance.
We need to create a copy constructor in Java to have a new enemy instance.
A copy constructor is this.
It's a method that takes an instance of a class, and returns a new instance copied exactly
like the first class.
You can use a static factory method, but best practice is use a constructor that takes a
single instance of the class as a parameter.
We'll create our copy constructor to use a constructor.
What goes in our copy constructor?
Well the next thought is to create a new enemy object, and copy the attributes over.
That looks like this.
Unfortunately this doesn't work either.
We wanted two enemies, but we really got two enemies sharing a weapon and toolbelt.
If we change a value on one weapon, say to overheating, both enemies will experience
the change.
That's because we did something called a shallow copy.
It's interesting to note the hit points and name were not a problem to copy.
If we change the hit points on one enemy, the other is not affected.
The reason is primitive values are just values.
There is no pointer to the value.
They are immutable.
What about the name?
Strings are classes, so do we have the same problem?
If we change the name from George to Gracie, will they both be called Gracie?
Nope.
Strings are immutable classes.
We can't change the value, so what would happen is we'd assign the name pointer to a new string
object.
After copying and changing the name, the enemies' names would point to different string instances.
To have truly different enemies, we need to do something called a deep copy.
That means every class attribute must be copied.
And deep really means deep!
Remember our tool belt?
We can't just copy arrays of class instances.
Every element needs a copy too.
Otherwise the belts would point to the same instances.
It gets ugly quick for classes with large attribute trees.
However, to have a true copy, that's what we need to do in our copy constructor.
Make a new instance of everything.
Best practice is copy constructors provide deep copies.
Some of you are probably thinking there got to be a better way, and digging through the
Java API we'd notice, hey, every object has a clone method.
The clone method is a copy constructor implemented as a static factory.
Kind of.
Unfortunately the clone method is a colossally horrible idea.
The way clone works is our object must implement Cloneable in order to be cloned.
The reason is the Object class has a clone method that checks to see if the Class implements
Cloneable.
If it doesn't, clone must throw an exception.
So every time we clone, we need to check for exceptions.
When we clone an object, we really need to call super on the clone method.
The reason is we don't always have access to all the state.
Some state might be private, so we need each class in the class hierarchy to handle it's
own part for clone.
Another problem is clone is protected.
And if any part of our class hierarchy doesn't implement Cloneable, the whole thing falls
apart.
Long story short, too late.
There is nothing in Java that provides deep copies for free.
So what do we do?
Well if we need a copy constructor, step one is to write our own.
This is better because we don't need to mess with the Cloneable interface and it doesn't
throw exceptions.
It's just alot of work.
The advantage of a copy constructor is you have complete control over how it's implemented,
and it returns the class instance you want.
A second thing that will help when making copy constructors is immutable objects.
Remember earlier, we had no problems with primitives and strings.
If our enemies consisted of immutable objects, copies become very easy.
It really depends on what we're doing, but if we can avoid mutable objects, it will make
things easier.
Finally another option is don't copy anything.
Make sure copying is really what you need to do.
There's nothing inherently wrong with copying objects, but we do need to be very careful.
If we can avoid it, even better.
Thanks for watching!
Copying instances can get very tricky, so if you have any questions let me know in the
comments.
Make sure you subscribe to the channel, so you don’t miss a video!
Liking the video helps me understand what I'm doing right, so if you liked the video...
you know what to do.
And with that, I’ll see you in the next tutorial!