You are on page 1of 43

Java Advanced Features

Lucian Bredean
Class versus Object

Class Object

Template / blueprint having the purpose A concrete implementation of the class


to model real-world concepts
Defines attributes -> used to model the Concrete values are given to attributes to
state define the state
Defines methods -> used to model the Alters the state as it was defined
behavior
OOP principles

o ABSTRACTION
- The ability to design class structure in such way that only essential details are displayed to the user,
while the irrelevant details are ignored.
- In OOP, abstraction also means hiding implementation details from the client code.

o ENCAPSULATION
₋ The principle according which all the related information (attributes) and the operations which can
be performed on this data (methods) into the same structure (class).
₋ In addition, another purpose is to control the access to all these items.

₋ Access modifiers (can be applied to classes, methods, attributes):


1. private – a private field can only be accessed within the same class
2. - a field with default access modifier (also called package-private) can be accessed within the
class where has been defined and from all classes in the same package
3. protected – a protected field can be accessed within your class, by all classes in the same
package and by all subclasses
4. public – can be accessed from any class
OOP principles

Task 1:
- Create a new maven project. Create two different packages within “src/main/java” path.
- Create two classes with the same name, each in different package
- Add in each of the class four field using the four access modifiers
- Create a third class with the main function; instantiate the previously created classes and try to access
their attributes using “.”
OOP principles

o ENCAPSULATION
₋ The instruments we can use to obtain encapsulation are:
• private attributes
• getter methods to read the attributes
• setter methods to change/set the attributes
• Constructor (with/without parameters)

Task 2:
- Create a class “Person” which should model a Person from the municipality point of view
- Create getters and setters for the attributes
- Create a method “getPersonDetails” which would print the information related to that person
- Create an instance of the class and an application which would call the “getPersonDetails” and print the
return value
OOP principles – Abstraction & Encapsulation exercises
OOP principles

o INHERITANCE
- It is a powerful mechanism which allows achieving code reuse
- Facilitates the creation of hierarchical models -> easy to understand: e.g. vehicles can be categorized as
two-wheelers, three-wheelers, four-wheelers etc. each having their own subclasses and particular
characteristics
- Extended class <-> parent class; the class extending a class <-> child class/derived class
- Inheritance can be referred to as an “IS-A” relationship
OOP principles - Inheritance

Task 3:
- Create a “Shape” class with a single integer colorCode attribute which should be made accessible only
for derived classes
- Define a “Circle” subclass
- It should contain a radius field visible only inside the class, a area method to compute the area and a
fillColor method which should print the color code
public class Shape {
protected int colorCode;
}

public class Circle extends Shape {


private int radius;

public void computeAndPrintArea() {


System.out.println(Math.PI * radius * radius);
}

void printFillColor() {
System.out.println(colorCode);
}
}
OOP principles - Inheritance

Task 4:
- Create a “TestNumber” class containing a utility method which computes the sum for an array of
numbers
- Create a number array holding a Byte, an Integer, a Float and a Double and call the method to compute
the sum
public class TestNumber {
public static double sum(Number []nums) {
double sum = 0.0;
for(Number num : nums) {
sum += num.doubleValue();
}
return sum;
}

public static void main(String []s) {


Number []nums = new Number[4];

nums[0] = new Byte((byte)10);


nums[1] = new Integer(10);
nums[2] = new Float(10.0f);
nums[3] = new Double(10.0f);
System.out.println("The sum of numbers is: " + sum(nums));
}
}
OOP principles - Inheritance

Task 5:
- Create a “Vehicle” class having a single attribute called maxSpeed visible only inside the class
- Make sure that it will be impossible to create an instance of the class without specifying a value for
maxSpeed
- Allow reading access for the defined maxSpeed attribute

public class Vehicle {

private int maxSpeed;

public Vehicle(int maxSpeed) {


this.maxSpeed = maxSpeed;
}

public int getMaxSpeed() {


return maxSpeed;
}
}
OOP principles - Inheritance

Task 6:
- Create a “Car” class; it should use the code already written for “Vehicle” class
- It should also have the isConvertible attribute, visible only inside the class with a default value of false
- Allow reading access for the defined isConvertible attribute

