public class A {
public static void f() {
C c = new C();
c.speak();
B b = c;
b.speak();
b = new B();
b.speak();
c.speak();
}
}
public class B {
public void speak() {
System.out.println("moo");
}
}
public class C extends B {
public void speak() {
System.out.println("quack");
}
}
Can you override a static method?
public class A {
public static void f() {
C c = new C();
c.speak();
B b = c;
b.speak();
b = new B();
b.speak();
c.speak();
}
}
public class B {
public void speak() {
System.out.println("moo");
}
}
public class C extends B {
public void speak() {
System.out.println("quack");
}
}
Can you override a static method?
No, because a static method is attached to the class and not a particular instance
public class A {
public static void f() {
C c = new C();
c.speak();
B b = c;
b.speak();
b = new B();
b.speak();
c.speak();
}
}
public class B {
public void speak() {
System.out.println("moo");
}
}
public class C extends B {
@Override
public void speak() {
System.out.println("quack");
}
}
What is the output of A.f() in the following?
What is the output of A.f() in the following?
public class A {
public static void f() {
C c = new C();
c.speak();
B b = c;
b.speak();
b = new B();
b.speak();
c.speak();
}
}
public class B {
public void speak() {
System.out.println("moo");
}
}
public class C extends B {
@Override
public void speak() {
System.out.println("quack");
}
}
c
of type C
C
overrides the speak()
method of B
c.speak() -> "quack"
public class A {
public static void f() {
C c = new C();
c.speak();
B b = c;
b.speak();
b = new B();
b.speak();
c.speak();
}
}
public class B {
public void speak() {
System.out.println("moo");
}
}
public class C extends B {
public void speak() {
System.out.println("quack");
}
}
What is the output of A.f() in the following?
b
of type B
(superclass) and assigns it to object of type C
(subclass) C
"is-a" B
so C
can be assigned to variable of type B
Even though b
is type B
, it still is referring to an object that is type C
What is the output of A.f() in the following?
b
is declared as type B
, the actual type that the variable is referring to is C
.
c.speak()
-> "quack"
public class A {
public static void f() {
C c = new C();
c.speak();
B b = c;
b.speak();
b = new B();
b.speak();
c.speak();
}
}
public class B {
public void speak() {
System.out.println("moo");
}
}
public class C extends B {
public void speak() {
System.out.println("quack");
}
}
What is the output of A.f() in the following?
B
b
no longer refers to type C
and is reassigned to type B
b.speak() -> "moo"
public class A {
public static void f() {
C c = new C();
c.speak();
B b = c;
b.speak();
b = new B();
b.speak();
c.speak();
}
}
public class B {
public void speak() {
System.out.println("moo");
}
}
public class C extends B {
public void speak() {
System.out.println("quack");
}
}
What is the output of A.f() in the following?
c.speak() -> "quack"
public class A {
public static void f() {
C c = new C();
c.speak();
B b = c;
b.speak();
b = new B();
b.speak();
c.speak();
}
}
public class B {
public void speak() {
System.out.println("moo");
}
}
public class C extends B {
public void speak() {
System.out.println("quack");
}
}
public class A {
public static void f() {
C c = new C();
c.speak();
B b = c;
b.speak();
b = new B();
b.speak();
c.speak();
}
}
public class B {
public void speak() {
System.out.println("moo");
}
}
public class C extends B {
public void speak() {
System.out.println("quack");
}
}
What is the output of A.f() in the following?
quack quack moo quack
public class A {
public static void f() {
B b1 = new B();
B b2 = new B();
b1.incX();
b2.incY();
System.out.println(b1.getX() + " " + b1.getY());
System.out.println(b2.getX() + " " + b2.getY());
}
}
public class B {
private int x = 0;
private static int y = 0;
public int getX() {
return x;
}
public int getY() {
return y;
}
public void incX() {
x++;
}
public void incY() {
y++;
}
}
What is the output of A.f() in the following?
public class A {
public static void f() {
B b1 = new B();
B b2 = new B();
b1.incX();
b2.incY();
System.out.println(b1.getX() + " " + b1.getY());
System.out.println(b2.getX() + " " + b2.getY());
}
}
public class B {
private int x;
private static int y;
public int getX() {
return x;
}
public int getY() {
return y;
}
public void incX() {
x++;
}
public void incY() {
y++;
}
}
What is the output of A.f() in the following?
b1: x=1, y=0
b2: x=0, y=0
public class A {
public static void f() {
B b1 = new B();
B b2 = new B();
b1.incX();
b2.incY();
System.out.println(b1.getX() + " " + b1.getY());
System.out.println(b2.getX() + " " + b2.getY());
}
}
public class B {
private int x;
private static int y;
public int getX() {
return x;
}
public int getY() {
return y;
}
public void incX() {
x++;
}
public void incY() {
y++;
}
}
What is the output of A.f() in the following?
b1: x=1, y=1
b2: x=0, y=1
Software development approach which provides an interface for others to use with clear preconditions, postconditions and invariants which, when adhered to, guarantees correct and expected behaviour
What is it?
A contract should address the following 3 conditions:
Defensive Programming
Alternative development approach is defensive programming.
This is where code actively checks and guards against potential unexpected or invalid input (e.g. throwing exceptions)
public class Calculator {
public static Double add(Double a, Double b) {
return a + b;
}
public static Double divide(Double a, Double b) {
return a / b;
}
public static Double sin(Double angle) {
return Math.sin(angle);
}
public static Double tan(Double angle) {
return Math.tan(angle);
}
}
Specify a contract for each function
i.e. preconditions & postconditions
public class Calculator {
/**
* @preconditions a, b != null
* @postconditions a + b
*/
public static Double add(Double a, Double b) {
return a + b;
}
/**
* @preconditions a, b != null, b != 0
* @postconditions a / b
*/
public static Double divide(Double a, Double b) {
return a / b;
}
/**
* @preconditions angle != null
* @postconditions sin(angle)
*/
public static Double sin(Double angle) {
return Math.sin(angle);
}
/**
* @preconditions angle != null, angle != Math.PI / 2
* @postconditions tan(angle)
*/
public static Double tan(Double angle) {
return Math.tan(angle);
}
}
What is it?
Design principle that states subclasses must be substitutable for their superclasses. To be substitutable, the subclass must behave like the superclass.
In this example, Car and Bicycle violate LSP.
But Plane does not violate LSP.
Subclasses must NOT:
In other words, subclass must:
class Bird {
/**
* @precondition height > 5
* @postcondition bird is now flying at that height
*/
public void fly(int height) {
System.out.println("Bird is now flying at " +
height + " metres");
}
}
class Penguin extends Bird {
/**
* @precondition height == 0 (penguins can't fly)
* @postcondition nothing changes to height of bird
*/
@Override
public void fly(int height) {
System.out.println("Penguin is still not flying...");
}
}
Are our postconditions and preconditions being strengthened or weakened?
Preconditions strengthened
Postconditions weakened
Precondition: 0 < theta < 180
Precondition: 0 < theta < 90
Here, we have a subclass that goes against the previous rule, in strengthening the precondition in the subclass.
Precondition: 0 < theta < 180
Precondition: 0 < theta < 90
If we give an input of 150, the input can be accepted by the superclass but NOT the subclass.
So, the subclass is not acting like the superclass.
THIS VIOLATES LSP
This class has 2 attributes and 4 operations.
getBalance()
returns a float
parameter of withDraw()
is of type float
+ Public attribute
- Private attribute
# Protected attribute
Inheritance: "is-a" relationship
Realisation: "implements" relationship
Aggregation: "part of" relationship
Composition: "has-a" relationship
"has-a" relationship
"has-a" relationship
Angle brackets
Italicised
Types of cardinality
Create an OO domain model for a system with the following requirements.
A Car has one or more engines and a producer. The producer is a manufacturing company who has a brand name. Engines are produced by a producer and have a speed. There are only two types of engines within UNSW's cars:
Cars are able to drive to a particular location x, y.
Since UNSW is a world-leader in technology innovation, they want you to be able to model the behaviour of Time Travelling for any vehicle, and to model a time travelling car. A vehicle that travels in time stays in the same location but travels to a LocalDateTime.
Generally, a good diagram maker that is free*
* if you sign up using .edu account
The Wondrous Sequence is generated by the simple rule:
For example, the sequence generated by starting with 3 is:
3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1
If the starting term is 1, then an empty list is returned.
Explore the IDE tools built into VSCode by:
There is a further bug in the function not caught by the given unit test. Find the other bug, and write a corresponding unit test inside WondrousTest.
Checked | Unchecked |
---|---|
Occur at compile time and used for recoverable conditions. Method that uses checked must either be handled (try-catch) or declared in method signature (throws keyword). | Errors in the program's logic which occur at runtime mostly due to programming mistakes. |
Any class that inherits from Exception except RuntimeException is a checked exception. E.g., IOException , SQLException
|
Any class that inherits from RuntimeException is unchecked E.g., ArrayIndexOutOfBoundsExceptions , ArithmeticException
|
import java.io.*;
public class TryCatchExample {
public static void main(String[] args) {
try {
FileReader file = new FileReader("file.txt"); // May throw IOException
file.read();
file.close();
} catch (IOException e) { // Handle the exception
System.out.println("An error occurred while reading the file: " + e.getMessage());
}
}
}
import java.sql.*;
public class ThrowsExample {
public static void connectToDatabase() throws SQLException { // Declaring exception
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "user", "password");
Statement stmt = conn.createStatement();
stmt.executeQuery("SELECT * FROM users"); // May throw SQLException
}
public static void main(String[] args) {
try {
connectToDatabase(); // Must handle or propagate exception
} catch (SQLException e) {
System.out.println("Database connection failed: " + e.getMessage());
}
}
}
try-catch
throws declaration
public class UncheckedExceptionExample {
public static void main(String[] args) {
int num = 10 / 0; // Causes ArithmeticException (unchecked)
}
}
Modify the method such that if a start is less than 1, an IllegalArgumentException is thrown. Write a corresponding test for this inside WondrousTest.
In many cases when we throw an exception we need to update the method signature and existing tests but here we don't - why is this?