Abstract Classes in Java
• An abstract class is declared using the abstract keyword.
• It can contain:
– Abstract methods (without implementation).
– Concrete methods (with implementation).
– Instance variables of any access modifier.
– Private methods (usually as helpers).
• It can define a constructor, which is called when a concrete subclass is instantiated.
• An abstract class can be extended by a non-abstract
class, but the subclass must implement all inherited abstract methods.
• An abstract class can also be extended by another abstract
class, which may leave some abstract methods unimplemented.
Using equals() in Java
Default Behavior
• By default, equals() in Object compares memory addresses (i.e., same as ==).
• Therefore, if a class does not override equals(), it behaves
like reference comparison.
Constructors in Java
Key Facts
• Constructors are not inherited by subclasses.
• If a superclass has a no-argument constructor, the subclass does not need to explicitly call it.
• If the superclass does not have a no-arg constructor, the
subclass must call one of the superclass’s constructors explicitly using super(...).
• A call to super(...) (superclass constructor) must be the
first statement in the subclass constructor.
• If a subclass constructor does not explicitly call
super(...), Java automatically inserts a call to the superclass’s no-arg constructor.
• If a subclass constructor does not explicitly call a superclass constructor, Java will automatically call the default
or no-arg constructor of the superclass just before the code
in the subclass constructor executes.
Method Dispatch in Java
1. Compile-time Check
• At compile time, the compiler checks the declared type
of the variable.
• Only methods defined (or inherited) in the declared type
are allowed to be called.
2. Runtime Dispatch
Correct Usage
• Example with String:
String a = "hello";
String b = new String("hello");
System.out.println(a == b);
//false
System.out.println(a.equals(b)); //true
• At runtime, the actual method executed depends on the
actual type of the object.
• If the method is overridden in the actual type, the overridden version is executed (dynamic binding).
• If the method is not overridden, the implementation from
the declared type (or its superclass) is executed.
3. Key Principle
Overriding equals()
• If you create your own class, override equals() to define
logical equality.
• Typical pattern:
Compile-time: check declared type
Runtime: execute based on actual type.
Method Overriding in Java
• The method in the subclass must have:
@Override
public boolean equals(Object obj) {
– The same method name,
if (this == obj) return true; //same
– The same parameter list,
if (obj == null ||
– The same return type (or a covariant return type),
getClass() != obj.getClass()) return false;
– Compatible access modifier (cannot reduce visibility,
MyClass other = (MyClass) obj;
e.g., from public → private).
return this.field1.equals(other.field1) &&
this.field2 == other.field2;
}
Rules
5. Relationship with hashCode()
• Only instance methods can be overridden (not static,
private, or final methods).
• If you override equals(), you must also override
hashCode().
• The overridden method in the subclass is called automatically at runtime based on the actual type of the object
(dynamic binding).
• Contract: if a.equals(b) is true, then a.hashCode() ==
b.hashCode() must also be true.
• The subclass can call the superclass version using
super.methodName().
Compile-time vs Runtime
– Positive → o1 comes after o2
• Compile-time: Compiler checks that the method exists
in the declared type.
class Person {
String name; int age;
Person(String name, int age) {
• Runtime: JVM executes the overridden method of the
this.name = name;
actual type of the object.
this.age = age; }
}
Java Method Overloading Rules
• The method name must be the same.
• The parameter list must be different:
– Different number of parameters, or
– Different parameter types
• The return type does not matter:
– Methods with the same name and parameter list but
different return type alone are not considered overloaded.
Comparator<Person> ageC = new Comparator<Person>() {
public int compare(Person p1, Person p2) {
return Integer.compare(p1.age, p2.age);
// ascending order by age
}
};
List<Person> people = Arrays.asList(
new Person("Alice", 30),
new Person("Bob", 25)
);
Collections.sort(people, ageC);
Key Points
Type Assignment Rules
• Upcasting (Legal): An object of a subclass can be assigned to a variable of a superclass type. This is always
legal without explicit casting.
• Object Assignment (Legal): Any object can be assigned to a variable of type Object, because all classes
inherit from Object.
• Downcasting (Illegal without explicit cast): A superclass object cannot be assigned to a variable of its subclass
type without an explicit cast. Doing so without a cast is
illegal.
• Unrelated Classes (Illegal): Objects of classes with no
inheritance relationship cannot be assigned to each other.
• Can be passed to ‘Collections.sort()’ or ‘List.sort()’.
• For descending order, simply reverse the comparison or use
‘Comparator.reverseOrder()’.
Sorting Arrays of Objects with Lambda
Person[] people = {
new Person("Alice", 25),
new Person("Bob", 20),
new Person("Tom", 30)
};
\\Sorting by Age (Ascending)
Arrays.sort(people, (p1, p2)
-> Integer.compare(p1.getAge(), p2.getAge()));
\\Sorting by Name (Alphabetical)
• Key Principle: Assignment without explicit casting is
only allowed along inheritance chains, from subclass to su- Arrays.sort(people, (p1, p2)
-> p1.getName().compareTo(p2.getName()));
perclass or to Object.
Custom Sorting with Comparator
• Comparator is used to define custom ordering for objects.
• It is especially useful when the class does not implement
Comparable, or when multiple sorting criteria are needed.
Java Array Sorting Summary
• Primitive type arrays:
– Arrays of primitive types (e.g., int[], double[]) can be
directly sorted.
– Use Arrays.sort(array) for ascending order.
Creating a Comparator
• Implement the Comparator<T> interface.
• Object arrays:
• Override the compare(T o1, T o2) method.
– Can only be directly sorted if the objects implement
Comparable<T>.
• Return value rules:
– The object’s compareTo() method defines the natural
order.
– Negative → o1 comes before o2
– Zero → o1 equals o2
– Arrays.sort(personArray); if Person implements
Comparable<Person>.