public class Car extends Vehicle {

private boolean convertible;

public Car(int maxSpeed, boolean convertible) {


super(maxSpeed);
this.convertible = convertible;
}

public boolean isConvertible() {


return convertible;
}
}
OOP principles - Inheritance

What would you change to make the maxSpeed field directly visible inside Car class?
protected int maxSpeed; //inside class Vehicle

What do you think would happen if we would declare a double private field called the same inside Car
class?
private double maxSpeed;

-> Field hiding. Possible, but not recommended; bad practice


Are we still able to access the field in the parent class inside the child class? Try to write a getter returning
the maxSpeed field in the parent class.
public int getParentHiddenMaxSpeed () {
return super.maxSpeed;
}

Inside a new runnable class, create a method capable of printing the maxSpeed value of any Vehicle.
Is it possible to use it in order to print the maxSpeed for a Car?

private static void printMaxSpeed(Vehicle vehicle) {


System.out.println(vehicle.getMaxSpeed());
}
OOP principles – Inheritance and Polymorphism
Polymorphism – means several forms -> in OOP, depending on the context, a class can be interpreted as
being of different types

There are two main types of polymorphism:


1. Static polymorphism (compile-time polymorphism) – method overloading
2. Dynamic polymorphism (run-time polymorphism) – method overriding

Static polymorphism – Method overloading


- Defining multiple methods with the same name but different type/number/order of parameters
- Allows you to have multiple implementations for the same things

Task 7:
Define a method which computes the sum of integer numbers passed as an array.
public static int sum(int[] numbers) {
Integer sum = 0;
for (Integer number : numbers) {
sum += number;
}
return sum;
}
OOP principles – Inheritance. Static Polymorphism.
We might need to compute the sum for a set of numbers passed as a single string where the numbers are
separated using comma.
public static int sum(String numbersAsString) {
String[] numbers = numbersAsString.split(",");
int sum = 0;
for (String number : numbers) {
sum += Integer.parseInt(number);
}
return sum;
}

Dynamic polymorphism – Method overriding


- We learned that a base class reference can point to a derived class instance
- If the method invoked is an overridable method, the compiler defers determining the exact method
to be called at run time (late binding) when the JVM picks the right method
class Shape {
public double area() { return 0; }
}
OOP principles – Inheritance. Dynamic Polymorphism.
class Circle extends Shape {
private int radius;

public Circle(int r) {radius = r; }

public double area() {return Math.PI * radius * radius; }


}

class Square extends Shape {


private int side;
public Square(int a) { side = a; }
public double area() { return side * side; }
}

public class TestShape {

public static void main(String []args) {


Shape shape1 = new Circle(10);
System.out.println(shape1.area());

Shape shape2 = new Square(10);


System.out.println(shape2.area());
}
}
OOP principles – Composition.
- It is the mechanism which allows reusing existing code by making an already defined class part of a new
class
- Composition can be referred to as an “HAS-A” relationship
- Using composition leads to code easy to change without impacting the client code
class Point {
private int xPos;
private int yPos;

public Point(int x, int y) {


xPos = x;
yPos = y;
}

public String toString() {


return "(" + xPos + "," + yPos + ")";
}
}
OOP principles – Composition.
class Circle extends Shape {
private Point center; // Circle "contains" a Point object
private int radius;

public Circle(int x, int y, int r) {


center = new Point(x, y);
radius = r;
}

public double area() {return Math.PI * radius * radius; }

public String toString() {


return "center = " + center + " and radius = " + radius;
}
}

Composition vs. Aggregation


- Assume we have a class Container and inside container we have a field of type Content (Content c
= new Content())
- Composition -> the Content does not make sense in the absence of Container
- Aggregation -> the Content can exist and makes sense in the absence of Container
OOP concepts – “static”/ “final” keyword.

- Both can be used with initialize blocks, variables, methods and classes
- A static variable is associated with the enclosing class and it is called a “class variable” and it shares
the same state with all class instances; other variables are called “instance variables” and have a
state per instance
- A static method can only access static variables/call static methods
public class Counter {
private static int count;

public Counter() {
count++;
}

public static void printCount() {


System.out.println("Number of instances created so far is: " + count);
}
public static void main(String []args) {
Counter anInstance = new Counter();
Counter.printCount();

Counter anotherInstance = new Counter();


Counter.printCount();
}
}
OOP concepts – “static”/ “final” keyword.

