[CS61B-Sp18] OOP

Inheritance

Hypernym and Hyponym

Interface: the Hypernym

  • All methods must be public, therefore public is redundant.
  • All variables are public static final (value can never change)
  • Cannot be instantiated
  • Can implement more than one interface per class
Interface Inheritance
  • What the subclasses are able to do
  • Abstract methods: no {}
  • Provide method declarations
public interface List61B<Item> {
    public void addFirst(Item x);
    public void add Last(Item y);
    public Item getFirst();
    public Item getLast();
    public Item removeLast();
    public Item get(int i);
    public void insert(Item x, int position);
    public int size();
}
Implementation Inheritance
  • How the subclasses should behave
  • Default (concrete) methods
  • Provide implementation with keyword default
default public void print() {
    for (int i = 0; i < size(); i += 1) {
        System.out.print(get(i) + " ");
    }
    System.out.println();
}

Subclass Definition: the Hyponym

public class AList<Item> implements List61B<Item>{...}

Overriding

  • @Override tag before subclass method signature
  • Run time polymorphism
  • Derived class provides the specific implementation of the method that is already provided by the base class or parent class. Return type must be same or co-variant (return type may vary in same direction as the derived class).
@Override
public void addFirst(Item x) {
    insert(x, 0);
}
Dynamic method selection
List61B<String> lst = new SLList<String>();
  • List61B is the “static type” and SLList is the “dynamic type”
  • lst is a pointer of List61B(static) type pointer pointing to a SLList(dynamic) type object
  • Does not work for Overloading
  • Java checks static type to see which matches the method signature

Extends

public class RotatingSLList<Item> extends SLList<Item>

The extends keyword lets us keep the original functionality of SLList, while enabling us to make modifications and add additional functionality.

implements defines the relationship between interface and classes, whereas extends defines the relationship between classes. Child class is a parrent class.

By using the extends keyword, subclasses inherit all members of the parent class. “Members” includes:

  • All instance and static variables
  • All methods
  • All nested classes

Constructors are not inherited, and private members cannot be directly accessed by subclasses.

Example: VengefulSLList

  • @Override tag: Overrides the removeLast() method in SLList
  • super: access the member in parent class
public class VengefulSLList<Item> extends SLList<Item> {
    SLList<Item> deletedItems;

    public VengefulSLList() {
        deletedItems = new SLList<Item>();
    }

    @Override
    public Item removeLast() {
        Item x = super.removeLast();
        deletedItems.addLast(x);
        return x;
    }

    /** Prints deleted items. */
    public void printLostItems() {
        deletedItems.print();
    }
}

Constructors: the Not-Inherited

Explicit: constructors must start with a call to one of its superclass’s constructors. Pass proper parameters when calling super().

Implicit: Or, if we choose not to, Java will automatically make a call to the superclass’s no-argument constructor for us.

The Object Class

All the classes extends Object implicitly. As seen in the documentation for the Object class, the Object class provides operations that every Object should be able to do.

Type checking

If method is overidden, dynamic method selection. If not overriden, use static method.

Compiler determines whether or not something is valid based on the static type of the object. Even though dynamic type is valid, still generates error.

Compile-time (static) type of expressions

Assignment
SLList<Integer> sl = new VengefulSLList<Integer>();

VALID: Above, the compile-time type of the RHS is VengefulSLList. The compiler checks to make sure that VengefulSLList “is-a” SLList, and allows this assignment.

VengefulSLList<Integer> vsl = new SLList<Integer>();

ERROR: Above, the compile-time type of the RHS is SLList. The compiler checks if SLList “is-a” VengefulSLList, which it is not in all cases, and thus a compilation error results.

Method calls
public static Dog maxDog(Dog d1, Dog d2) { ... }

The static type of maxDog is Dog.

Poodle frank = new Poodle("Frank", 5);
Poodle frankJr = new Poodle("Frank Jr.", 15);

Dog largerDog = maxDog(frank, frankJr);
Poodle largerPoodle = maxDog(frank, frankJr); //A dog is a poodle? Does not compile! RHS has compile-time type Dog

Casting

Poodle largerPoodle = (Poodle) maxDog(frank, frankJr); 
// compiles! RHS has compile-time type Poodle after casting

