Java Exam Notes
Java Exam Notes
import java.util.Scanner;
switch (caseValue) {
case 1:
// Code to handle x > y/2
break;
case 0:
// Code to handle x <= y/2
break;
default:
// Default case
}
MISSING INITIALISATIONS AND FOR-LOOP
import java.util.Scanner;
* continue ends execution early and goes to the next iteration of the loop
* different to break which ends the entire loop
STORED BY REFERENCE
public class BankExample3 {
public static void main(String[] args) {
BankAccount account1, account2;
account1 = new BankAccount();
account2 = account1; // Same object
account1.ownerName = "Donald Knuth";
account1.balance = 1000;
account1.balance -= 15;
System.out.println(account1.ownerName + " has $" + account1.balance);
System.out.println(account2.ownerName + " has $" + account2.balance);
}
}
* Non-primitive variables store references -> hence default value for variable storing object is null
* objects (instance of a class) are stored by reference
• account1 and account2 store a reference to the object, not the object itself
ARRAYS
* JAGGED ARRAY -> arr = new type[x][]
• Arrays can be initialised with specific values -> String[] names = {"Donald", "Alan"}; int[][]
myArray = {{1,2},{3,4,5}};
public class ArrayFor {
public static void main(String[] args) {
int[][] multiples = new int[5][5];
// for loops go well with arrays
for (int i = 0; i < multiples.length; i++) {
for (int j = 0; j < multiples[i].length; j++) {
multiples[i][j] = (i + 1) * (j + 1);
}
} // So do for-each loops
for (int[] row : multiples) {
for (int num : row) {
System.out.print(num + "\t");
}
System.out.println();
}
}
ARRAYLIST
import java.util.ArrayList;
public class ClassDatabase {
### ArrayList uses .get(_index_) to get a value at an index
private ArrayList<StudentCourse> entry;
public ClassDatabase() {
this.entry = new ArrayList<>();
}
* Can have multiple constructors: but each need different parameter lists
• Gives all numeric types a value of 0, boolean a value of false, and all objects null
• null is a special value for reference (object) variables that means they do not have any reference
yet
String student;
String course;
STRINGS
modifying strings:
char[] chars = s.toChaArray()
new_string =new String(chars)
• we can only read the characters in a string, A string cannot be changed once it has been created’
} else {
if (Character.isUpperCase(data[index+1])) {
return false;
}
index++;
}
} while (index < data.length - 1);
return true;
ABSTRACTION
-DATA HIDING-
• Data hiding and encapsulation achieve abstraction
* Data Hiding: Data hiding is the practice of restricting access to certain parts of objects (attributes,
methods) from outside the objects' scope
* prevents unintended or unauthorized access to the object's internal state.
* Achieve data hiding by using access modifiers like private, protected, and public.
-ENCAPSULATION-
* bundling of data (attributes) and methods that operate on the data into a single unit (class)
* hide the internal state of an object and only expose a controlled interface to interact with the
object
* Methods and constructors can have parameters that are classes, meaning the values passed in
are objects.
* Variables storing objects or arrays store references, while variables that store primitive types
store the value directly
RECURSION
* Static Fields: These are variables that belong to the class. All instances of the class share the
same static field.
* Static Methods: These are methods that belong to the class. Declared using the static keyword.
• These methods make sense when they do not need to use fields
-FINAL-
• Abstract methods must be overidden
• final methods can never be overidden. They are “final”
• final classes can never be inherited from. They are “final” too
METHOD HIDING
Method hiding occurs when a subclass defines a static method with the same name
and signature as a static method in the superclass.
Unlike method overriding, which involves instance methods and allows for
polymorphic behavior,
method hiding involves static methods and does not allow polymorphism.
When a method is hidden, the superclass's method is called, and the subclass's
equivalent is hidden.
INHERITANCE
class Animal {
public void talk() {
System.out.println("Animal talks");
}
}
* super.(...) gives access to superclass members that shares same name as the subclass members
System.out.println(best);
}
}
DYNAMIC DISPATCH
class Animal {
// ...
}
class Goose extends Animal {
// ...
}
public class SuperGoose {
public static void main(String[] args) {
// What if we did this ??
Animal a = new Goose();
a.talk();
}
OUTPUT IS: Goose.talk() because it’s the runtime type of the object being called that determines
which method gets used
Packages and access modifiers
Modifier | Class | Package | Subclass| World
public Yes | Yes | Yes | Yes
protected Yes | Yes | Yes | No
(default) Yes | Yes | No | No
private Yes | No | No | No
Exceptions
• Let’s understand what happens when an exception gets thrown
• First, something goes wrong (e.g., array index out of bounds)
• An exception is an object. One is created and “thrown”
• If the exception is not caught, the method immediately terminates
• The exception goes up to the parent method that called the current method
• This continues until either the exception is caught, or we run out of methods
• If it remains uncaught, the program crashes and reports the error
Compile-time (checked)
Run-time (unchecked)
@Override
public String sound() {
return "Squeak";
}
}
Enums
• Enums can be public, protected, private, or default like any class
• All enums implicitly extend the built-in Enum class: default methods{ values(), ordinal(),
valueOf() }
enum Transport {
BUS(50), TRAIN(100), FERRY(20), TRAM(30);
Transport(int typicalSpeed) {
this.typicalSpeed = typicalSpeed;
}
Autoboxing/unboxing
• Autoboxing: automatic conversion from primitive to object type
• Unboxing: automatic conversion from object to primitive type
Useful for data structures or methods that only accept object types
Character Class
isDigit(), isLetter(), isUpperCase(), isLowerCase(), isWhiteSpace()
toUpperCase(), toLowerCase()
public static <T> Iterator<T> reversed(DoubleEndedIterator<T> it) {
return new Iterator<T>() {
Generics
public class GenericPair<T, V> { @Override
public T first; public boolean hasNext() {
public V second; return it.hasNext();
}
public GenericPair(T first, V second) {
this.first = first; @Override
this.second = second; public T next() {
}
} if (hasNext()) {
return it.reverseNext();
} else {
Generic Interfaces and Methods throw new NoSuchElementException();
}
}
};
}
Interface
public class RunningMaximum<T extends Comparable<T>> {
private T currentMax;
public T getCurrentMax() {
return currentMax;
}
}
Method
public class GenericMax {
public static <T extends Comparable<T>> T max(T a, T b) {
if (a.compareTo(b) > 0) {
return a;
} else {
return b;
}
}
}
Interfaces (II)
Bounded Type parameters
<T extends SuperClass>
This type parameter will accept any type argument that is either SuperClass or a subclass of
SuperClass
They are bounded since SuperClass is an upper bound on the type of <T>
Usually, <T> would accept any type --- this is equivalent to <T extends Object>
violation
public class FileManager {
public String readFile(String filePath) { ... }
public void writeFile(String filePath, String content) { ... }
public String compressFile(String contents) { ... }
}
Open–closed principle
* Software entities should be open for extension but closed for modification
* Add new features by making new classes/methods, not by modifying existing code
Once we call start(), the run() method executes concurrently in a new thread
class MyThread extends Thread {
private int number;
Synchronised
Java offers the synchronised statement
When a thread enters the block, it attempts to get a lock on the object
The thread will wait until the object is available if it is locked
• First, it locks the object >>>Then, it executes the block >>> Then, the object is unlocked
class AddThread extends Thread { // SpecialInt is an integer object with increment() method
private SpecialInt specialInt;
Synchronised(obj){…} ensures the object
being updated inside the synchronised block
public AddThread(SpecialInt specialInt) {
is inaccessible to other concurrently running
this.specialInt = specialInt;
threads.
}
Multiple threads might be running
public void run() {
concurrently and accessing specialInt to
for (int i = 0; i < 1000000; i++) {
increment, but synchronised ensure only one
synchronized (specialInt) {
thread is allowed to modify the object at a
specialInt.increment();
time
}
}
Concurrency and Threads (II)
Join
Once we start a thread, how do we wait until it has finished?
This may happen if you depend on the result
For example, if you create two threads to read from 2 different databases you may wait for a result
from both to continue with the program • Thread has a join() method • When the thread finishes
executing run(), it will join with the calling thread • Calling join() waits for that to happen
When a thread calls wait() on an object, it releases the lock it holds on that object and enters a
waiting state. It will remain in this state until another thread calls notify() or notifyAll() on the
same object.
notify() : When a thread calls notify() on an object, it wakes up one of the threads that are waiting
on that object. The awakened thread will then compete for the object's lock and continue its
execution.
class ProduceConsume {
private String sharedResource;