- The main method, where the program execution starts, is always declared static

- A static method cannot be overridden -> “this”/“super” cannot be used inside a static method

- A final class is a non-inheritable class, so it cannot be extended; all methods of a final class are
implicitly final

- A final method cannot be overridden

- A final variable can be assigned only once: at declaration or within the constructor

- The value of a final parameter cannot be changed

Small exercise: Try, in turn, to change to final the method “public double area() ” in class “Shape” and
then the entire class.
OOP concepts – Abstract classes and methods.

Abstract classes are used when you want to define an abstraction with some common functionality
but you also want to prevent instantiation of that abstraction.
abstract class Shape {
public double area() { return 0; }
}

If we do not want to provide a default implementation but we want to make sure that any subclass
will provide one, we can declare the method abstract as well.
abstract class Shape {
public abstract double area();
}

To Remember: The “abstract” keyword can be used with classes and non-static methods of a class.
OOP concepts – Interfaces.
An interface can be seen as a set of abstract methods that defines a protocol.
It is said that a class implements a interface, whenever the class adheres to the protocol defined by
the interface -> all methods defined by the interface have to be implemented in the class
public interface Colourable {
int DEFAULT_COLOR_CODE = 0;

static void describeBehavior() {


System.out.println("This is colourable.");
}

default void printFillColor() {


System.out.println(DEFAULT_COLOR_CODE);
}

void render();
}
To remember:
- an interface cannot be instantiated but the interface type can be used as variable/parameter type
- an interface can extend another interface
- all fields declared inside an interface are “public static final”
- an interface can have abstract/default/static methods
- all methods declared in an interface are by default considered to be abstract
- default methods must have an implementation and are instance methods
- static methods will be class methods for the classes implementing the interface
OOP concepts – Nested classes.

Static Nested Classes


You can define a class (or interface) as a static member inside another class (or interface).
Task 8:
Add the Color nested static class to the (abstract) Shape class and create an instance of the nested class.
Print toString() method call output for that instance to console.
public static class Color {
int m_red, m_green, m_blue;

public Color() {
this(0, 0, 0);
}

public Color(int red, int green, int blue) {


m_red = red;
m_green = green;
m_blue = blue;
}

public String toString() {


return " red = " + m_red + " green = " + m_green + " blue = " + m_blue;
}
}
OOP concepts – Nested classes.

Static Nested Classes

To remember:

- The static nested class can be referenced using OuterClassName.NestedClassName

- An inner nested class (or interface) declared inside an interface is implicitly public and static

- Static nested classes can access (static) members of the outer class

- The outer class can access members (even private ones) of the nested static class

- Static nested classes can be declared abstract or final


OOP concepts – Nested classes.

Inner Classes
You can define a class (or interface) as a non-static member inside another class.
Task 9:
Add the “Point” class as an inner class for the Circle class. Add a constructor receiving three parameters:
radius, x coordinate, y-coordinate and use the inner Point class to initialize the “center” field for the Circle
instances.
Try to create an instance of the inner Point class somewhere outside the Circle class.

public Circle(int radius, int x, int y) {


this.radius = radius;
this.center = this.new Point(x, y);
}

Circle circle = new Circle(5, 0, 0);


Circle.Point point = circle.new Point(5, 5);
OOP concepts – Nested classes.

Local Inner Classes

- are defined inside a code block (e.g. inside a method)


- are not members of an outer class, are available just inside the enclosing code block
Task 10:
Add the following method (and Local InnerClass) to the abstract “Shape” class. Then use this new method
and print the new “toString” representation.
static Shape.Color getDescriptiveColor(final Shape.Color color) {
// local class DescriptiveColor that extends Shape.Color class
class DescriptiveColor extends Shape.Color {
public String toString() {
return "You selected a color with RGB values" + color;
}
}
return new DescriptiveColor();
}

System.out.println(Shape.Color.getDescriptiveColor(shapeColor).toString());
OOP concepts – Nested classes.

Local Inner Classes

Task 11:
What point do you think it has the “final” keyword for the Shape.Color color parameter? What if that “final”
would be removed?