Casting is dangerous. Casting is telling the compiler not to do its type-checking duties - telling it to trust you and act the way you want it to. May compile but throw error during run time.

Higher Order Functions

In Python:

def tenX(x):
    return 10*x

def do_twice(f, x):
    return f(f(x))

In Java:

The initial problem: no function pointer

public interface IntUnaryFunction {
    int apply(int x);
}
public class TenX implements IntUnaryFunction {
    /* Returns ten times the argument. */
    public int apply(int x) {
        return 10 * x;
    }
}
public static int do_twice(IntUnaryFunction f, int x) {
    return f.apply(f.apply(x));
}
System.out.println(do_twice(new TenX(), 2));

Subtype Polymorphism

Example: Comparable

Compare two objects and return the max.

max function

public static Dog maxDog(Dog[] dogs) {
    if (dogs == null || dogs.length == 0) {
        return null;
    }
    Dog maxDog = dogs[0];
    for (Dog d : dogs) {
        if (d.size > maxDog.size) {
            maxDog = d;
        }
    }
    return maxDog;
}

public static void main(String[] args) {
    Dog[] dogs = {new Dog("Elyse", 3), new Dog("Sture", 9), new Dog("Benjamin", 15)};
    Dog maxDog = maxDog(dogs);
    maxDog.bark();
}

Deficiency:

  • Code redundancy: specific to dog not general enough, inflexible measure of comparison.
  • fundamental issue: Objects cannot be compared with >

OurComparable
在这里插入图片描述

public interface OurComparable {
    public int compareTo(Object o);
}

Define a interface for objects that are able to compare to other objects.

public class Dog implements OurComparable {
    private String name;
    private int size;

    public Dog(String n, int s) {
        name = n;
        size = s;
    }

    public void bark() {
        System.out.println(name + " says: bark");
    }

    public int compareTo(Object o) {
        Dog uddaDog = (Dog) o;
        return this.size - uddaDog.size;
    }
}

Notice that since compareTo takes in any arbitrary Object o, we have to cast the input to a Dog to make our comparison using the size instance variable.

public static OurComparable max(OurComparable[] items) {
    int maxDex = 0;
    for (int i = 0; i < items.length; i += 1) {
        int cmp = items[i].compareTo(items[maxDex]);
        if (cmp > 0) {
            maxDex = i;
        }
    }
    return items[maxDex];
}

max function can take in an array of any OurComparable type objects and return the maximum object in the array.

Advantages:

  • max function can be used by any object that implements ourComparable.
  • Do not need to have a max function for each class. Only a compareTo() would do.

Deficiencies:

  • Not a built-in interface. There are tons of classes that do not have compareTo() function.
  • Wierd casting.

Comparable
在这里插入图片描述

public class Dog implements Comparable<Dog> {
    private String name;
    private int size;

    public Dog(String n, int s) {
        name = n;
        size = s;
    }

    public void bark() {
        System.out.println(name + " says: bark");
    }

    public int compareTo(Dog uddaDog) {
        return this.size - uddaDog.size;
    }
}

Notice that since compareTo takes in Dog now. It avoids wierd casting as seen in advantages section.

public static Comparable max(Comparable[] items) {
  // Not Comparable<Dog>[]
    int maxDex = 0;
    for (int i = 0; i < items.length; i += 1) {
        int cmp = items[i].compareTo(items[maxDex]);
        if (cmp > 0) {
            maxDex = i;
        }
    }
    return items[maxDex];
}

Changes OurComparable to Comparable in max function.

public static void main(String[] args) {
    Dog[] dogs = {new Dog("Elyse", 3), new Dog("Sture", 9), new Dog("Benjamin", 15)};
    Dog maxDog = (Dog) Maximizer.max(dogs);
    maxDog.bark();
}

Main function does not change. Still need casting at return type of max function.

Advantages:

  • Classes like String use Comparable
  • Libraries like Array.sort(), Collection.max() use Comparable
  • Avoids casting: see below

The better Comparable avoids casting:

public class Dog implements Comparable<Dog> {
  public int compareTo(Dog uddaDog) {
    return this.size - uddaDog.size;
  }
}

