ProMind
SearchFor TeachersFor Parents
ProMind
Privacy PolicyTerms of ServiceRefund Policy

© 2025 DataGrid Softwares LLP. All rights reserved.

    Methods Common to All Objects

    Flashcards for topic Methods Common to All Objects

    Intermediate61 cardsGeneral

    Preview Cards

    Card 1

    Front

    How should you properly compare float and double fields in an equals() method and why is special handling required?

    Back

    Float and double fields require special handling due to special values like NaN, -0.0f, +0.0f, etc.

    Correct way to compare:

    • For float: Use static Float.compare(float, float) method
    • For double: Use static Double.compare(double, double) method

    Example:

    @Override public boolean equals(Object o) { // other code... // DON'T do this: // return this.doubleField == otherObj.doubleField; // DO this instead: return Double.compare(this.doubleField, otherObj.doubleField) == 0; }

    Note: While you could use Float.equals() or Double.equals(), this causes autoboxing on every comparison, hurting performance.

    Card 2

    Front

    Write a proper equals method for a Point class that allows correct behavior with subclasses and explain why this approach works.

    Back

    public class Point { private final int x; private final int y; public Point(int x, int y) { this.x = x; this.y = y; } @Override public boolean equals(Object o) { // Use instanceof not getClass to allow proper subclass behavior if (!(o instanceof Point)) return false; // Cast to Point (works with all subclasses too) Point p = (Point) o; // Compare only the relevant fields for Point return p.x == x && p.y == y; } // Don't forget to override hashCode() as well }

    This implementation works because:

    1. It uses instanceof which allows subclasses to be equal to Points
    2. It only compares the fields defined in Point, maintaining the LSP
    3. Subclasses of Point will still function correctly in collections that rely on equals
    4. Proper inheritance hierarchy is maintained while allowing for substitutability
    Card 3

    Front

    What is a "value class" in Java and when should you override equals for such classes?

    Back

    A value class:

    • Is a class that represents a value (like Integer, String, or Date)
    • Contains state that defines what it is, rather than who it is
    • Is typically immutable
    • Should be compared based on logical equivalence, not object identity

    You should override equals for a value class when:

    1. The class has a notion of logical equality that differs from mere object identity
    2. A superclass has not already overridden equals in an appropriate way
    3. You want instances to work properly as map keys or set elements

    Examples of value classes that need equals overridden:

    • Money class representing an amount and currency
    • Complex number class with real and imaginary parts
    • Date class representing a specific day
    • Address class with street, city, state fields

    Exception: Value classes that use instance control (ensuring at most one instance exists per value, like Enum types) don't need to override equals because object identity already provides logical equality.

    Proper equals implementation enables users to compare objects as expected and allows collections to work correctly with your class.

    Card 4

    Front

    Explain the problem of "mixed-type comparison" in equals methods and why attempting to interoperate with other types often fails.

    Back

    Mixed-type comparisons in equals methods typically fail because:

    1. Symmetry violations: If class A knows about class B but not vice versa:

      // CaseInsensitiveString attempting to interoperate with String cis.equals(string) // returns true string.equals(cis) // returns false (String doesn't know about CaseInsensitiveString)

      This breaks the symmetry requirement: x.equals(y) must return the same as y.equals(x)

    2. Transitivity violations: When mixed comparisons ignore components:

      colorPoint1.equals(point) // ignores color → true point.equals(colorPoint2) // point doesn't check color → true colorPoint1.equals(colorPoint2) // checks color → false if colors differ

      This breaks transitivity: if a equals b and b equals c, then a must equal c

    3. Infinite recursion risk: When two unrelated subclasses try to interoperate:

      // If both implement "mixed comparison" handling: colorPoint.equals(smellPoint) // calls smellPoint.equals(colorPoint) // which
    Card 5

    Front

    Why is the number 31 typically used as the multiplier in hashCode() implementations, and what properties make it effective?

    Back

    The number 31 is commonly used in hashCode() implementations because:

    1. It's an odd prime number (important properties):

      • Being odd ensures that if multiplication overflows, information isn't lost (unlike even multipliers where multiplication by 2 is equivalent to shifting)
      • Being prime helps with distribution of hash values, though this advantage is less clearly established
    2. Performance optimization:

      • Multiplication by 31 can be optimized by modern JVMs using a bitshift and subtraction:
      • 31 * i == (i << 5) - i
      • This makes calculations faster on many architectures
    3. Historical precedent:

      • Traditional usage in many Java standard library classes
      • Empirically produces good distribution of hash values for common data

    This choice helps create hash functions that distribute values evenly across buckets in hash tables.

    Card 6

    Front

    What problem occurs when significant fields are excluded from a hashCode() implementation to improve performance?

    Back

    Excluding significant fields from hashCode() creates:

    • Poor quality hash functions that may map many distinct instances to the same hash code
    • Hash table performance degradation to the point of becoming unusable (quadratic time instead of linear)
    • "Hash collisions" for collections of instances that differ mainly in the ignored regions
    • Pathological behavior for hierarchical names (as seen in pre-Java 2 String hash function)

    Example: When a pre-Java 2 String hash function only used 16 evenly spaced characters, URLs with similar patterns would all hash to the same bucket.

    Card 7

    Front

    Why is using Objects.hash() for implementing hashCode() problematic in performance-critical code?

    Back

    Objects.hash() causes performance issues because:

    • It requires creation of an array to pass variable arguments
    • It performs boxing of primitive types to their wrapper classes
    • Requires unboxing if any arguments are primitive types
    • The array creation and boxing/unboxing create garbage collection pressure

    Example of the slower but convenient implementation:

    @Override public int hashCode() { return Objects.hash(lineNum, prefix, areaCode); }

    When performance is critical, manually compute the hash code using the multiplication by prime approach instead.

    Card 8

    Front

    What are the proper steps for implementing clone() in a class that contains mutable object references?

    Back

    To properly implement clone() with mutable object references:

    1. Call super.clone() to get a baseline shallow copy
    2. Identify all mutable object fields that need deep copying
    3. Create new instances of those mutable objects
    4. Perform a deep copy of each mutable field (which may require recursive cloning)
    5. Assign the newly created copies to the clone's fields
    6. Return the modified clone

    Example for a Stack class:

    @Override public Stack clone() { try { Stack result = (Stack) super.clone(); // Deep copy of mutable array field result.elements = elements.clone(); return result; } catch (CloneNotSupportedException e) { throw new AssertionError(); // Can't happen } }

    Note: If the mutable objects themselves contain references to other mutable objects, those would need to be cloned as well in a recursive manner.

    Card 9

    Front

    What are the alternative approaches to object copying that are preferable to implementing the Cloneable interface, and what specific advantages do they offer?

    Back

    Better alternatives to Cloneable:

    1. Copy Constructor:

      public Yum(Yum original) { this.field1 = original.field1; this.field2 = new ArrayList<>(original.field2); // Deep copy if needed // Copy remaining fields }
    2. Static Copy Factory:

      public static Yum newInstance(Yum original) { Yum copy = new Yum(); copy.field1 = original.field1; copy.field2 = new ArrayList<>(original.field2); return copy; }

    Advantages over Cloneable/clone:

    • No dependence on error-prone extralinguistic object creation mechanism
    • No need to catch checked exceptions
    • No reliance on conventions that can't be enforced
    • No conflicts with final fields
    • No requirement for casting
    • Can accept interfaces as parameters (conversion constructors/factories)
    • Allow choosing implementation type of copy (e.g., copy HashSet to TreeSet)
    • More clearly express intent in code

    Exception: Arrays are best copied with clone() method.

    Card 10

    Front

    What should a class designed for inheritance do regarding the Cloneable interface, and what are the two implementation strategies to handle this situation?

    Back

    For a class designed for inheritance, do not implement Cloneable. Instead, choose one of these strategies:

    Strategy 1: Allow subclasses to choose whether to implement Cloneable

    // Mimics Object's behavior for subclasses @Override protected Object clone() throws CloneNotSupportedException { if (!(this instanceof Cloneable)) { throw new CloneNotSupportedException(); } // Perform proper cloning if subclass implements Cloneable return super.clone(); }

    This gives subclasses the freedom to implement Cloneable or not, just as if they extended Object directly.

    Strategy 2: Prevent subclasses from implementing Cloneable

    // Prevents any subclass from implementing functional cloning @Override protected final Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); }

    This completely blocks the Cloneable mechanism for all subclasses.

    Either approach is better than implementing Cloneable in a superclass and forcing that design choice on all subclasses.

    Showing 10 of 61 cards. Add this deck to your collection to see all cards.