To remember:
- the variables passed to a local inner class have to be final; the compiler treats them as effectively
final, so they cannot be changed once passed to the local inner class

- interfaces cannot have local classes and local interfaces cannot be created

- a local inner class can access all the variables available in the enclosing code block
OOP concepts – Nested classes.

Anonymous Inner Classes

- do not have names


- cannot have explicit constructors, so parameters cannot be passed to such classes
Task 12:
Replace the previous Local Inner Class with the following Anonymous Class:

static Shape.Color getDescriptiveColor(final Shape.Color color) {


// note the use of anonymous inner classes here
// -- specifically, there is no name for the class and we construct
// and use the class "on the fly" in the return statement!

return new Shape.Color() {


public String toString() {
return "You selected a color with RGB values" + color;
}
};
}
System.out.println(Shape.Color.getDescriptiveColor(shapeColor).toString());
OOP concepts – Exceptions

- An exception is an unwanted or unexpected event which occurs during the program execution and
disrupts the normal flow of the program
- Whenever such situation occurs, the enclosing method creates an Exception object and hands it
over to JVM -> throwing an exception
- the list of the methods which had been called if known as “Call Stack”
OOP concepts – Exceptions

- Errors: indicate a serious problem that should not be handled by the application; it is not checked at
compile time

- Exceptions:
• Checked Exceptions: checked at compile time; when such exception is thrown, then the
exception must be either handled or thrown again
• Unchecked Exceptions: not checked at compile time -> not mandatory to be handled

- Any Exception extending RuntimeException class or Error class is an unchecked exception

- try-catch-finally mechanism is used to handle exceptions in Java


try {
int x = 5 / 0;
} catch (Exception e)
System.out.println("Exception is caught and handled!");
} finally {
System.out.println("This will be printed no matter what.");
}
OOP concepts – Exceptions

- try-catch-finally mechanism allows multiple catches


try {
int[] intArray = new int[]{1, 4};
int y = 0;
int x = intArray[5] / y;
} catch (ArithmeticException e) {
System.out.println("ArithmeticException caught!");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("ArrayIndex(...)Exception caught!");
} catch (Exception e) {
System.out.println("Another exception caught!");
}

- try-catch-finally mechanism allows the handling of multiple exceptions in the same catch clause
try {
int[] intArray = new int[]{1, 4};
int y = 0;
int x = intArray[5] / y;
} catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {
System.out.println("ArithmeticException or ArrayIndexOutOfBoundsException caught!");
} catch (Exception e) {
System.out.println("Another exception caught!");
}
OOP concepts – Exceptions

- Exceptions can also be thrown inside a method


- When the thrown Exception is a Checked exception, it is mandatory to add this to the method
signature and to handle it in the client code
- Custom exceptions can be created by extending any of the known exceptions classes (mainly
Exception)
Task 13:
1. Create a custom CarCrashedException which would include in the exception message the max speed of
the car
2. Define a field “speed” inside the “Car” class. Define a method to increate the maximum speed of the
car; the method should throw an exception when the speed exceeds the maximum speed.
public void increaseSpeed(int amount) throws CarCrashedException {
speed += amount;
if (speed > maxSpeed) {
throw new CarCrashedException(this);
}
}

public static class CarCrashedException extends Exception {


CarCrashedException(Car car) {
super("Car " + car + " has crashed.");
}
}
OOP concepts – Enum data type.

- it is a mechanism allowing to group together a set of related constants


- compared to manually defining the constants, it improves readability

Let’s define an enum type, containing constants which describe printer types:
public enum PrinterType {
DOTMATRIX, INKJET, LASER;
}

Main methods of an enum:

- name() -> returns the name of the enum constant, exactly as declared in its enum declaration;
cannot be overridden

- toString() -> returns the name of this enum constant, as contained in the declaration; this method
may be overridden

- ordinal() -> returns the ordinal of this enumeration constant (its position in its enum declaration,
where the initial constant is assigned an ordinal of zero)
OOP concepts – Enum data type.

Task 14:
Create method which would return/print a description based on the printer type.

