diff --git a/core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/objectclassguide/Car.java b/core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/objectclassguide/Car.java new file mode 100644 index 000000000000..37978a5b9076 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-types/src/main/java/com/baeldung/objectclassguide/Car.java @@ -0,0 +1,78 @@ +package com.baeldung.objectclassguide; + +import java.util.Objects; + + +/** + * Represents a car object, implementing Cloneable and overriding Object methods. + * + * The class uses standard implementation for equals(), hashCode(), and toString(). + * The clone() method performs a shallow copy, which is sufficient since 'make' (String) + * and 'year' (int) are immutable or primitive. + */ +public class Car implements Cloneable { + private String make; + private int year; + + + public Car(String make, int year) { + this.make = make; + this.year = year; + } + + + // Getters for external access (useful for testing) + public String getMake() { + return make; + } + + + public int getYear() { + return year; + } + + + /** + * Standard implementation of equals() for value equality. + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Car car = (Car) obj; + // Use Objects.equals for safe String comparison + return year == car.year && Objects.equals(make, car.make); + } + + + /** + * Standard implementation of hashCode() based on make and year. + */ + @Override + public int hashCode() { + return Objects.hash(make, year); + } + + + /** + * Standard implementation of toString() for debugging and logging. + */ + @Override + public String toString() { + return "Car{" + + "make='" + make + '\'' + + ", year=" + year + + '}'; + } + + + /** + * Overrides the protected clone() method from Object to perform a shallow copy. + * This is the standard pattern when implementing the Cloneable marker interface. + */ + @Override + public Object clone() throws CloneNotSupportedException { + // Calls Object's native clone() method + return super.clone(); + } +} diff --git a/core-java-modules/core-java-lang-oop-types/src/test/java/com/baeldung/objectclassguide/CarObjectUnitTests.java b/core-java-modules/core-java-lang-oop-types/src/test/java/com/baeldung/objectclassguide/CarObjectUnitTests.java new file mode 100644 index 000000000000..7f4e7642d9e8 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-types/src/test/java/com/baeldung/objectclassguide/CarObjectUnitTests.java @@ -0,0 +1,92 @@ +package com.baeldung.objectclassguide; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; + +public class CarObjectUnitTests { + + @Test + void givenACarObject_whenTestingObjectEqualsItself_thenEqualsReflexive() { + Car car1 = new Car("Honda", 2020); + assertTrue(car1.equals(car1)); + } + + @Test + void givenTwoCarObjects_whenTestingSymmetric_thenEqualsSymmetric() { + Car car1 = new Car("Honda", 2020); + Car car2 = new Car("Honda", 2020); + assertTrue(car1.equals(car2)); + assertTrue(car2.equals(car1)); + } + + @Test + void givenThreeCarObjects_whenTestingTransitive_thenEqualsTransitive() { + Car car1 = new Car("Honda", 2020); + Car car2 = new Car("Honda", 2020); + Car car3 = new Car("Honda", 2020); + + assertTrue(car1.equals(car2)); + assertTrue(car2.equals(car3)); + assertTrue(car1.equals(car3)); + } + + @Test + void givenTwoDifferentCarObjects_whenComparingWithEquals_thenEqualsReturnsFalse() { + Car car1 = new Car("Honda", 2020); + Car car2 = new Car("Toyota", 2020); + + assertFalse(car1.equals(car2)); + } + + @Test + void givenANonNullCarObject_whenTestingAgainstNull_thenEqualsReturnsFalse() { + Car car1 = new Car("Honda", 2020); + + assertFalse(car1.equals(null)); + } + + @Test + void givenTwoEqualCarObjects_whenComparingHashCodes_thenReturnsEqualHashCodes() { + Car car1 = new Car("Honda", 2020); + Car car2 = new Car("Honda", 2020); + + assertEquals(car1.hashCode(), car2.hashCode()); + } + + @Test + void givenACarObject_whenTestingHashCodeConsistency_thenReturnsSameHashCodeAcrossMultipleCalls() { + Car car = new Car("Honda", 2020); + int initialHash = car.hashCode(); + + assertEquals(initialHash, car.hashCode()); + } + + @Test + void givenACarObject_whenTestingToString_thenReturnsExpectedString() { + Car car = new Car("Tesla", 2023); + String expected = "Car{make='Tesla', year=2023}"; + + assertEquals(expected, car.toString()); + } + + @Test + void givenACarObject_whenTestingGetClass_thenReturnsCarClass() { + Car car = new Car("Ford", 2015); + + assertEquals(Car.class, car.getClass()); + } + + @Test + void givenACarObject_whenTestingClone_thenCloneSuccess() throws CloneNotSupportedException { + Car original = new Car("Honda", 2020); + Car cloned = (Car) original.clone(); + + assertNotSame(original, cloned); + assertEquals(original, cloned); + assertEquals(original.getMake(), cloned.getMake()); + assertEquals(original.getYear(), cloned.getYear()); + } +}