toString()
and equals()
In Java, it is possible to inherit attributes and methods from one class to another.
Shape
Rectangle
Circle
super class
sub classes
package shapes;
public class Shape {
public String color;
public Shape(String color) {
System.out.println("Inside Shape constructor");
this.color = color;
}
}
public class Rectangle extends Shape {
public int height;
public int width;
public Rectangle(String color) {
super(color);
System.out.println("Inside Rectangle constructor with one argument");
}
public Rectangle(String name, int width, int height) {
this(name);
this.width = width;
this.height = height;
System.out.println("Inside Rectangle constructor with three arguments");
}
public static void main(String[] args) {
Rectangle r = new Rectangle("red", 10, 20);
System.out.println(r.color);
System.out.println(r.width);
System.out.println(r.height);
}
}
Shape.java
Rectangle.java
package shapes;
public class Shape {
public String color;
public Shape(String color) {
System.out.println("Inside Shape constructor");
this.color = color;
}
}
public class Rectangle extends Shape {
public int height;
public int width;
public Rectangle(String color) {
super(color);
System.out.println("Inside Rectangle constructor with one argument");
}
public Rectangle(String name, int width, int height) {
this(name);
this.width = width;
this.height = height;
System.out.println("Inside Rectangle constructor with three arguments");
}
public static void main(String[] args) {
Rectangle r = new Rectangle("red", 10, 20);
System.out.println(r.color);
System.out.println(r.width);
System.out.println(r.height);
}
}
Shape.java
Rectangle.java
super
vs. this
package shapes;
public class Shape {
public String color;
public Shape(String color) {
System.out.println("Inside Shape constructor");
this.color = color;
}
}
public class Rectangle extends Shape {
public int height;
public int width;
public Rectangle(String color) {
super(color);
System.out.println("Inside Rectangle constructor with one argument");
}
public Rectangle(String color, int width, int height) {
this(color);
this.width = width;
this.height = height;
System.out.println("Inside Rectangle constructor with three arguments");
}
public static void main(String[] args) {
Rectangle r = new Rectangle("red", 10, 20);
System.out.println(r.color);
System.out.println(r.width);
System.out.println(r.height);
}
}
Shape.java
Rectangle.java
super
vs. this
package shapes;
public class Shape {
public String color;
public Shape(String color) {
System.out.println("Inside Shape constructor");
this.color = color;
}
}
public class Rectangle extends Shape {
public int height;
public int width;
public Rectangle(String color) {
super(color);
System.out.println("Inside Rectangle constructor with one argument");
}
public Rectangle(String color, int width, int height) {
this(color);
this.width = width;
this.height = height;
System.out.println("Inside Rectangle constructor with three arguments");
}
public static void main(String[] args) {
Rectangle r = new Rectangle("red", 10, 20);
System.out.println(r.color);
System.out.println(r.width);
System.out.println(r.height);
}
}
Shape.java
Rectangle.java
super
vs. this
Shape.java
Rectangle.java
public class Rectangle extends Shape {
public int height;
public int width;
public Rectangle(String color) {
super(color);
System.out.println("Inside Rectangle constructor with one argument");
}
public Rectangle(String color, int width, int height) {
this(color);
this.width = width;
this.height = height;
System.out.println("Inside Rectangle constructor with three arguments");
}
public static void main(String[] args) {
Rectangle r = new Rectangle("red", 10, 20);
System.out.println(r.color);
System.out.println(r.width);
System.out.println(r.height);
}
}
package shapes;
public class Shape {
public String color;
public Shape(String color) {
System.out.println("Inside Shape constructor");
this.color = color;
}
}
super
vs. this
public class Shape {
public String color;
public Shape(String color) {
System.out.println("Inside Shape constructor");
this.color = color;
}
}
public class Rectangle extends Shape {
public int height;
public int width;
public Rectangle(String color) {
super(color);
System.out.println("Inside Rectangle constructor with one argument");
}
public Rectangle(String color, int width, int height) {
this(color);
this.width = width;
this.height = height;
System.out.println("Inside Rectangle constructor with three arguments");
}
public static void main(String[] args) {
Rectangle r = new Rectangle("red", 10, 20);
}
}
What will the main
code in Rectangle
print and why?
Shape.java
Rectangle.java
super
vs. this
public class Shape {
public String color;
public Shape(String color) {
System.out.println("Inside Shape constructor");
this.color = color;
}
}
public class Rectangle extends Shape {
public int height;
public int width;
public Rectangle(String color) {
super(color);
System.out.println("Inside Rectangle constructor with one argument");
}
public Rectangle(String color, int width, int height) {
this(color);
this.width = width;
this.height = height;
System.out.println("Inside Rectangle constructor with three arguments");
}
public static void main(String[] args) {
Rectangle r = new Rectangle("red", 10, 20);
}
}
What will the main
code in Rectangle
print and why?
Shape.java
Rectangle.java
super
vs. this
Inside Shape constructor
Inside Rectangle constructor with one argument
Inside Rectangle constructor with three arguments
public abstract class Shape {
private String colour;
// Only one variable for all Shape objects
private static int count = 0;
public Shape(String colour) {
System.out.println("Inside Shape constructor");
this.colour = colour;
count++;
}
public void setColour(String colour) {
this.colour = colour;
}
public String getColour() {
return colour;
}
public static int getCount() {
return count;
}
public abstract int getArea();
}
public abstract class Shape {
private String colour;
// Only one variable for all Shape objects
private static int count = 0;
public Shape(String colour) {
System.out.println("Inside Shape constructor");
this.colour = colour;
count++;
}
public void setColour(String colour) {
this.colour = colour;
}
public String getColour() {
return colour;
}
public static int getCount() {
return count;
}
public abstract int getArea();
}
public abstract class Shape {
private String colour;
// Only one variable for all Shape objects
private static int count = 0;
public Shape(String colour) {
System.out.println("Inside Shape constructor");
this.colour = colour;
count++;
}
public void setColour(String colour) {
this.colour = colour;
}
public String getColour() {
return colour;
}
public static int getCount() {
return count;
}
public abstract int getArea();
}
Rectangle r2 = new Square("blue", 20);
What is happening here?
How can we assign an instance of Square
to Rectangle
?
r2
can store any object that is Rectangle
or subclass of Rectangle
(i.e. Square
)
Rectangle
) but still use specific subtypes (Square
) behind the scenesRectangle r2 = new Square("blue", 20);
At compile time, Java only knows r2
as Rectangle
:
Rectangle
(or superclass)Square
At runtime:
r2
is actually pointing to a Square
in memoryRectangle
but this is overridden at runtime using the Square
implementationThis is called DYNAMIC DISPATCH
// Since in memory r2 is of type Square,
// this will run Square implementation of printMessage()
r2.printMessage();
/**
* File class that stores content under a file name
*/
public class File {
/**
* Constructor used to create a file
* @param fileName the name of the file
* @param content contents of the file
*/
public File(String fileName, String content) {}
/**
* Constructor used to make a partial file when receiving a new file
* I.e., content.length() != fileSize with no compression
* @param fileName
* @param fileSize
*/
protected File(String fileName, int fileSize) {}
/**
* Checks if transfer has been completed
* @return true if it has been completed
*/
public boolean hasTransferBeenCompleted() {}
}
VSCode Extensions
Employee
Manager
Manager is-a Employee
But not all Employees are Managers
toString()
returns a string that "textually represents" the object. This is useful for easily viewing data inside the class and for debugging.
toString()
is inherited from the Object class which means all classes can override toString()
Default implementation
Contains the class name and hash code for the instance
Overriden Implementation
Contains the class name and now the attributes of the class and its values
toString()
returns a string that "textually represents" the object. This is useful for easily viewing data inside the class and for debugging.
toString()
is inherited from the Object class which means all classes can override toString()
equals()
Compares whether the contents of two instances are equal
equals()
is similar to strcmp(
) in C which comparing the contents of stringsequals()
vs. ==
equals() | == |
---|---|
A method defined in Object class | An operator |
Compares if two objects are meaningfully equivalent (i.e. same class, same attributes) | Compares references (memory addresses) and primitive data types (i.e. int, char, boolean, float, etc.) |
equals()
What is the relationship between a super type and a sub type in terms of equality? Can a concrete instance of an Employee be equal to an instance of a Manager?
equals()
What is the relationship between a super type and a sub type in terms of equality? Can a concrete instance of an Manager be equal to an instance of a Employee?
Although a subclass can be treated as its super class, they are not equal. A subtype is more specific version and so cannot be treated as equal to its supertype.
Manager is more specific version than Employee with additional fields.
The abstract class is a class that cannot be instantiated and is meant to be subclassed.
It can have abstract methods (methods without a body) that must be implemented by subclasses, as well as concrete methods (methods with body).
// Abstract class Shape (acts as a blueprint)
abstract class Shape {
String name;
// Constructor
public Shape(String name) {
this.name = name;
}
// Abstract method (must be implemented by subclasses)
abstract double area();
// Concrete method (can be used by all shapes)
public void display() {
System.out.println("This is a " + name);
}
}
class Circle extends Shape {
double radius;
public Circle(double radius) {
super("Circle");
this.radius = radius;
}
@Override
double area() {
return Math.PI * radius * radius;
}
}
Abstract class
Subclasses
class Rectangle extends Shape {
double width, height;
public Rectangle(double width, double height) {
super("Rectangle");
this.width = width;
this.height = height;
}
@Override
double area() {
return width * height;
}
}
Think of an abstract class as a class that gives a basic structure but leaves some details for subclasses to fill in.
For example...
You are designing a template of different animals. Every animal makes a sound, but the exact sound depends on the specific animal. Instead of defining a general sound, we create an abstract class that forces each specific animal to define its own sound.
woof
meow
Interfaces define a set of methods that a class must implement, but do not provide the actual implementation of these methods.
Think of interfaces like a contract - if a class agrees to follow it, it must provide its own versions of methods specified in the interface.
class Rectangle extends Shape implements Drawable {
double width, height;
public Rectangle(double width, double height) {
super("Rectangle");
this.width = width;
this.height = height;
}
@Override
double area() {
return width * height;
}
@Override
public void draw() {
System.out.println("Drawing a Rectangle with width "
+ width + " and height " + height);
}
}
// Drawable interface
interface Drawable {
void draw();
}
Abstract Class | Interface |
---|---|
Can store state (attributes) | Cannot store state |
Can have both concrete and abstract methods | All methods are abstract by default |
Classes can inherit from only one abstract class | A class can implement multiple interfaces |
Mostly used for inheritance (subclass/superclass), think of nouns (e.g. Dog -> Labrador ) |
Mostly used for functionality/behaviours, think of verbs (Flyable , Drawable ) |
public class Circle {
int a; // Default
private int b; // Private
protected int c; // Protected
public int d; // Public
}