When one object variable is assigned to another in various programming languages like Java or C#, a reference to the object's memory location is duplicated, rather than the object itself. Consequently, both variables indicate the same object instance stored in memory. This differs from value-type variables such as integers, booleans, etc., which store the actual value directly.
For example:
MyClass g1 = new MyClass();
MyClass g2 = g1;
Here, g1 and g2 serve as reference variables that hold memory addresses directing to the physical MyClass object stored in memory, such as address 5000. Upon assigning g1 to g2 using =, we duplicate the reference, resulting in both g1 and g2 pointers pointing to the IDENTICAL MyClass instance at address 5000.
As a result, modifications performed on the object using g1 or g2 will reflect when interacting with the object through either, as there remains a single underlying object. This differs from duplicating a value type such as an integer, where g2 would retain its separate instance of the value.
So, to recap, the = assignment operator for reference types duplicates the reference, not the object itself, leading both references to point to the identical instance. Contrastingly, value types store values directly, resulting in the value being duplicated into the new variable during assignment.
What is Shallow Copy?
A superficial duplication of an object does not generate fresh duplicates of the inner objects; instead, it duplicates the reference to these inner objects. This implies that the duplicated object directs to the identical inner objects as the initial object.
In more detail:
- A new instance is created with exact copies of the values present in the original object when a shallow copy is made.
- References to lists, arrays, and other reference-type fields in the original object are copied to the new object. So, the new object points to the same nested objects.
- If the original object is modified, the nested objects are modified. Since the shallow copy points to the same nested objects, those changes would also be reflected in the copy.
- Essentially, the nested objects are "shared" between the original and shallow copied objects by reference instead of being copied. Only the top-level values are copied.
Example:
Let's consider a C# program to demonstrate the concept of Shallow copy.
using System;
using System.Collections.Generic;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public List<string> Hobbies { get; set; } = new List<string>();
public override string ToString()
{
return $"Person: {Name}, Age: {Age}, Hobbies: {string.Join(", ", Hobbies)}";
}
}
class Program
{
static void Main()
{
// Create an instance of the Person class with hobbies
Person originalPerson = new Person { Name = "John", Age = 30, Hobbies = { "Reading", "Gaming" } };
// Perform shallow copy
Person copiedPerson = ShallowCopy(originalPerson);
// Modify the original object
originalPerson.Name = "Jane";
originalPerson.Age = 25;
originalPerson.Hobbies.Add("Traveling");
// Display original and copied objects
Console.WriteLine("Original: " + originalPerson);
Console.WriteLine("Copy: " + copiedPerson);
Console.ReadLine();
}
static Person ShallowCopy(Person original)
{
// Simply create a new instance and copy the values, including the reference type (List<string>)
return new Person { Name = original.Name, Age = original.Age, Hobbies = original.Hobbies };
}
}
Output:
Original: Person: Jane, Age: 25, Hobbies: Reading, Gaming, Traveling
Copy: Person: John, Age: 30, Hobbies: Reading, Gaming, Traveling
What is Deep Copy?
A deep copy refers to duplicating an object in a way that reproduces all nested objects within the original object. Rather than copying references to nested objects, it generates fresh instances of these nested objects.
In more detail:
- When creating a deep copy, wholly new instances of nested objects are created recursively through all levels of nesting within the object.
- No object references are shared between the original and the deep-copied object. It isolates the copied object from any changes made to the original object after copying.
- Performing a deep copy requires additional processing/memory to create the duplicated nested objects, compared to a shallow copy. It enables true independence between the original and copied objects.
- Languages may provide built-in support for deep copying via copy constructors, clone methods, etc. Alternatively, a manual deep copy requires recursively traversing the object structure to create copies.
Example:
Let's consider a C# code example to demonstrate the concept of Deep copy.
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
[Serializable]
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public override string ToString()
{
return $"Person: {Name}, Age: {Age}";
}
}
class Program
{
static void Main()
{
// Create an instance of the Person class
Person originalPerson = new Person { Name = "Virat", Age = 30 };
// Perform deep copy
Person copiedPerson = DeepCopy(originalPerson);
// Modify the original object
originalPerson.Name = "Virat";
originalPerson.Age = 25;
// Display original and copied objects
Console.WriteLine("Original: " + originalPerson);
Console.WriteLine("Copy: " + copiedPerson);
Console.ReadLine();
}
static T DeepCopy<T>(T obj)
{
using (MemoryStream memoryStream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Context = new StreamingContext(StreamingContextStates.Clone);
formatter.Serialize(memoryStream, obj);
memoryStream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(memoryStream);
}
}
}
Output:
Original: Person: Virat, Age: 25
Copy: Person: Virat, Age: 30