Outline
- Review
- JUnit Tests
- Javadoc
- Inheritance
- UML
Reminders
Classes
- The purpose of a class is to maintain the consistent state of its members.
- Public methods take an instance from one consistent state to the next.
- IS-A, HAS-A, RESPONDS-TO
Constructors
- constructors: initialize a new instance
public Balloon(){ }
- new and constructors
new Balloon(); // create and initialize a new Balloon
- Can also have one constructor call another, see overloading below
References
- A Reference holds the address of an instance
- A reference is NOT the instance
- Speed Dial analogy (no Inheritence)
- The VALUE of a reference is the address it holds
- a=b calculated by computing the VALUE of the right side and placing it in the left
- Java is pass by VALUE
- Java occasionally garbage collects instances that have no references to them.
Balloon b1=null; // no Balloons exist, we have 1 reference to Balloon
// b1 is of type Reference to Balloon
// b1 holds the address of a Balloon (or it will)
// b1.inflate(5); // gets null pointer exception
// Exception in thread "main" java.lang.NullPointerException
// at Balloon.main(Balloon.java:8)
new Balloon(); // Call first constructor
// One new Balloon is created, but no one can talk to it, we lost its phone number
b1 = new Balloon(20, "green");
System.out.println(b1.toString());
System.out.println(b1); // Same as above, default call to toString
Balloon b2 = new Balloon(30, "blue"); // All in one line:
Array of References
Balloon [] ba; // Reference to (array of reference to Balloon)
// No array of reference to Balloon exists yet!!!
ba = new Balloon[10]; // now have an array of 10 reference to Balloon
// no new Balloon created!!!
// Notice ba[0], ..., ba[9] all have type reference to Balloon
for(int i=0; i
Overloading
- many methods with the same name, different signatures
- Can overload methods
/**
* Inflate to capacity
*/
public void inflate(){
this.inflate(this.capacity-this.amount);
}
/**
* inflate the specified amount
*/
public void inflate(int amount){
...
}
- overload constructors
// initialize a default Balloon with capacity=10, colour="red"
public Balloon(){
this(10,"red"); // must be first line in constructor
}
// initialize a Balloon with the specified capacity and colour
public Balloon(int capacity, String colour){
...
}
Protection
/**
* Modifier Class Package Subclass World
* public Y Y Y Y
* protected Y Y Y N
* no modifier Y Y N N
* private Y N N N
**/
- Rule of thumb: instance variables are private. Some methods are public.
Javadoc
- a tool for automatically generating documentation from well-commented source code
- Doc goes before method, or top of class.
- Use special
/** */ comments
- Use special annotations @param, @return
- Example:
/**
* Add amount to this, if balloon exceeds capacity, then this is popped
*
* @param amount the amount to be added to this, must be positive
* @return the amount actually added to this
*/
public int inflate(int amount) {
...
}
-
javadoc -d doc *.java
- Example: javadoc for Balloon
- Example: Java 22 API
- How to Write Doc Comments for the Javadoc Tool
Static
- static things are part of the class not part of any instance
- one of each static thing for the class, no matter how many instances
private static int numCreated = 0;
private static int numPopped = 0;
public Balloon(int capacity, String colour){
Balloon.numCreated ++; // look in class
...
}
public static void printPopulation(){
System.out.println("numCreated="+numCreated);
System.out.println("numPopped="+numPopped);
// System.out.println("capacity="+this.capacity); // can't reference from a static context
}
Search for Names in a Single Class
- Search here (in this method)
- Search instance
- Search class (static)
Modifying search
- No modifier: here then instance then class:
amount, amount could be a local
- this: instance then class:
this.amount, amount could be an instance var or static var
- class name: class:
Balloon.numCreated, static numCreated, on the bulletin board
Misc
- toString(): return a String representation of this
Unit Testing
- takes less time to unit test than to debug
- can make changes to code confidently, change and then test
- forces thought on inputs and outputs of code
- identifies location of problems should they arise
- TDD: Test driven development = write test cases first then code
- Motivating: Yes!! Green light!
JUnit
See: JUnit 5
and the JUnit 5 api
- Each method in a Unit Test can be labelled with @BeforeEach @BeforeAll, @Test, @AfterEach, @AfterAll
- Each Unit Test has many test cases, and for each test case:
- @BeforeEach: do some setup/prep work e.g., open a file, open a network connection.
- @Test: run the test case.
- @AfterEach: clean up after the test finishes, e.g., closing the file, close the connection.
- It's BTA, BTA, BTA, ... , not BTTTTTTTTA
- In total Ba (Be T Ae) (Be T Ae) (Be T Ae) (Be T Ae) Aa
- During a test, you make
assertions
- Example: BalloonTest.java
- Additional Reading: junit.org,
assertions
Inheritance in Java
- HAS-A instance variables
- RESPONDS-TO methods
- IS-A inheritance,
extends
public class Cat extends Animal {
...
}
// Cat is a subclass of Animal, child class
// Animal is the superclass of Cat, parent of Cat
- Object is the base class, is the superclass of all classes.
- Each class (other than Object) has exactly one superclass. This is single inheritance. Other languages have multiple inheritance.
- So all Java classes form a Tree with Object as root.
Search for Method Names (again)
- Important Search starts at the class of the instance
and moves up towards Object.
If I call my friend, who is a Doctor, they answer
Dr. Smith, even though I may have placed them in
the friend section of my phone book.
- To start search at the superclass (parent) use super.method()
- To use super class (parents) constructor use super(arguments)
- You can not directly access super super class things
Search for Variables (again)
- Important Search starts at the method
that is executing and moves up towards Object.
It does not care which class the method is executing
on.
- To start search at the super class (parent) use super.variable
- You can not directly access super super class things
Overriding and Shadowing
- Overriding: same method name and signature exists in subclass
- Prevent overriding of method by declaring it final
- Shadowing: same variable name and type exists in subclass
Abstract Classes
- contains abstract methods that are NOT implemented
- may also contain implemented methods
- may contain variables
- CANNOT be instantiated , because it is not "concrete".
- A class can extend (inherit from) an abstract class and implement the abstract methods, then CAN be instantiated.
- A child class of an abstract class can still be abstract.
- Example:
public abstract class Shape {
public abstract double getArea();
public abstract double getPerimeter();
}
Who Inherits from Whom?
Question:
What should the relationship be between the following classes?
Shape
Circle
Rectangle
Square
Liskov Substitution Principle (LSP):
"Objects of subtypes should behave like those of supertypes if used via supertype methods."
Functions that use references to parent classes must be able to use objects of child classes without knowing it. In other words, methods in the parent class must make total sense for the child class.
If Square is a subclass of Rectangle, then Rectangle setWidth() and setHeight() methods do NOT make sense for Square. Violating LSP.
Square should directly inherit from Shape.
On stack overflow
UML
- Unified Modeling Language (UML) allows us to express the design of a program before writing any code.
- It is language-independent.
- An extremely expressive language.
- We will use only a small part of the language, Class Diagrams, to represent basic OO design.
UML Class Notation
- Methods have name and parameter types
- Visibility:
+ public
- private
# protected
~ package
- Different types of classes:
Regular class: A
Interface: <> A
Abstract class: <> A
- Static: underline
- Arrows:
- Extends:
- Implements:
- Association:
- Dependency:
The difference between the Dependency arrow and Association arrow in a UML diagram?
Association is for when an instance itself holds onto a reference to another class. Dependency is when some method is handed an instance of the other class to temporarily communicate with, or when a method creates an instance of the other class. So the idea is that the connection to the other class is temporary. See, for example this or this.
- What should I be able to do?
Understand the language of Design Patterns as in