Lab 04 - Wildcard,Nested Class, Java package

Wildcard

The goal of wildcard in Java is to make generics covariant.

Set notation

  • Upper bounded wildcard (? extends T): It represents a set of type XX, where XX is the subtype of T. {X:X<T}\{X:X<T\}

  • Lower bounded wildcard (? super T): It represents a set of type YY, where YY is the supertype of T. {Y:T<Y}\{Y:T<Y\}

A classic problem is to find the range of a type parameter given a series of wildcards. (This is to determine which type you should declare a variable to to be safe to hold the element you get from a sequence).

The classic solution is to solve a system of inequalities.

Classic Examples

In Exercise 4 - Box, we have a method called Transformer<X, Y> which represents a unary transformation f:XYf:X\to Y. This question actually requires us to find the most relaxed bounds for XX and YY. To do so, let's try the method of solving the inequalities:

  1. ff should be able to "eat" everything of type T, so X:>T.

  2. The range of ff should be a subset of U, so Y<:U.

  3. Therefore, we should write Transformer<? super T, ? extends U>.

Methods take in reference type as argument

When you write a method with arguments being a reference type f(Object o), always check whether o is equal to null at first!

Functional Programming

A classic way to describe a function fxf(x)f:x\mapsto f(x). This means that if our function ff is deterministic, the previous formula is saying: if you fix a function ff and supply it with any xx, ff can always find the correct yy.

But we can also say it another way: if you fix a "seed" xx and supply it with any deterministic function ff, xx can always find its image yy, through ff.

So, there's nothing stopping us from writign f(x)=yf(x)=y as x(f)=yx(f)=y.

But notice the change in mindset here: instead of throwing an xx into ff and let ff do its work, we now ask xx to use some ff to mutate itself. (This is the basic of functional programming!)

To put it simply, our starting point changes from the function ff to argument xx.

Java package

In Java, a package is a way to group closely related classes together. Usually, classes in the same package have high dependency among one another and contain logic/data for performing a specific type of tasks.

For example, java.io is a package containing all classes related to IO, and java.utilcontains many utility data structures. (Useful in CS2040S).

A package needs to be imported before its classes can be used. This help to keep irrelevant classes invisible to simplify development process.

default access modifiers

When used as access modifiers, default doesn't need to be explicitly stated.

When a class/field/method has no access modifier, it’s said to have default accessibility: it can be accessed by any member from the same package.

Classes not belonging to any package are put into the default package by Java. This is why for the previous exercises, not having access modifiers is equivalent to being public (for class/fields/methods).

protected access modifiers

The protected means being accessible by any member from the same package and child classes outside the package.

Nested Class

In practice, the use of nested class is called the discriminated union. This is a design of having an abstract parent class with a few sealed inner classes. And its use cases are:

  1. An instance of the parent class is always one of the few subtypes.

  2. Each subtype consists of exactly the same functionalities of the parent class.

  3. The behaviours between different subtypes are mutually exclusive. In other words, the behaviour of the parent class is completely partitioned into disjoint cases.

This design actually utilises polymorphism.

For example,

Last updated