Example Notes
These notes were generated from a recording of Daniel Kluver's CSCI 1913 class held on November 3rd, 2021.
Download Raw MarkdownPost-Lecture Note Sheet
Overview
This lecture focused on object-oriented programming concepts, specifically the implementation of the equals method in Java, understanding how to design classes for inheritance, and using abstract classes. We explored practical implications with examples, particularly in a veterinary clinic context with a Cat
class.
Equals Method in Java
Definition
The equals method is used to compare two objects to determine if they are logically equivalent. In Java, this method is inherited from the Object
class and must be overridden in your class.
Implementation Steps
-
Method Signature
- The method signature must be
public boolean equals(Object obj)
. The parameter type must beObject
, as this maintains the contract of theequals
method inherited fromObject
.
- The method signature must be
-
Same Object Check
- The first check should be to see if the current object is being compared to itself:
if (this == obj) { return true; }
- The first check should be to see if the current object is being compared to itself:
-
Null Check
- Check if the provided object is null:
if (obj == null) { return false; }
- Check if the provided object is null:
-
Type Check
- Use the
instanceof
operator to verify that obj is of the correct type (e.g.,Cat
):if (!(obj instanceof Cat)) { return false; }
- Use the
-
Type Casting
- Cast the object to the correct type:
Cat other = (Cat) obj;
- Cast the object to the correct type:
-
Field Comparison
- Compare relevant fields for equality (e.g., age, weight, name):
return this.age == other.age && this.weight == other.weight && this.name.equals(other.name) && this.owner.equals(other.owner);
- Compare relevant fields for equality (e.g., age, weight, name):
Example
Here is an example implementation of the equals
method in a Cat
class:
public class Cat {
private String name;
private int age;
private double weight;
private String owner;
public Cat(String name, int age, double weight, String owner) {
this.name = name;
this.age = age;
this.weight = weight;
this.owner = owner;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || !(obj instanceof Cat)) {
return false;
}
Cat other = (Cat) obj;
return this.age == other.age &&
Math.abs(this.weight - other.weight) < 0.01 &&
this.name.equals(other.name) &&
this.owner.equals(other.owner);
}
// Other methods like getters and setters...
}
Designing for Inheritance
Purpose of Inheritance
Inheritance allows a class (child or subclass) to inherit fields and methods from another class (parent or superclass). This promotes code reuse and establishes a relationship between classes.
Key Concepts
-
Child Class Responsibilities
- A child class can inherit common properties from its parent class but also must implement or override its own behaviors where necessary.
-
Encapsulation in Inheritance
- Use private fields in parent classes to protect the data and expose only what is necessary through public or protected methods.
-
Protected Methods
- Defined as
protected
, these methods can be accessed and modified by subclasses, allowing them to customize functionality without compromising encapsulation.
- Defined as
Example Structure
Consider a Greeter
class as a parent class that could have various types of greeters (e.g., casual, formal, or specific language types).
public abstract class Greeter {
protected String name;
public Greeter(String name) {
this.name = name;
}
public abstract String greet();
}
public class CasualGreeter extends Greeter {
public CasualGreeter(String name) {
super(name);
}
@Override
public String greet() {
return "Hey, " + name + "!";
}
}
public class FormalGreeter extends Greeter {
public FormalGreeter(String name) {
super(name);
}
@Override
public String greet() {
return "Good day, " + name + ".";
}
}
Abstract Classes
Role and Characteristics
-
Purpose:
- Abstract classes serve as templates that define attributes and methods that must be implemented by derived classes.
-
Defining Abstract Classes:
- Use the
abstract
keyword in both the class declaration and for methods that do not have a body:public abstract class Shape { public abstract double area(); }
- Use the
-
Instantiation:
- Abstract classes cannot be instantiated directly. You can create instances of subclasses that implement the abstract methods.
-
Method Implementation:
- Subclasses must provide implementations for all abstract methods unless they themselves are abstract.
Example
Here's an abstract class representing a Shape
with specific geometrical shapes extending it:
public abstract class Shape {
public abstract double area();
}
public class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
}
public class Rectangle extends Shape {
private double width;
private double height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public double area() {
return width * height;
}
}
Conclusion
This lecture emphasized the importance of precise implementation when overriding methods in Java, especially the equals
method, and the structuring of classes for efficient inheritance and polymorphism. Understanding these principles prepares you for crafting robust Java applications and future projects.
Next Steps
- Complete your assignments reflecting these concepts.
- Prepare for next lecture, which will focus on further examples and practical implementations related to the use of abstract classes and polymorphism in Java.