Finals Review CC-BY-NC

Maintainer: admin

This notes extends Midterm Review. The final exams includes everything tested in the midterm

1Frameworks

1.1Framework

A framework is a set of classes and interface types that structures the essential mechanisms of a particular domain. In other words, a framework is a set of tools that change the way you program something. e.g. Swing, jQuery, django

An application framework is a framework for creating applications of a particular type: it supplies a set of classes that an application programmer extends to build an app.

The programmer has little or no influence on the order in which the extended classes are called - the programmer becomes the framework's bitch. This phenomenon is often called inversion of control. The flow of execution is controlled by the framework classes, not the application specific classes.

1.2Example: Graph Editor Framework

Uses the prototype pattern

2Objects and Types

2.1Types and Subtypes

Type
A set of values together with a set of operations that can be applied to the values

Strongly typed languages: casts are almost never implicitly done, example: Java, python
Weakly typed languages: When the compiler finds the wrong type, it tries to use the operations anyway, causing weird behavior. Example: Javascript, C

Java is statically typed, that means type validation is done during compile time, so if you call an undefined method on a variable, it will not compile.
Some languages like javascript or python are dynamically typed, which means types aren't known during compile time, and an undefined method will result in a runtime exception.

Types in Java are:

  1. Primitive type(int, short, long, byte, char, float, double, boolean)
  2. A class type
  3. An interface type
  4. An array type
  5. The null type

Values in java are:

  1. A primitive value
  2. A reference to an object
  3. A reference to an array
  4. null

You can substitute a value of a subtype whenever a supertype value is required.

S is a subtype of T if:

  1. S and T are the same type
  2. S and T are both class types and S is a direct or indirect subclass of T
  3. S and T are both interface types and S is a direct or indirect subinterface of T
  4. S is a class type, and T is an interface type, and S or one of its superclasses implements T or a subinterface of T
  5. S and T are both array types and the component type of S is a subtype of T's component type
  6. T of type java.lang.Object, S is not a primitive
  7. S is an array type and T is the type Cloneable or Serializable
  8. S is null and T is not a primitive type

2.1.1Arrays

Arrays are annoying. The following will generate a runtime error:

Rectangle [] r = new Rectangle[10];
Shape [] s = r; // valid because Rectangle is a subtype of Shape
s[0] = new Circle(); // valid because Circle is a subtype of Shape, BUT s IS NOT A SHAPE ARRAY! IT IS A RECTANGLE ARRAY!

2.1.2Wrapper classes

Primitives types have their corresponding wrapper classes. They are all immutable classes. You can also assign primitivive values to objects of the wrapper classes because of autoboxing (Since java 1.5)

2.1.3enums

An enumerated type is a type with a finite set of values, to declare an enum the syntax is:

public enum Day {MONDAY, TUESDAY, WEDNESDAY}; // FUCK THE REST OF THE WEEK

Each member in an enum is a singleton of the class, thus Day.MONDAY == Day.MONDAY will always be true. null is also a possible value of the enum.

You can also add methods and fields to an enum class:

public enum Day{
    MONDAY(1), TUESDAY(2), WEDNESDAY(3);
    public String foo(){
        return "bar";
    }
}

Enums are Comparable.

2.2Type Inquiry

The instanceof operator can be used to test the type, with the syntax if (var instanceof Type).
Typically you use it before casting to ensure safety. If var is null, it will return false.

You can also find the type of an object by using the Class object.

Class c = var.getClass();

The object c contains information about the class of var, including its name, superclass.

You can get a class object from a name by using the Class.forName("java.awt.Rectangle") method.

Primitive types also have an associated Class object.

Class objects are singletons, thus you can use == to test type equality like so: if (var.getClass() == Type.class).

You can use isArray() to test whether a type is an array, then use getComponentType() to get the class of the component type.

2.3The Object Class

All java classes are subclasses of the Object class. It contains the following methods:

  • String toString()
  • boolean equals(Object other)
  • int hashCode()
  • Object clone()

The equals method must be reflexive, symmetric, and transitive. The default equals method is testing equality using ==
The default hashCode() method returns the memory address.

3Persistence

3.1Serialization

Serialization denotes the process of storing an object and its dependent objects in a stream.

To serialize something, you use an ObjectOutputStream on an object that implements Serializable:

Cat kitty = new Cat();
ObjectOutputStream out = new ObjectOutputStream(new FileOutputSTream("kitty.dat"));
out.writeObject(kitty);
out.close();

To read it back, you use an ObjectInputStream:

