CPSC 331: Tutorial 1
Introduction, Java Review and Generics
PhD Student
Spring 2018
Introduction
Joshua Horacsek (PhD Student)
joshua.horacsek@ucalgary.ca
MS 625A
These slides will be made available on D2L
Policy:
- No food or drink
- Be academically honest
- Be respectful of your peers
I don't have scheduled office hours, but if you want to chat, just send me an email, I'll try to make it work.
Introduction
Keep in mind this is a Spring course. Things are going to move fast.
Please don't hesitate to ask questions. This material comes up A LOT in practice, it's important for you to learn.
We'll take a 10-15 minute break half way through each tutorial session.
Today
You should have knowledge of Java from a prerequisite course, but I'll try to refresh you on it.
Java Refresher
Java Generics
You should have knowledge of Java from a prerequisite course, but I'll try to refresh you on it.
Break ~ 15min somewhere in there...
Exercises
Some simple exercises to get the juices flowing.
Some Simple Bash
When you log into the ARM server, you'll be presented with a bash (Bourne Again SHell) command prompt. Initially you're in your home directory. Some simple commands are:
- pwd - prints the current working directory
- ls - shows the contents of the current directory
- mkdir - create a new directory
- cd - change directory
- rm - remove file
Bash is actually a scripting language, but you'll only need to know basic commands to get by in this course. See this for more info on bash.
Editing Files
Easy mode:
nano filename.c
Productivity mode:
Nano is a barebones text editor, it's great for quick and easy file editing, and has an easier learning curve comapared to emacs.
vim filename.c
Vi (improved) is a text editor that very heavily relies on text commands. It's a bit of an effort to learn, but improves workflow once you've memorized the key commands.
Vim
By default Vim is in command mode:
- i - changes to insert mode (esc changes to command mode when in insert mode)
- w - moves the cursor to the next word
- b - moves the cursor to the previous word
- u - undo
- :w - write the file
- :q - quit
- ZZ save and quit
Cheat sheet: https://vim.rtorr.com/
When you're in insert mode, type as normal, then esc puts you back in command mode
Java Refresher
Java is a high-level programming language. We try to abstract ourselves away from the machine -- java doesn't care if you're running on an Intel CPU (your desktop) or an ARM CPU (your phone).
main:
; initializes the two numbers and the counter. Note that this assumes
; that the counter and num1 and num2 areas are contiguous!
;
mov ax,'00' ; initialize to all ASCII zeroes
mov di,counter ; including the counter
mov cx,digits+cntDigits/2 ; two bytes at a time
cld ; initialize from low to high memory
rep stosw ; write the data
inc ax ; make sure ASCII zero is in al
mov [num1 + digits - 1],al ; last digit is one
mov [num2 + digits - 1],al ;
mov [counter + cntDigits - 1],al
jmp .bottom ; done with initialization, so begin
Java Refresher
Java is a high-level programming language. We try to abstract ourselves away from the machine -- java doesn't care if you're running on an Intel CPU (your desktop) or an ARM CPU (your phone).
As a high level language, it's easier to express concepts and algorithms.
Java Refresher
Hello World Example
Compile:
/**
* File: HelloWorld.java
*/
public class HelloWorld{
public static void main(String []args){
System.out.println("Hello World");
}
}
Execute in JVM:
javac HelloWorld.java
java HelloWorld
Java Refresher
Hello World Example
/**
* File: HelloWorld.java
*/
public class HelloWorld{
public static void main(String []args){
System.out.println("Hello World");
}
}
Execute in JVM:
java HelloWorld
Realistically we'll just do this in Eclipse
Java Refresher
Java is a Object Oriented. We organize concepts as objects. Objects model "real life" phenomena -- although we typically model a small amount of properties/features we care about.
/**
* File: Person.java
*/
public class Person{
private String firstName;
private String lastName;
private int age;
private int height;
public Person(String firstname, string lastname, int age, int height) {
}
// getters and setters...
}
Java Refresher
Classes encapsulate the behaviour of objects. This means that other classes shouldn't be aware of the internal structure of a given class. For example:
/**
* File: Person.java
*/
public class Person{
private String firstName;
private String lastName;
private int age; // <- this is bad design, we have to update it every year
private int height;
public Person(String firstname, string lastname, int age, int height) {
}
// getters and setters...
public getAge() {
return this.age;
}
// getters and setters...
}
Java Refresher
A better design
/**
* File: Person.java
*/
public class Person{
private String firstName;
private String lastName;
//private int age; // <- this is bad design, we have to update it every year
private Date dateOfBirth;
private int height;
// We have to keep this constructor around to not break any code that depended on it
public Person(String firstname, string lastname, int age, int height) {
// as a hack store today's date minus age, then refactor code to not use this method
}
// We have to keep this constructor around to not break any code that depended on it
public Person(String firstname, string lastname, Date dateOfBirth, int height) {
// fill values
}
// getters and setters...
public getAge() {
// return difference in years between today and the persons's date of birt
}
// getters and setters...
}
Changing the internals of the class means that most users of the class don't need to change their code
Java Refresher
Classes enforce a hierarchy design via inheritance. I.e we often have is-a relationships between classes for example, a Student is a person, but has a few extra attributes (like a student number)
/**
* File: Student.java
*/
public class Student extends Person {
private int studentId;
public Student(String firstname, string lastname, int age, int height, int sid) {
super(firstname, lastname, age, height);
this.studentId = sid;
}
// getters and setters...
}
A Student object inherits all the methods of a Person, it's a subtype of a Person, whereas a Person is a supertype of student.
Java Refresher
The last fundamental concept in OOP design is polymorphism. Put simply this means that similar objects have the same interface, but perhaps different implementations.
public class Person{
// properties and methods...
/* returns an amount of left over food */
public int eatGivenFood(int amountOfFood) {
return amountOfFood - 1;
}
}
public class Student extends Person {
public int eatGivenFood(int amountOfFood) {
return 0;
}
}
Java Generics
Often times, we want to perform the same operations on various different types of data. For example, if I write a method to sort integers, it should be able to sort floating point values.
Rather than repeating the code for different types, it is more clean and more maintainable to write code once, and have it work on different types.
This is the problem "Generics" try to solve.
Java Generics
First lets consider an example without generics. Lets say we want to store a pair of values. Without generics this might look like
class Pair {
Object x;
Object y;
public Pair( Object x, Object y ) {
this.x = x;
this.y = y;
}
public Object getX() { return x; }
public Object getY() { return y; }
//...
}
Java Generics
class Pair {
Object x;
Object y;
public Pair( Object x, Object y ) {
this.x = x;
this.y = y;
}
public Object getX() { return x; }
public Object getY() { return y; }
//...
}
Class usage
Pair pair1 = new Pair(new Integer(1), new Integer(2));
Pair pair2 = new Pair(new Double(2), new Double(2));
// An explicit cast in needed to retrieve a value
int v1 = (Integer)pair1.getX();
double v2 = (Double)pair2.getY();
You have to do all type checking in code -- ideally the compiler should do this.
Java Generics
Let's rewrite the same class with generic parameters. Classes can take a list of parameters between angular <, > braces.
class Pair <T1, T2> {
T1 x; // x is of type T1
T2 y; // y is of type T2
public Pair( T1 x, T2 y ) {
this.x = x;
this.y = y;
}
public T1 getX() { return x; }
public T2 getY() { return y; }
//...
}
Java Generics
class Pair <T1, T2> {
T1 x; // x is of type T1
T2 y; // y is of type T2
public Pair( T1 x, T2 y ) {
this.x = x;
this.y = y;
}
public T1 getX() { return x; }
public T2 getY() { return y; }
//...
}
Class usage
Pair <Integer , Integer> pair1 =
new Pair<Integer, Integer>(new Integer(1), new Integer(2));
Pair <Double, Double> pair2 =
new Pair<>(0.5, 3.14); // The compiler infers the omitted types
int v1 = pair1.getX(); // ok
int v2 = pair2.getY(); // compile error
double v3 = pair2.getY(); // ok
Java Generics
You can extend generic classes to generic and non-generic classes
import java.lang.*;
class Point extends Pair<Double, Double> {
public Point(Double x, Double y) {
super(x,y);
}
public double getDistance(Point p2) {
Double d1 = (this.x - p2.x), d2 = (this.y - p2.y);
return Math.sqrt(d1*d1 + d2*d2);
}
}
Java Generics
You can extend generic classes to generic and non-generic classes
class Triple <T> extends Pair <T,T> {
private T z; // Add another member
public Triple(T x, T y, T z) {
super(x,y);
this.z = z;
}
public T getZ() {return z;}
}
Java Generics
Note:
- Say we have a class Student that is a subtype of the class Person. If we have a generic type List<> it is not true in Java that List<Student> is a subtype of List<Person>
Triple<Integer> tr = new Triple<>(1,2,3);
Pair<Integer, Integer> pr = tr; // This is valid
Triple<Object> tro = tr; // This produces an error
Java Generics
The previous example raises an interesting question, is there a generic type that can be used as a supertype?
void printTriple(Triple <?> tr) {
System.out.println( "" + tr.getX() + ", " +
tr.getY() + ", " + tr.getZ() )
}
Yes, Java has wildcard types.
You can also impose constraints on wildcard. I.e. that they must be subtypes or supertypes of a given object.
// Anything that is a subtype of a Person, i.e. student type
List<? extends Person>
// anything that is a supertype of the Person, i.e. an Animal type,
List<? super Person>
Java Generics
Methods can also be generic, we could write the printTriple method as
public static <T> void printTriple( Triple <T> tr ) {
System.out.println( "" + tr.getX() + ", " +
tr.getY() + ", " + tr.getZ() );
}
Java Generics
As an example of a generic method, let's look at Insertion sort (if you haven't learned about Insertion sort yet, it's not a big deal.)
public <T extends Comparable <T>> void insertionSort( T[] data ) {
for(int i = 1, j; i < data.length; i++) {
T tmp = data[i];
for(j = i; j > 0 && tmp.compareTo(data[j-1]) < 0; j--)
data[j] = data[j-1];
data[j] = tmp;
}
}
The only requirement for these types of sorting algorithms (exchange sorts) is that we can order items. i.e. they implement the Comparable<T> interface
Java Generics
Caveats
- Cannot declare static fields whose types are generic
public class G<T> {
private static T var; //not allowed
}
- Cannot use primitive types as type parameters
Triple <int > tr1; // not allowed
Triple <Integer > tr2; // ok
- Cannot instantiate generic types in a generic context
T obj = new T(); // not allowed
T[] arr = new T[10]; // not allowed
There are more restrictions, see
https://docs.oracle.com/javase/tutorial/java/generics/
for details.
Generics Exercises
I'm going to give you some exercises and some time, then at the end of the session I'll walk you through my process.
We'll see how many of them we get through
Generics Exercises
Exercise 1:
We created a generic Pair<T1, T2> class that stored two values of potentially different types. Create a generic Triple class (don't extend the Pair class) that has similar behaviour. You only need to create getters for the class.
Generics Exercises
Exercise 2:
We created a generic Pair<T1, T2> class that stored two values of potentially different types. Create a generic Triple class, by extending Pair, that has similar behaviour. You only need to create getters for the class.
Note we had a similar example before, but it each element in the triple had the same type T
Generics Exercises
Exercise 3:
Suppose we have the classes
abstract class Shape2D {
abstract public double getArea();
}
class Circle extends Shape2D {
private double radius;
public Circle(double radius) { this.radius = radius; }
public double getArea() { return 3.14 * this.radius * this.radius; };
}
class Rectangle extends Shape2D {
private double length, width;
public Rectangle(double len, double width) { this.length = len; this.width = width; }
public double getArea() { return this.length * this.width; };
}
// Note how this doesn't extend the base Shape2D class
class Triangle {
private double base, height;
public Triangle(double base, double height) { this.base = base; this.height = height; }
public double getArea() { return this.height * this.base * 0.5; };
}
Create a method that prints the area of any Shape2D subclass. It shouldn't accept Triangle instances.
Generics Exercises
Exercise 4:
Write a method that searches through an array of generic type T. This function should return where the element is in the array. It should return -1 if it can't find the element (or a null value).
Next Week
Victoria Day, Practice Analysis and Correctness
CPSC 331: Tutorial 1
By Joshua Horacsek
CPSC 331: Tutorial 1
- 1,822