0% found this document useful (0 votes)
54 views11 pages

Cs 131 Notes

The document discusses Java concepts including interfaces, inheritance, polymorphism, exceptions, and the visitor pattern. It provides code examples to illustrate interface and class definitions, inheritance relationships between classes, exception handling, and using the visitor pattern to add new operations to existing types.

Uploaded by

jtai1
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as ODT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
54 views11 pages

Cs 131 Notes

The document discusses Java concepts including interfaces, inheritance, polymorphism, exceptions, and the visitor pattern. It provides code examples to illustrate interface and class definitions, inheritance relationships between classes, exception handling, and using the visitor pattern to add new operations to existing types.

Uploaded by

jtai1
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as ODT, PDF, TXT or read online on Scribd
You are on page 1/ 11

05/05 JAVA LECTURE interface StringSet { boolean isEmpty(); void add(String s); boolean contains(String s); String get();

; } /* StringSet s = new ArraySet(); if(s.isEmpty()) { s.add("hello"); } */ class ArraySet implements StringSet { protected String[] elems; protected int size; public boolean isEmpty() { return size == 0; } public boolean equals(Object o) { ... } } // generics, or parametric polymorphism interface Set<E> { boolean isEmpty(); void add(E item); boolean contains(E item); E get(); } /* Set<String> s1 = ...; s1.add("hello"); Set<Shape> s2 = ...; s2.add(new Circle()); */ /* subtype polymorphism */ interface RemovableStringSet extends StringSet { void remove(String s); } class RemovableArraySet extends ArraySet implements RemovableStringSet { // inheriting all the operations from ArraySet public void remove(String s) { ... } } /* subtype polymorphism: if T1 is a subtype of T2, then values of type T1 can be used wherever values of type T2 are expected */ void union(StringSet s1, StringSet s2) { ... } RemovableStringSet rs = ...; union(rs, new ArraySet());

RemovableStringSet rs = ...; StringSet s = rs; rs.add("hello"); rs.remove("hello"); s.remove("hello"); // compile-time type error interface ObjectSet { boolean isEmpty(); void add(Object s); boolean contains(Object s); Object get(); } ObjectSet s = ...; s.add("hello"); // typechecks because String is a subtype of Object Object o = s.get(); // ack! lost the fact that this is a set of strings Object is the top of the class hierarchy, implicitly class Object { String toString(); boolean equals(Object equals); } Don't confuse subtyping with inheritance: Subtyping is an "interface-level" property about behavioral/semantic compatibility: - S is a subtype of T if I can use an S wherever a T is expected Inheritance is an "implementation-level" property that allows for code reuse - if C inherits from D, then C is reusing some of the methods and fields of D - just a convenience: I could just copy the methods/fields of D into C manually * Subtyping without inheritance: You might want to consider a Square to be a subtype of Rectangle. - allows squares to be passed wherever Rectangles are expected interface Rect { ... } class Rectangle implements Rect { int length; int width; ... } class Square implements Rect { int side; ... } * Inheritance without subtyping - want Bags and Sets to share code without being in a subtype relationship - wouldn't make sense since they do different things for add() (one allows duplicates; the other does not) abstract class Collection { Object[] elems; ... // shared methods } class Bag extends Collection { ... }

class Set extends Collection { ... } Dynamic dispatch: on a method call, invoke the "most-specific" method implementation for the run-time class of the receiver object class C { void n() { this.m(); } void m(); } class D extends C { void m() {} } D d = new D(); C c = d; d.m(); // invokes D's m method c.m(); // invokes D's m method d.n(); c.n(); // invokes D's m method // invokes D's m method