OurComparable: Wierd casting

public class Dog implements OurComparable {
  public int compareTo(Object obj) {
    Dog uddaDog = (Dog) obj;
    return this.size - uddaDog.size;
  }
}

Deficiency:

  • Dog maxDog = (Dog) Maximizer.max(dogs); still uses casting
  • Can only compare objects from same class
  • Does not support multiple ordering

Comparator

在这里插入图片描述

Comparator is a java interface. The object that implements Comparator must have a compare method.

public interface Comparator<T> {
    int compare(T o1, T o2);
}

Since a comparator is an object, we’ll use Comparator by writing a nested class inside Dog that implements the Comparator interface. The Dog class now has a NameComparator in it, which has a compare method, which defers to String's already defined compareTo method.

import java.util.Comparator;

public class Dog implements Comparable<Dog> {
    ...
    public int compareTo(Dog uddaDog) {
        return this.size - uddaDog.size;
    }

    private static class NameComparator implements Comparator<Dog> {
        public int compare(Dog a, Dog b) {
            return a.name.compareTo(b.name);
          	// deferring to String's compareTo()
        }
    }

    public static Comparator<Dog> getNameComparator() {
        return new NameComparator();
    }
  
}

The NameComparator is a static class because we do not need to instantiate a Dog to get a NameComparator.

If there is no getNameComparator() in the Dog class, in main(), we can use NameComparator like this:

Dog.NameComparator<Dog> nc =  new Dog.NameComparator();
if(nc.compare(d1,d3)>0) ...

To improve, create a getter function for main to use the NameComparator:

import java.util.Comparator;
....
//NameComparator is the subclass of Comparator<Dog>
Comparator<Dog> nc = Dog.getNameComparator();
if(nc.compare(d1,d3)>0) ...

Comparator is like a third-party machine that compares two objects whereas Comparable compares another object to itself because itself is a comparable object.

Java Libraries

在这里插入图片描述

List, Set, Map Demo

List: Method getWords takes in a String inputFileName and puts every word into a list.

package: import java.util.List; import java.util.ArrayList;

public static List<String> getWords(String inputFileName) {
    List<String> lst = new ArrayList<String>();
    In in = new In();
    while (!in.isEmpty()) {
        lst.add(in.readString()); //optionally, define a cleanString() method that cleans the string first.       
    }
    return lst;
}

Set: Method countUniqueWords takes in a List<String> and counts how many unique words there are in the file.

package: import java.util.Set; import java.util.HashSet;

public static int countUniqueWords(List<String> words) {
    Set<String> ss = new HashSet<>();
    for (String s : words) { // enhanced for loop
           ss.add(s);        
    }
    return ss.size();
}

**Map: **Method collectWordCount takes in a taget and words List<String> and counts how many times words in target appears in the words list.

package: import java.util.Map; import java.util.HashMap;

public static Map<String, Integer> collectWordCount(List<String> words, List<String> target) {
    Map<String, Integer> counts = new HashMap<String, Integer>();
    for (String t: target) { // set up empty counts
        counts.put(s, 0);
    }
    for (String s: words) { // actually count the words
        if (counts.containsKey(s)) {
            counts.put(word, counts.get(s)+1);
        }
    }
    return counts;
}

Why java?

  • Takes less time to write programs:

    1. Static types (type checking and helps guide programmer)
    2. Force interface inheritance leading to cleaner subtype polymorphism
    3. Access control modifiers
  • More efficient code:

    1. more control over engineering tradeoffs (ADTs)

    2. Single valued arrays lead to better performance (?)

  • Basic data structures more closely resemble underlying hardware

Abstract Classes

An intermediate level between interfaces and classes.

InterfaceAbstract Class
Methods must be publicMethods can be public or private
Variables must be public static finalCan have any types of variables
Cannot be instantiatedCannot be instantiated
Methods are by default abstract unless specified to be defaultMethods are by default concrete unless specified to be abstract
Can implement more than one interface per classCan only implement one per class

When in doubt, use interfaces.

Packages

Package names give give a canonical name for everything.

import ug.joshh.animal.Dog or import ug.joshh.animal.*

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值