public static void printDescription(PrinterType printerType) {


switch (printerType) {
case DOTMATRIX:
System.out.println("Dot-matrix printers are economical and almost obsolete");
break;
case INKJET:
System.out.println("Inkjet printers provide decent quality prints");
break;
case LASER:
System.out.println("Laser printers provide best quality prints");
break;
default:
System.out.println("Unknown printer type.");
break;
}
}
OOP concepts – Enum data type.

Task 15:
Could the enum be enriched with a page print capacity information?

public enum PrinterType {


DOTMATRIX(5),
INKJET(10),
LASER(50);

private int pagePrintCapacity;

private PrinterType(int pagePrintCapacity) {


this.pagePrintCapacity = pagePrintCapacity;
}

public int getPrintPageCapacity() {


return pagePrintCapacity;
}
}
OOP concepts – Enum data type.

To remember:

- enums are implicitly public, static and final -> cannot be extended

- any enum implicitly inherits the public abstract class Enum

- enums can be declared as inner structures of classes

- equals() method can be called to compare enumeration constants; if the constants are defined in
different enumerations, then the method call returns false – the check is made only at runtime

- the comparison of enum constants can also be made using == operator; in this case, type safety is
assured: if enum constants belonging to different enums are compared, this is detected at compile
time
Java Collections

Collection: group of individual elements (objects) represented in a single structure

- In Java, the collections are structured under different interfaces related based on inheritance.
Java Collections

List interface:
- any list can contain duplicates
- the elements are ordered
- implementations: ArrayList, LinkedList
- operations like add(), remove(), get(), set() are allowed

• ArrayList – resizable array, fast for search but slow for inserts/deletes
• LinkedList – doubly linked list, fast for inserts/deletes but slow for search
• ArrayDeque – resizable array with double-ended queue functionality
• PriorityQueue – the elements can be ordered according to their natural order or according to a
Task 16: specified comparator
Create an ArrayList containing Point objects. Add several Point instances to the ArrayList. Try to remove one
of the Point instances from the list.
Java Collections

Task 16:
Create an ArrayList containing Point objects. Add several Point instances to the ArrayList.
Try to remove one of the Point instances from the list.

Task 17:
Create a priority queue and add several Point objects inside.

Define a comparator and use it to create the priority queue.


Java Collections

Set interface:
- does not contain allow duplicates
- implementations: TreeSet, HashSet, LinkedHashSet

• TreeSet – it stores the elements in a sorted order inside a tree data structure; the order of
elements is in the natural order or according to a comparator

• HashSet – internally it uses a hash table; it is fast for searching and retrieving elements

• LinkedHashSet – similar to the HashSet; the difference relies in the fact that it is used when the
iteration order matters: it iterates through the elements in the order they were inserted
Java Collections

Task 18:
Create a TreeSet Point objects. Add several Point instances to it; try to add at least one duplicate.
Should it work if the Point class does not implement equals?
Try to remove one of the Point instances from the Set.

Task 19:
Create a HashSet Point objects. Add several Point instances to it; try to add at least one duplicate.
Should it work if the Point class does not implement equals?
Try to remove one of the Point instances from the Set.
Java Collections

Map interface:
- it’s also know as a dictionary: stores key-value pairs
- does not contain allow duplicate keys
- implementations: TreeMap, HashMap, HashLinkedMap, HashTable

• TreeMap - it stores the key-value pairs in a sorted order inside a tree data structure; the order
of elements is in the natural order or according to a comparator

• HashMap - internally it uses a hash table to store the key-value pairs; it is fast for searching and
retrieving elements; it does not maintain the insertion order of the elements

• Hashtable – very similar to the HashMap; compared to that, it is synchronized and does not
allow null keys/values

• HashLinkedMap –– similar to the HashMap; the difference relies in the fact that it is used when
the iteration order matters: it iterates through the elements in the order they were inserted
Java Collections

Task 20:
Create a TreeMap Point associating Point objects to their String representation. Add several Point-String
pairs to it; try to add at least one duplicate.
Should it work if the Point class does not implement equals?
Try to remove one of the Point-String pairs from the Map.

Task 21:
Create a HashMap Point associating Point objects to their String representation. Add several Point-String
pairs to it; try to add at least one duplicate.
Should it work if the Point class does not implement equals?
Try to remove one of the Point-String pairs from the Map.

You might also like