ObjectInputStream in = new ObjectInputStream(new FileInputStream("kitty.dat"));
Cat kitty = (Cat)in.readObject();
in.close();

The class Cat must implement Serializable.

To have fields that you don't want to be serialized, you use the transient keyword.

private transient boolean badCat;

4Generics

4.1Type Variables

A generic type has one or more type variables, like List<E>.

Use them in the following format:

public class Heap<E>
{
    public E pop(){}

    public void set(int i, E value){}
}

Methods can also be generic:

public class Foo{

public <E> void bar(Heap<E> a, E value){
    a.set(0,value);
}
}

We can also specify conditions on generic types

public class Foo{

public <E, F extends E> void compareEF(ArrayList<E> a, ArrayList<F> b){}

public <E> void compareExtends(ArrayList<E> a, ArrayList<? extends E> b){}

public <E> void compareSuper(ArrayList<? super E> a, ArrayList<E> b){}
}

4.2Type Erasure

Generic types are erased during compile time

http://docs.oracle.com/javase/tutorial/java/generics/erasure.html

5Code quality

If you hate yourself when you read your code 2 weeks later, you're doing it wrong. If you don't, then you're clueless.

6Thread

6.1Threads and the Runnable Interface Type

In java you can implement blocks of code as separate threads of execution. They are executed independently of other parts of the program.

To use threads, you use the following syntax:

Thread t = new Thread(new Runnable(){
    void run(){
        for(int i = 0;i<100;i++){
            System.out.println("Hello");
        }
    }
});
t.start();

You can use the sleep method to put the current thread to sleep for a given number of milliseconds. A thread terminates when the run() method terminates.

6.2Scheduling Threads

A thread scheduler allows each thread to execute for a short amount of time, called a time slice. Each thread has a thread state and a priority. The thread state can be:

  • new (before start() is called)
  • runnable
  • blocked
  • dead (after run() terminates)

A thread enters the blocked state by either:

  • Sleeping
  • Waiting on I/O
  • Waiting to acquire a lock
  • Waiting for a condition

Once a thread is blocked, it stays blocked until it gets the reason it gets blocked for is resolved (no fucking shit).
The scheduler will activate a new thread when one of three events occurs:

  • A thread has completed its time slice
  • A thread has blocked itself
  • A thread with higher priority has become runnable

6.3Stopping threads

To stop a thread do not use stop() because if your thread is holding any lock on resources, shit might happen. To stop a thread, use the interrupt() method.
The call doesn't terminate the thread, it just politely interrupts the thread's dinner. It's up to the thread whether or not he wants to leave the restaurant.

7Synchronization

7.1Thread Synchronization

When threads share access to a common object, they can conflict with each other. If you have two threads adding to an ArrayList, it's possible that it might not behave as expected.

A race condition occurs if the effect of multiple threads on shared data depends on the order in which the threads are scheduled.

7.2Locks

A thread can acquire a lock, and when another thread tries to acquire the same lock, it is blocked. When the first thread releases the lock, the other threads are unblocked. To lock a block of code, we use ReentrantLock()

l = new ReentrantLock();
l.lock();
try{
    // only one thread can be in here at once
}
finally{
    l.unlock();
}

Putting synchronized in front of a method like:

public synchronized void add(E e){}

makes sure that only one thread can be inside this function at once.

7.3Deadlocks

A deadlock occurs if no thread can proceed because each thread is waiting for another to do some work first. Most of the time it happens because a thread is blocked inside a locked block of code, and other threads can't unblock it because it has the lock, like so:

public void add(E new){
    l.lock();
    try{
        while(!condition()){
            //condition never becomes true
        }
    }
    finally{
        l.unlock();
    }

}

To avoid deadlocks, you can use a Condition object to briefly release a lock, like so:

private Condition c = l.newCondition();

public void add(E new){
    l.lock();
    try{
        while(!condition()){
            c.await();
        }
    }
    finally{
        l.unlock();
    }
}

public void condition(){
    c.signalAll()
}

When signalAll is called, the waiting threads are unblocked.

If synchronized was used, each Thread has one condition, and to block it you use wait(), and notifyAll() unblocks it.

8The Visitor Design Pattern

Context

  1. An object structure contains element classes of multiple types, and you want to carry out operations that depend on the object types.
  2. The set of operations should be extensible over time.
  3. The set of element classes is fixed.

Solution

  1. Define a visitor interface type that has methods for visiting elements of each of the given types.
  2. Each element class defines an accept method that invokes the matching element visitation method on the visitor parameter.
  3. To implement an operation, define a class that implements the visitor interface type and supplies the operation's action for each element type.