840 likes | 902 Views
COSC 3P91 Advanced Object-Oriented Programming Super Course. Instructor: Michael Winter Office J323 email: mwinter@brocku.ca Webpage: www.cosc.brocku.ca/~mwinter/Courses/3P91.
E N D
COSC 3P91Advanced Object-Oriented ProgrammingSuper Course • Instructor: Michael Winter • Office J323 • email: mwinter@brocku.ca • Webpage: www.cosc.brocku.ca/~mwinter/Courses/3P91
Course Description (Brock Calendar):Advanced object-oriented programming techniques such as graphical user interfaces, animation, sound, music, networking, parallelism, client-server and XML using game design as an example. Topics in object-oriented program design including UML and design patterns. Introduction to advanced Java APIs such as awt, swing, io, nio, sound, net and xml. • Prerequisites:two COSC credits or permission of the instructor. • Java: Java 8 or greater and NetBeans
Textbooks • Main Course Material • SLIDES and NOTES (available through the webpage) • Supplemental Texts • Developing Games in Java, D. Brackeen, New Riders (2003), ISBN 1-5927-3005-1 • Object-Oriented Software Development Using Java, second edition, Xiaoping Jia, Addison Wesley (2002), ISBN 0-201-73733-7
Course Work • Marking Scheme • Project = 5 Programming parts 60% (done in class/lab, 5%, 10%, 3x15%) • Final Exam 40% (Saturday Aug 31, 10:00am -noon, TH246) • Programming parts 1-5 due by the end of each day (05:00pm) starting on Monday, August 26.
Design principles Design principles in this course and used by the design patterns • Use abstraction whenever possible • introduce (abstract) superclass (or interfaces) in order to implement or define common behavior • nothing should be implemented twice • Program to an interface, not an implementation • Favor composition over inheritance • delegation • Design for change and extension
Basic programming principles The following principles will produce code that is easy to understand without any unforeseen effects. • Do not use side effects in expressions. • Construct blocks of code as single entry-exit blocks, i.e., • No break statements. • Only exception to this rule are breaks within switch statements. • No “forever”-loops. • The only return statement in a method should be the last statement of the method.
Classes [ClassModifiers] class ClassName [extends SuperClass] [implements Interface1, Interface2, …] { ClassMemberDeclarations } • Class modifiers • visibility: package versus public • abstract • final • extends clause specifies the superclass • implements clause specifies the interfaces being implemented
Class members • Class (static) members • one occurrence for entire class • shared access by all instances • if visible, accessed via class name • public static void main(String[] args) {…} • Member modifiers • public versus protected versus package versus private • abstract • final • synchronized (method) • native (method) • volatile (field) • transient (field)
Inheritance • Parent/child, superclass/subclass • Instances of child inherit data and behaviour of parent • implements • inheritance of specification • extends • subclassing • inheritance of code and specification • overriding • polymorphism • Subclass versus subtype • substitutability • Subclass as an extension of behavior (specialization) • Subtype as a contraction of value space (specialization)
Subtypes • a subclass extends the capability of its superclass; the subclass inherits features from its superclass and adds more features • every instance of a subclass is an instance of the superclass • each class defines a type • Definition: Subtype Type T1 is a subtype of type T2 if every legitimate value of T1 is also a legitimate value of T2. In this case, T2 is a supertype of T1. Substitutability of subtypes: A value of a subtype can appear wherever a value of its supertype is expected.
Overriding versus Overloading • Overloading • methods • same name, different signatures • same class or subclass • effect – multiple methods with same name • do not overuse (readability of programs) • overloading should be used only in two situations: • When there is a general, non-discriminative description of the functionality that fits all the overloaded methods. • When all the overloaded methods offer the same functionality, with some of them providing default arguments. • Overriding • instance methods • same name, signature and result type • in subclass • effect – replacement implementation • access superclass version via super
Forms of inheritance • Inheritance for specification • parent provides specification • abstract classes • interfaces • behaviour implemented in child • subtype • Inheritance for extension • adding behaviour • subtype • Inheritance for specialization • child is special case • child overrides behavior to extend • subtype
Inheritance for construction • inherit functionality • ad hoc inheritance • not a subtype • use composition • Inheritance for limitation • restricting behaviour • not subtype • use composition • Inheritance for combination • combining behaviours • multiple inheritance • only through interfaces in Java
Inheritance for Specification: Java interfaceCh.8.4, Budd: Understanding Object-Oriented Programming with Java interface ActionListener { public void actionPerformed (ActionEvent e); } class CannonWorld extends Frame { … // a fire button listener implements the action // listener interface private class FireButtonListener implements ActionListener { public void actionPerformed (ActionEvent e) { … // action to perform in response to button press } } }
Inheritance for Specification: abstract classCh.8.4, Budd: Understanding Object-Oriented Programming with Java public abstract class Number { public abstract int intValue(); public abstract long longValue(); public abstract float floatValue(); public abstract double doubleValue(); public byte byteValue() { return (byte) intValue(); } public short shortValue() { return (short) intValue(); } }
Inheritance for ExtensionCh.8.4, Budd: Understanding Object-Oriented Programming with Java class Properties extends Hashtable { … public synchronized void load(InputStream in) throws IOException {…} public synchronized void save(OutputStream out, String header) {…} public String getProperty(String key) {…} public Enumeration propertyNames() {…} public void list(PrintStream out) {…} }
Inheritance for Specialization public class MyCar extends Car { … public void startEngine() { motivateCar(); super.startEngine(); } … }
Inheritance for Construction Ch.8.4, Budd: Understanding Object-Oriented Programming with Java class Stack extends LinkedList { public Object push(Object item) { addElement(item); return item; } public boolean empty() { return isEmpty(); } public synchronized Object pop() { Object obj = peek(); removeElementAt(size() - 1); return obj; } public synchronized Object peek() { return elementAt(size() - 1); } }
Inheritance for LimitationCh.8.4, Budd: Understanding Object-Oriented Programming with Java class Set extends LinkedList { // methods addElement, removeElement, contains, // isEmpty and size are all inherited from LinkedList public int indexOf(Object obj) { System.out.println(“Do not use Set.indexOf”); return 0; } public Object elementAt(int index) { return null; } }
Inheritance for Combination public class Mouse extends Vegetarian implements Food { … protected RealAnimal getChild() { … } … public int getFoodAmount() { … } … }
Vehicle - speed : Integer + Vehicle(speed : Integer) + getSpeed() : Integer {leaf} + accelerate() Truck # trailer : Trailer + Truck(speed : Integer, tr : Trailer) <<interface>> Cloneable + clone() : Object 1 MyCar {leaf} + MyCar(speed : Int) + accelerate() Trailer + CAPACITY : Integer {readonly} + Trailer() + clone() : Object UML Class diagrams 0..* 1
Composition • Composition has-a relationship (strong ownership) • Inheritance is-a relationship • Inheritance versus composition • desire to reuse existing implementation • substitutability (subtype) • subclass inherits specification and all methods and variables • composition allows selective reuse
LinkedList + addElement(obj : Object) + removeElement(obj : Object) + contains(obj : Object) : boolean + isEmpty() : boolean + size() : int + indexOf(obj : Object) : int + elementAt(index : int) : Object Set + indexOf(obj : Object) : int + elementAt(index : int) : Object UML Class diagramsInheritance versus Composition public int indexOf(Object obj) { System.out.println(“Do not use Set.indexOf”); return 0; } public Object elementAt(int index) { System.out.println(“Do not use Set.elementAt”); return null; }
LinkedList + addElement(obj : Object) + removeElement(obj : Object) + contains(obj : Object) : boolean + isEmpty() : boolean + size() : int + indexOf(obj : Object) : int + elementAt(index : int) : Object Set - content : LinkedList + addElement(obj : Object) + removeElement(obj : Object) + contains(obj : Object) : boolean + isEmpty() : boolean + size() : int UML Class diagramsInheritance versus Composition 0..1 1 public void addElement(Object obj) { content.addElement(obj); } … public int size(){ return content.size(); }
Generics • Up to Java 4 • container classes store object of class Object • storing elements in a container uses subtype polymorphism • accessing elements in a container requires type casting Stack s = new Stack(); s.push(new Integer(3)); Integer n = (Integer) s.pop(); // cast required s.push(”abc”); // no error Integer second = (Integer) s.pop(); // runtime error // (ClassCastException)
Generics (cont’d) • from Java 5 • generic classes (similar to templates in C++) Stack<Integer> s = new Stack<Integer>(); s.push(new Integer(3)); Integer n = s.pop(); // no cast required s.push(”abc”); // type error // (at compile time)
Generic (cont’d) Advantages of generics : • Strong static type-checking • fewer ClassCastExceptions • fewer casts • no unchecked warnings • Improved readability • Better tool support • No future deprecation
E MyGenericClass Generics - UML class diagram A class generic in E <<bind>>E MyClass1 An instantiation of the generic class using the class MyClass1. MyInstantiationClass Two short forms for an instantiation (useful if generic class is not part of the diagram. MyGenericClass<E MyClass2> or MyGenericClass<MyClass2>
Generics - Example public class Pair<X,Y> { private X first; // first component of type X private Y second; // second component of type Y public <A extends X,B extends Y> Pair(A a,B b) { first = a; second = b; } // constructor public Pair(Pair<? extends X, ? extends Y> p) { first = p.getFirst(); second = p.getSecond(); } // constructor
Generics – Example (cont’d) public X getFirst() { return first; } // getFirst public void setFirst(X x) { first = x; } // setFirst public Y getSecond() { return second; } // getSecond public void setSecond(Y y) { second = y; } // setSecond public boolean equals(Object obj) { if (obj instanceof Pair<?,?>) { Pair<?,?> p = (Pair<?,?>) obj; return first == p.getFirst() && second == p.getSecond(); }; return false; } // equals
Auto boxing • in Java 4 Stack s = new Stack(); s.push(new Integer(3)); // wrapper class needed Integer n = (Integer) s.pop(); • from Java 5 Stack<Integer> s = new Stack<Integer>(); s.push(3); // auto boxing int n = s.pop(); // again auto boxing s.push(new Integer(1)); // without boxing Integer num = s.pop(); // again without boxing s.push(2); // any combination num = s.pop(); // possible
Iterations • in Java 4 List strings; ... for(int i = 0; i < strings.size(); i++) { String str = strings.elementAt(i); System.out.println(str); } or better using an iterator for(Iterator iter = strings.iterator(); iter.hasNext();) { String str = (String) iter.next(); System.out.println(str); }
Iterations (cont’d) • from Java 5 List<String> strings; ... for(String str : strings) { System.out.println(str); } int[] vector = new int[100]; ... int sum = 0; for(int elem : vector) sum += elem;
Enumeration types • in Java 4 • enumeration types are implemented by using the type int public static final int RED = 0; public static final int YELLOW = 1; public static final int BLUE = 2; ... switch(myColor) { case Color.RED: System.out.println(”red”); break; case Color.YELLOW: System.out.println(”yellow”); break; case Color.BLUE: System.out.println(”blue”); break; };
Enumeration types (cont’d) Advantages of explicit enumeration types: • they are type safe (checked at compile time) • int enums don't provide any type safety at all • they provide a proper name space for the enumerated type • with int enums you have to prefix the constants to get any semblance of a name space • they are robust • int enums are compiled into clients, and you have to recompile clients if you add, remove, or reorder constants • printed values are informative • if you print an int enum you just see a number • can be stored in collections (objects) • arbitrary fields and methods can be added
Enumeration types (cont’d) Simple example: public enum Color {RED, YELLOW, BLUE}; ... for (Color myColor : Color.values()) System.out.println(myColor); values() is a static method of an enumeration type returning an array containing all the values of the enum type in the order they are declared.
public enum Planet { MERCURY (3.303e+23, 2.4397e6), VENUS (4.869e+24, 6.0518e6), EARTH (5.976e+24, 6.37814e6), MARS (6.421e+23, 3.3972e6), JUPITER (1.9e+27, 7.1492e7), SATURN (5.688e+26, 6.0268e7), URANUS (8.686e+25, 2.5559e7), NEPTUNE (1.024e+26, 2.4746e7), PLUTO (1.27e+22, 1.137e6); private final double mass; // in kilograms private final double radius; // in meters Planet(double mass, double radius) { this.mass = mass; this.radius = radius; } public double mass() { return mass; } public double radius() { return radius; } // universal gravitational constant (m3 kg-1 s-2) public static final double G = 6.67300E-11; public double surfaceGravity() { return G * mass / (radius * radius); } public double surfaceWeight(double otherMass) { return otherMass * surfaceGravity(); } }
public enum Operation { PLUS { double eval(double x, double y) { return x + y; } }, MINUS { double eval(double x, double y) { return x - y; } }, TIMES { double eval(double x, double y) { return x * y; } }, DIVIDE { double eval(double x, double y) { return x / y; }}; // Do arithmetic op represented by this constant abstract double eval(double x, double y); } public static void main(String args[]) { double x = Double.parseDouble(args[0]); double y = Double.parseDouble(args[1]); for (Operation op : Operation.values()) System.out.printf("%f%s%f=%f%n",x,op,y,op.eval(x,y)); }
<<enumeration>> Planet MERCURY VENUS EARTH MARS JUPITER SATURN URANUS NEPTUNE PLUTO + G : double { readonly } + mass() : double + radius() : double + surfaceGravity() : double + surfaceWeight(double) : double Enum types - UML class diagram
Static import Static import • in Java 4 double sinus = Math.sin(Math.PI/2.0); • from Java 5 import static java.lang.Math.*; double sinus = sin(PI/2.0); • import of all static components of a class • usage without class prefix • different from import java.util.*;
Lambda Expressions and Method References Old style of an external iterator to traverse a list (before Java 8): for(String item : items){ System.out.println(item); } New style using an internal iterator (forEach) and a lambda expression: items.forEach(item->System.out.println(item)); Same loop using a reference to the static method println: items.forEach(System.out::println);
Lambda Expressions and Method References Another use for a lambda expression (sorting an array): Arrays.sort(myPersonArray, (a, b) -> Person.compareByAge(a, b) ); Same call using a reference to the static method compareByAge: Arrays.sort(myPersomArray, Person::compareByAge); Similar call using a reference to a method of the myComparator object: Arrays.sort(myPersomArray, myComparator::compareByName);
Lambda Expressions and Method References Streams offer additional features such as filters: items.stream().filter(s->s.contains("B")) .forEach(System.out::println); A very fancy example using streams: Streams.iterate(1,number -> number + 1) .map(number -> number * number) .limit(25) .forEach(number -> System.out.println(number + “ “)); Output: 1 4 9 16 25 36 49 64 … 529 576 625
Lambda Expressions and Method References Another example is creating a thread (see Day 3): Runnable r1 = new Runnable() { public void run() { System.out.println("Old Way"); } ; new Thread(r1).start(); Instead of creating a Runnable object we can use a lambda expression: new Thread(() -> System.out.println("New Way")).start();
Class Object • Common parent (base class) • Minimal functionality • Classes may override to provide specific behaviour • public boolean equals(Object other) {…} • public int hashCode() {…} • public String toString() {…} • public Class getClass() {…} • public Object clone() {…}
Serialization • Serialization is the process of transforming an object into a stream of bytes. • Deserialization is the reverse process. public interface Serializable {}; • Making an object serializable requires almost no effort (the interface Serializable is empty). • More complex operations may be necessary if, for instance, just a portion of an object’s state is to be saved on the output stream.
Serialization (cont.) import java.io.*; public class IntPair implements Serializable { int x; int y; public IntPair(int x, int y) { this.x = x; this.y = y; } public String toString() { return “(" + x + "," + y + ")"; } }
Serialization (cont.) import java.io.*; public class inout { public static void main(String[] args) { IntPair p = new IntPair(2,3); try { ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream(Filename)); out.writeObject(p); out.close(); } catch(IOException e) { e.printStackTrace(); } } }
Serialization (cont.) import java.io.*; public class inout { public static void main(String[] args) { try { ObjectInputStream in = new ObjectInputStream( new FileInputStream(Filename)); IntPair p = (IntPair) in.readObject(); System.out.println(p); } catch(Exception e) { e.printStackTrace(); } } }