void myMethod(C c) { c.n(); } class MyClass { private List lst = new ArrayList(); } Good OO style: an object knows how to do certain things. - client should manipulate an object only through its interface - client never knows what implementation the object uses Example: chess game interface Piece { ... } class Rook implements Piece { ... } class Pawn implements Piece { ... } ... class Board { void badMove(Piece p, int x, int y) { if (p instanceof Pawn) { ... check whether it's a legal move, and if so make it } else if (p instanceof Rook) { ... } } void goodMove(Piece p, int x, int y) { if (p.isValidMove(x,y)) { p.move(x,y); } } }

05/12 EXCEPTIONS PAIR.JAVA

interface Pair<F,S> { F first(); S second(); } class IntStringPair implements Pair<Integer,String> { public Integer first() { return 0; } public String second() { return "hi"; } } interface Drawable { void draw(); } class Shape implements Drawable { } public void draw() { }

class PairImpl<T1 extends Drawable, T2 extends Drawable> implements Pair<T1,T2>, Drawable { protected T1 fst; protected T2 snd; PairImpl(T1 f, T2 s) { fst = f; snd = s; } public String toString() { return "(" + fst.toString() + ", " + snd.toString() + ")"; } public void draw() { fst.draw(); snd.draw(); } public T1 first() { return fst; } public T2 second() { return snd; }

class Main { public static void main(String[] args) { Pair<Integer,String> p = new IntStringPair(); // // Pair<Integer,String> p2 = new PairImpl<Integer,String>(new Integer(45), "hello"); Pair<Shape,Shape> p2 = new PairImpl<Shape,Shape>(new Shape(), new Shape()); System.out.println(p2.toString()); Integer i = p.first(); int j = i.intValue() + 45; System.out.println("first is " + i.toString()); } }

EXCEPTIONS.JAVA

class OutOfBoundsException extends Exception { OutOfBoundsException() {} OutOfBoundsException(String message) { super(message); } } // unchecked exception class FatalError extends RuntimeException {} class OtherException extends Exception {} interface List<T> { void add(int i); T get(int i) throws OutOfBoundsException; } class ListImpl<T> implements List<T> { // add an element at position i public void add(int i) { } void helper() throws OtherException { throw new OtherException(); } // get the element at position i public T get(int i) throws OutOfBoundsException { if (i < 0) throw new OutOfBoundsException("negative index"); // ... if (i > 1000) throw new FatalError(); try { this.helper(); } catch(OtherException e) { System.out.println("caught the exception"); } // can have multiple catch blocks // catch(AnotherException e) { // ... } return null; }

// //

05/19 VISITOR.JAVA // visitor pattern: adding new operations to existing types // represent a new operation on Nodes that returns a String interface Visitor { String visitEmptyNode(EmptyNode n); String visitValueNode(ValueNode n); } class ConcatAll implements Visitor { public String visitEmptyNode(EmptyNode n) { return ""; } public String visitValueNode(ValueNode n) { return n.value + n.next.accept(this); }

/* ListNode n = ...; n.accept(new ConcatAll()); */ interface Node { int size(); String accept(Visitor v); /* generic version: <A,R> R accept(Visitor v, A a); */

class EmptyNode implements Node { public int size() { return 0; } public String accept(Visitor v) { return v.visitEmptyNode(this); }

class ValueNode implements Node { String value; Node next; ValueNode(String v, Node n) { value = v; next = n; } public int size() { return 1 + next.size(); } public String accept(Visitor v) { return v.visitValueNode(this); } }

05/17 NODES.JAVA import java.util.Iterator; import java.lang.Iterable; // an exception for places in the code that you need to implement class ImplementMe extends RuntimeException {} // an interface for sets of strings interface Set { // is string s in the set? boolean contains(String s); // add an element; no duplicates allowed void add(String s); // how many elements are in the set? int size(); } // a type for nodes in the linked list interface ListNode { boolean contains(String s); ListNode add(String s); int size(); } // a sentinel indicating that we've reached the end of the linked list class EmptyNode implements ListNode { ListSet set; EmptyNode(ListSet s) { this.set = s; } public boolean contains(String s) { return false; } public ListNode add(String s) { return set.valuenode(s, this); } public int size() { return 0; } public String value() { return null; } public ListNode next() { return null; } } class ValueNode implements ListNode { // the element stored in this node protected String value; // a pointer to the next node in the list protected ListNode next; ValueNode(String value, ListNode next) { this.value = value; this.next = next; } public boolean contains(String s) { return s.equals(value) || next.contains(s); } public ListNode add(String s) { next = next.add(s);

return this;

public int size() { return 1 + next.size(); } public String value() { return value; } public ListNode next() { return next; }

class ListSet implements Set { // the head of the linked list of nodes protected ListNode head; ListSet() { head = this.emptynode(); } // factory methods public ListNode emptynode() { return new EmptyNode(this); } public ListNode valuenode(String s, ListNode n) { return new ValueNode(s, n); } public boolean contains(String s) { return head.contains(s); } public void add(String s) { if(contains(s)) return; head = head.add(s); } public int size() { return head.size(); }

class SortedValueNode extends ValueNode { SortedValueNode(String s, ListNode n) { super(s,n); } } class SortedListSet extends ListSet { // no need to create a new kind of empty node now! public ListNode valuenode(String s, ListNode n) { return new SortedValueNode(s, n); } SortedListSet() { super(); } } class Test { public static void main(String[] args) { Set s1 = new ListSet(); s1.add("hello"); s1.add("hi"); s1.add("hello"); System.out.println("test 1: " + (s1.contains("hi") == true)); System.out.println("test 2: " + (s1.contains("bye") == false)); System.out.println("test 3: " + (s1.size() == 2));

05/19 MULTIMETHOD3.JAVA /* double dispatch: - gets the right behavior - cumbersome, error-prone (but at least no casts) - tedious to extend */ interface Shape { boolean intersect(Shape s); boolean intersectRect(Rectangle r); boolean intersectTri(Triangle t); } class Rectangle implements Shape { public boolean intersect(Shape s) { return s.intersectRect(this); } public boolean intersectRect(Rectangle r) { /* implement intersection of a rect and a rect */ System.out.println("rect, rect"); return true; } public boolean intersectTri(Triangle t) { /* implement intersection of a rect and a tri */ System.out.println("rect, tri"); return true; } } class Triangle implements Shape { public boolean intersect(Shape s) { return s.intersectTri(this); } public boolean intersectRect(Rectangle r) { /* implement intersection of a rect and a tri */ System.out.println("tri, rect"); return true; } public boolean intersectTri(Triangle t) { /* implement intersection of a tri with a tri */ System.out.println("tri, tri"); return true; } } class Client { public static void main(String[] args) { Shape r = new Rectangle(); Shape t = new Triangle(); r.intersect(t); }

05/31 MGU
*unification* E1 = E2 tries to find a substitution s (mapping from variables to terms) such that s(E1) = s(E2) (the trees are equal) otherwise says "no" ---s is a *unifier* for t1 and t2 if s(t1) = s(t2). there's always a *most general unifier* (MGU) or substitution for any two terms that unify: s is an MGU for t1 and t2 if s is a unifier for t1 and t2 and for any other unifier s', there exists a substitution s'' such that s''(s(t1)) = s'(t1) and s''(s(t2)) = s'(t2) example: f(X,Y) = f(a,Y)

{X->a, Y->a} {X->a, Y->b} ... MGU: {X->a} t=term, c=constant, a=atom, X=variable

Let's define MGU: MGU(c,c) = {} MGU(X,X) = {} mgu(x,t) = {x->t}

if x not in t, else "no"

[occurs check]

mgu(t,x) = {x->t} if x not in t, else "no" mgu(a(t1,...,tn), a(t1',...,tn')) = for each i, mgu(ti, ti') = si if any of those fails to unify, then return "no" otherwise if s1 u ... u sn is inconsistent return "no" else return s1 u ... u sn mgu(_, _) = "no" example: g(a, x, x) = g(y, b, z) - recursively ask a = y x = b x = z {y->a, x->b, x->z} ---> {y->a, x->b, z->b} example: mgu(x, f(x)) = {x->f(x)}

------------key computation step in prolog is *resolution*: a *clause* is either a fact or a rule. the head of a clause is either the fact itself (if a fact) or the head of the rule. the tail of a clause is nothing (if a fact) or the body of the rule. resolution(clause, list of goals to be proven): clause = renameVars(clause) // rename all vars to fresh names s = MGU(head(clause), head(goals)) return s(append(tail(clause), tail(goals))) example: 1. 1.5. 2. 3. 4. p(f(Y)) :- q(Y), r(Y). p(b). q(h(Z)) :- t(Z). r(h(a)). t(a).

resolution(p(f(Y)) :- q(Y), r(Y), [p(X)]) MGU(p(f(Y)), p(X)) = {X->f(Y)} return [q(Y), r(Y)] resolution(q(h(Z)) :- t(Z), [q(Y), r(Y)]) MGU(q(h(Z)), q(Y)) = {Y -> h(Z)} return [t(Z), r(h(Z))] resolution(t(a), [t(Z), r(h(Z))]) MGU(t(a), t(Z)) = {Z->a} return [r(h(a))] resolution(r(h(a)), [r(h(a))]), MGU(r(h(a)), r(h(a))) = {} return [] ------------rev(Res, [2,1]) 1. No 2. rev(T, X), app(X, [H], [2,1]) 1. app([], [H], [2,1]) (eventually "no") 2. rev(T',X'), app(X', [H'], X), app(X, [H], [2,1]) 1. app([],[H'],X), app(X,[H],[2,1]) (eventually "yes")

You might also like