【CS 61b study notes 3】Inheritance

Inheritance1

Hypernym and Hyponym

We know that SLLists and ALists are both clearly some kind of “list”

  • Hypernym and Hyponym example :
    • List is a Hypernym of SLList and AList
    • SLList is a Hyponym of List.
  • Hypernyms and Hyponyms comprise a hierarchy
  • Express this in Java is a two-step process:
    • step 1: Define a reference type for our hypernym(List61B)
      • We will use the new keyword interface instead of class to define List61B
        • Idea : Interface is a specification of what a List is able to do , not how to do.
    • step2 : Specify that SLLists and ALists are hyponyms of that type.

Overload & Override

  • Method Overriding in Java
    • If a “subclass” has a method with the exact same signature as in the “superclass” , we say the subclass overrides the method. Overriding happens in different classes (parent class & subclass)
  • Method Overloading in Java
    • Java allows multiple methods with same name , but different parameters (signatures) . This is called method overloading. Overloading often happens in the same class.
// superclass 
public interface List61B<Item>{
	public void test(Item y){
		
	}
	// overloading
	public void test(){
	}
}
// subclass -- overriding
public class Alist<Item> implements List61B<Item>{
	public void test(Item x){
	}
}

// abs is overloading as follows 
public class Math{
	public int abs(int a);
	public double abs(double b);
}
  • Difference

    • Overriding is something that only applies to inheritance relationship and only when we have the exact same method signatures.
    • Overloading happens in all kinds of place and it’s any time we have two methods that have the same name but different signature.
  • Adding the @Override Annotation

    • We can mark every overriding method with the @Override annotation.
    • The only effect of this tag is that the code won’t compile if it is not actually an overriding method.
  • Why using @Override

    • Main reason : Protect against typos
    • Reminds programmer that method definition came from somewhere

Interface Inheritance

Specifying the capabilities of a subclass using implements keyword is know as interface inheritance

  • Interface : The list of all method signatures

    • Interfaces are like blueprints for objects : they tell us what an object needs , but not how to implement them
    • They are very similar to normal classes except for some major differences :
      • All variables are constants (public static final)
      • Methods have no body just a signiture
      • Classed can inherit from multiple interfaces
  • Inheritance : The subclass “inherits” the interface from a superclass.

  • Specifies what the subclass can do , but not how.

  • Subclass must override all of this methods, it will fail to compile otherwise.

  • Copying the bits

    • If X is a superclass of Y, then memory boxes for X may contain Y.
  • Implementation Inheritance

    • Interface Inheritance: Subclass inherits signatures but NOT implementation.
    • Implementation Inheritance : Subclass can inherit signatures AND implementation.
    • Using the default keyword to specify a method that subclasses should inherit from an interface.
      • but default methods are not efficient to all subclass.
      • when the default methods are inefficient to the subclass ,we can override them.

Static type vs. Dynamic type

  • Static type
    • Every variable in java has a “compile-time type”, a.k.a. “static type”.
    • This is the type specified at declaration . Never changes!
  • Dynamic type
    • This is the type specified at instantiation (eg: when using new)
    • “run-time type” a.k.a. “dynamic type”
    • Equal to the type of the object being pointed at.

Suppose we call a method of an object using a variable with:

  • compile-time type X
  • run-time type Y

Then Y overrides the method , Y’s method is used instead. This is known as “dynamic method selection”.

public static void main(String[] args){
	List61B<String> s1 = new SLList<String>();
	// SLList is a subclass of List61B
	s1.print()
}

For s1, its static type is List61B, and its dynamic type is SLList.

  • Dynamic Method Selection Example

Pay attention to the difference of overriding and overloading

public interface Animal{
	default void greet(Animal a){
		System.out.println("hello animal");
	}
	default void sniff(Animal a){
		System.out.println("sniff animal");
	}
	default void praise(Animal a){
		System.out.println("u r cool animal");
	}
	default void voice(Animal a){
		System.out.println("animals' voice");
	}
}

public class Dog implements Animal{
	// default void greet(Animal a);
	@Override 
	void sniff(Animal a){
		System.out.println("dog sniff animal");
	}
	// default void praise(Animal a);
	void praise(Dog a){
		System.out.println("u r cool dog");
	}
	@Override
	void voice(Animal a){
		System.out.println("dogs' voice");
	}
	
	void voice(Dog a){
		System.out.println("bark! bark!");
	}
}

public static void main(String[] args){
	Animal a = new Dog(); //line 1
	Dog d = new Dog(); // line 2
	
	a.greet(a); // line3
	a.greet(d); // line4
	d.greet(a); // line5
	d.greet(d); // line6
	
	a.sniff(a); // line7
	a.sniff(d); // line8
	d.sniff(a); // line9
	d.sniff(d); // line10
	
	a.praise(a); // line11
	a.praise(d); // line12
	d.praise(a); // line13
	d.praise(d); // line14
	
	a.voice(a); // line15
	a.voice(d); // line16
	d.voice(a); // line17
	d.voice(d); // line18
	
}
  • Analysis
    • Two classes : Dog implements Animal.
      • Animal : 4 default methods
        • void greet(Animal a);
        • void sniff(Animal a);
        • void praise(Animal a);
        • void voice(Animal a);
      • Dog : 2 overriding Method, 2 overloading Method and 2 Methods inheriting from Animal(implicit)
        • void sniff(Animal a); → \rightarrow overiding
        • void bark(Animal a); → \rightarrow overiding
        • void praise(Dog a); → \rightarrow overloading
        • void bark(Dog a); → \rightarrow overloading
        • void greet(Animal a); → \rightarrow inheriting from Animal (implicit)
        • void praise(Animal a); → \rightarrow inheriting from Animal (implicit)
    • Line 1 → \rightarrow a : static type is Animal , while dynamic type is Dog;
    • Line 2 → \rightarrow d : static type and dynamic type are both Dog;
    • Line 3-6 → \rightarrow greet : there are NO overrides and overloads for this method.
      • greet method is quite simple. There is only one method named greet in the A n i m a l Animal Animal CLASS,and D o g Dog Dog inherits this method without any changes.
      • As long as the compile-time type of the reference variable and parameter are A n i m a l Animal Animal or has a “is-a” relatioship with A n i m a l Animal Animal, Java will compile successfully and get the same results。
      • So the output of these 4 lines(Line 3-6) are all “hello animal”
    • Line 7-10 → \rightarrow sniff: there is only an overide for this method
      1. Line 7-8 → \rightarrow the output of a.sniff(a) and a.sniff(d) are both “dog sniff animal”
        • Why is the same?
          • The only differece between the two is the passed-in parameter. One is a a a, and the other is d d d.
          • There is no method with the signature void sniff(Dog a) in the A n i m a l Animal Animal and D o g Dog Dog CLASS.
          • There is a “is-a” relationship between the compile-time types of a a a and d d d, so void sniff(Animal a) is selected.
        • Compile-time resolution
          (1)The compiler looks at the type of the reference variable a a a and the available s n i f f sniff sniff method void sniff(Animal a).
          (2)The reference variable a a a is of type A n i m a l Animal Animal ,so compiler will check in the A n i m a l Animal Animal CLASS.
        • Method Overriding
          • A n i m a l Animal Animal CLASS has a method void sniff(Animal a)
          • D o g Dog Dog CLASS overrides the method void sniff(Animal a)
        • Runtime Polymorphism (Dynamic Type Selection)
          • The method to be called is determined at runtime based on the actual (runtime) type of the object referred to a a a.
          • The runtime type (Dynamic type) of a a a is Dog.
      2. Line 9-10 → \rightarrow the output of d.sniff(a) and d.sniff(d) are both “dog sniff animal”
        • The dynamic type and compile-time type of d d d are both D o g Dog Dog.
        • There exists a s n i f f sniff sniff method with the signature void sniff(Animal a) in the D o g Dog Dog CLASS.
        • So Dog.sniff(Animal a) is selected .
        • Finding methods/variables in this class first , then the super class
    • Line 11-14 → \rightarrow praise: there is only an overload for this method
      1. Line 11 → \rightarrow the output of a.praise(a) is “u r cool animal”.

        • Compile-time resolution
          (1)The compile-time type of the reference variable a a a and the parameter a a a are both A n i m a l Animal Animal.
          (2)The compiler will only check the p r a i s e praise praise method in the A n i m a l Animal Animal CLASS, because in this case A n i m a l Animal Animal does not have the super class besides the O b j e c t Object Object CLASS in the java environment.
          (3)There exists only one praise method with the signature void praise(Animal a) in the A n i m a l Animal Animal CLASS, so it compiles successfully.
        • Method Selection
          (1) a a a is type of A n i m a l Animal Animal , but it refers to an instance of D o g Dog Dog.
          (2)There is no overrides for the p r a i s e praise praise method, so we only consider the compile-time type of the invoking object a a a. That is , the compiler looks for the p r a i s e praise praise Method only in the A n i m a l Animal Animal.
          (3)Then void praise(Animal a) is selected.
      2. Line 12 → \rightarrow the output of a.praise(d) is “u r cool animal”.

        • Compile-time resolution
          (1)The compile-time type of the reference variable a a a is A n i m a l Animal Animal, while the compile-time type of the parameter d d d is D o g Dog Dog.
          (2)It is very similar with a . p r a i s e ( a ) a.praise(a) a.praise(a). The only difference is the type of the passed-in parameter. And we notice that there exists a “is-a” relationship between parameter a a a and d d d (i.e. d d d is-a a a a) .Although there is no other praise method with void priase(Dog a) in the A n i m a l Animal Animal CLASS, it can call void priase(Animal a) instead. So it compiles successfully.
        • Method Selection
          (1)It keeps the same with a . p r a i s e ( a ) a.praise(a) a.praise(a), then void praise(Animal a) is selected.
      3. Line 13 → \rightarrow the output of d.praise(a) is “u r cool animal”.

        • Compile-time resolution
          (1)The compile-time type of the reference variable d d d is D o g Dog Dog, while the compile-time type of the parameter a a a is A n i m a l Animal Animal.
          (2)The compiler selects the method based on the compile-time type of the argument a a a in the D o g Dog Dog CLASS. it will first check for the method in the D o g Dog Dog CLASS that matches signature void praise(Animal a).
          (3)Now we notice that the void praise(Dog a) in the D o g Dog Dog CLASS does NOT match, so we need to check in its super class A n i m a l Animal Animal. Then we find the method void praise(Animal a) in the A n i m a l Animal Animal CLASS. D o g Dog Dog CLASS can inherit the method void praise(Animal a) from the A n i m a l Animal Animal CLASS, so it compiles successfully.
        • The compiler only considers methods defined in the class that is the compile-time type of the invoking object belongs to and its super class(if any). (In this case , invoking object is d d d)
        • Method Overloading
          (1)Actually there are two method named p r a i s e praise praise (including the praise inheriting from the Animal CLASS) in the D o g Dog Dog CLASS, but we notice that the signatures of the two are different due to the different pass-in parameters of them. So there is an overload.
          (2)For the selection between the two praise methods , it depends on the compile-time type of the parameter a a a, which is A n i m a l Animal Animal . So void praise(Animal a) in the Animal CLASS is selected.
      4. Line 14 → \rightarrow the output of d.praise(d) is “u r cool dog”.

        • Compile-time resolution
          (1)The compile-time type of the reference variable d d d and parameter d d d are both D o g Dog Dog.
          (2)The compiler will first check for a method in the D o g Dog Dog CLASS that matches the signature void praise(Dog d). If yes, it compiles successfully. If not , it will check its super class then.
        • Method Overloading
          (1)Method p r a i s e praise praise is overloaded in the D o g Dog Dog CLASS. (for the same reason)
          (2)Since the parameter type exactly matches void praise(Dog d), the method is selected.
        • Method Overloading resolution is based on the compile-time types of the arguments provided.
    • Line 15-18 → \rightarrow voice: there are both an overide and an overload for this method
      1. Line 15 → \rightarrow the output of a.voice(a) is “dogs’ voice”
        • Compile-time resolution
          (1)The compiler looks at the compile-time type of the reference variable a a a, which is A n i m a l Animal Animal.
          (2)The compiler looks for available v o i c e voice voice methods in the A n i m a l Animal Animal CLASS.
          (3)The A n i m a l Animal Animal CLASS has a method void voice(Animal a)
        • Overriding Check
          (1) A n i m a l Animal Animal has the void voice(Animal a)
          (2) D o g Dog Dog overrides the void voice(Animal a)
          (3)The dynamic type of a a a is D o g Dog Dog. According to the Dynamic Type Selection , JVM will call the void voice(Animal a) in the D o g Dog Dog CLASS at the runtime (i.e. Dog.voice(Animal a))
      2. Line 16 → \rightarrow the output of a.voice(d) is “dogs’ voice”
        • Compile-time resolution is the same as the check of a.voice(a) . Owing to the passed-in parameter 's type is D o g Dog Dog , it need another Overloading Check.
        • Overloading Check
          (1)The compiler checks if there are any overloaded v o i c e voice voice methods that matches the argument type D o g Dog Dog.
          (2)In this case , the A n i m a l Animal Animal CLASS has no such method , so the search continues in the D o g Dog Dog CLASS because a a a refers to a D o g Dog Dog Object.
          (3)The D o g Dog Dog CLASS has an overloaded method void voice(Dog a), but since the reference compile-time type of a a a is Animal, this overloaded methos is NOT considered during the compile time.
        • Overriding Check is the same as the check of a.voice(a) . Finally void voice(Animal a) in the Dog CLASS (i.e. Dog.voice(Animal a) is selected.
        • In this case , overriding takes precedence because the method resolution process starts with the compile-time type but ends with the dynamic type, leading to the overridden method in the D o g Dog Dog CLASS being called.
        • The overloaded method in the D o g Dog Dog CLASS is not considered because the reference compile-time type A n i m a l Animal Animal can not “see” the void voice(Dog a) method.
      3. Line 17 → \rightarrow the output of d.voice(a) is “dogs’ voice”
        • The two type of d d d are both D o g Dog Dog, so check in the D o g Dog Dog CLASS. Then find the method with the signature void voice(Animal a) matched the d.voice(a) perfectly. i.e. Dog.voice(Animal a) is selected.
        • When an object is passed to a method as an argument, the dynamic type of this object does not affact method resolution at compile time. Howewer, it can affect the behavior of the method if the method uses dynamic type internally (e.g. calling other overidden methods on the argument).
      4. Line 18 → \rightarrow the output of d.voice(d) is “bark! bark!”
        • The two type of d d d are both D o g Dog Dog, so check in the D o g Dog Dog CLASS. Then find the method with the signature void voice(Dog a) matched the d.voice(d) perfectly. i.e. Dog.voice(Dog a) is selected.
        • Althoght the Dog.voice(Animal a) is right , the compiler selects the method with the most specific parameter type that can accept d d d. Apparently Dog.voice(Dog a) is better.

Method Overloading vs. Method Overriding

  1. Method Overloading
    • Overloading occurs when two or more methods in that same class (notice that some may herit from the super class) but different parameters (type, number etc.)
    • The method to be called is determined at the compile-time based on the method signature and the compile-time type of the arguments.
  2. Method Overriding
    • Overriding occurs when a subclass provides a specific implementation for a methos that us already defined in its superclass.
    • The method to be called is determined at runtime based on the actual object type(Dynamic type)
  3. Dynamic Method Selection as a Two Step Process
    • At compile time : We determine the signature S of the method to be called
      • signature S is decided using ONLY static types
    • At runtime : The dynamic type of the invoking object uses its method with the exact signature S
      • By invoking object , we mean the object whose method is invoked

Interface vs. Implementation Inheritance

  • Interface Inheritance ( a.k.a. what) :
    • Allows to generalize code in a powerful, simple way
  • Implementation Inheritance (a.k.a. how):
    • Allows code-reuse : Subclasses can rely on superclasses or interfaces
      • Print() implemented in List61B.java
      • Gives another dimension of control to subclass designers : can decide whether or not to override default implementations.

Inheritance2

Implementation Inheritance : Extends

Extends

  • When a class is a hyponym of an interface ,we used implements
  • If one class is a hyponym of another class, we can use extends
    • if class A extends class B , we will know that A inherits all members of B
      • All instance and static variable
      • All methods
      • All nested classes
      • private members are inaccessible
      • Constructors are not inherited
    • All constructors must start with a call to one of the super class’s constructor
      • Idea: If every VengefulSLList is-an SLList ,every VengefulSLList must be set up like an SSList
      • We can explicitly call the constructor with the keyword super (no dot)
      • If we do not expicitly call the constructor , java will automatically call the default(no-argument) constructor in the parent.
      • If we want to use a super constructor other than the no-argument constructor, we can give the parameters to super.
public VengefulSLList(){
	deletedItems = new SSList<Item>();
}

// is equivalent to 
public VengefulSLList(){
	super();
	deletedItems = new SSList<Item>();
}

// constructor with parameters
public VengefulSSList(Item x){
	super(x); // calls SLList(Item x)
	deletedItems = new SSList<Item>();
}

// is not equivalent to 
public VengefulSSList(Item x){
	// the implicit call is super();
	deletedItems = new SSList<Item>();
}

The Object class

  • As it happens , every type in Java is a descendant of the Object class ,which means VengefulSLList extends SLList and SLList extends Object implicitly.

Is - a vs. has - a

  • extends should only be used for is-a (hypernymic) relationships
  • has-a relationship a.k.a. meronymic

Abstract Class

Abstract classes live in the place between interface and concrete classes : we can implement whichever methods you want and leave the rest as abstract methods ( same behavior as interface methods).
If a class does not contain enough infomation to depict a concrete object , such class is called Abstract Class.
Interfaces cannot be instantiated, but they can be implemented. A class that implements an interface must implement all the methods described within the interface, otherwise it must be declared as an abstract class.

  • Variables behave just like a concrete class
  • Normal methods can be created like any other concrete class
  • Abstract methods behave just like methods in interfaces
  • Classes can only inherit from one abstract class
  • Abstract class can not be instantiated by itself, and it needs to be subclassed by another class to use its properties. (using extends)
  • Constructors are allowed in the abstract class.
  • We can have an abstract class without any abstract method.
  • There can be a final method in the abstract class, while any abstract method in the abstract class can not be declared as final (// error : public final abstract void method4()😉
  • We can define static methods in an abstract class
  • Abstract class can contain another abstract class as its nested class.
public abstract class base{
	// constructor
	
	public base(){
		System.out.println("base constructor called");
	}
	
	// abstract method
	public abstract void method1();
	
	// static method
	public static void method2(){
		System.out.println("base method2 called");
	}
	
	// final method
	public final void method3(){
		System.out.println("base method3 with final keyword called");
	}
}


public class derived extends base{
	
	// derived constructor
	public derived(){
		System.out.println("derived constructor called");
	
	}
	
	public void method1(){
		System.out.println("derived method1() called");
	}
	
	
	public static void main(String[] args){
		
		derived d = new derived();
		
		d.method1();
		d.method2();
		d.method3();
	}
	
}

the results are :
base constructor called
derived constructor called
derived method1() called
base method2 called
base method3 with final keyword called

final keyword

  • f i n a l V a r i a b l e → T o C r e a t e C o n s t a n t V a r i a b l e final \quad Variable \rightarrow To \quad Create \quad Constant \quad Variable finalVariableToCreateConstantVariable
    • When a variable is declared as final, its value cannot be changed once it has been initialized.
    • Useful for declaring constants or other values that should not be modifed
  • f i n a l M e t h o d s → T o P r e v e n t M e t h o d O v e r r i d i n g final \quad Methods \rightarrow To \quad Prevent \quad Method \quad Overriding finalMethodsToPreventMethodOverriding
    • When a method is declared as final, it can not be overridden by a subclass
    • Useful for methods that are part of a class’s public API and should not be modified by subclasses.
  • f i n a l C l a s s → T o P r e v e n t I n h e r i t a n c e final \quad Class\rightarrow To \quad Prevent\quad Inheritance finalClassToPreventInheritance
    • When a class is declared as final , it cannot be extended by a subclass.
  • If the final variable is a reference, this means that the variable cannot be re-bound to reference anothor object , but the internal state of the object pointed by that reference variable can be changed.
    • If we declare a final array, we can add or remove elements from it.

Encapsulation

Module : A set of methods that work together as a whole to perform some task or set of related tasks.
A module is said to be encapsulated if its implementation is completely hidden, and it can be accessed only through a documented interface.

  • Instance variables private
    • Implementation inheritance (e.g. extends) breaks encapsulation
      • If we override A method calling the inherited B method , and at the same time the B method calls the A method in the superclass , it will get caught in an infinite loop.
// break example
public class Dog{
	// constuctor
	private int size ;
	
	public Dog(String n, int s){
		name = n;
		size = s;
	}
	
	public void bark(){
		barkMany(1);
	}
	public void barkMany(int N){
		for(int i = 0 ; i < N ; i += 1){
			System.out.println("bark");
		}
	}
}

public class verboseDog extends Dog{
	private int size ;
	
	public verboseDog (String n, int s){
		name = n;
		size = s;
	}
	@Override
	public void barkMany(int N){
		for(int i = 0 ; i < N ; i += 1){
			bark(); // calls inherited bark method
		}
	}
	
	public static void main(String[] args){
		vd = new VerboseDog("test",2);
		vd.barkMany(3); // infinite loop
	}
}

Type checking and Casting

Compile-time type checking

  • Reminder : Dynamic Method Selection

    • If overridden , deciding which method to call based on run-time(dynamic type) of the variable.
  • Compile-Time type checking

    • Compiler allows method calls based on compile-time(static type) type of variable.
      • If the variable’s static type does not have A method , while dynamic type does have , when we call variable.A(), it will still get the compilation error.
    • Static type only determine the Signiture and whether there exists compilation error.
  • Expressions have compile-time type : An expression using the new keyword has the specified compile-type

    SLList<Integer> s1 = new VengefulSLList<Integer>(); //  ASSIGNMENT 1
    VengefulSLList<Int> vs1 = new SLList<Integer>(); //  ASSIGNMENT 2
    
  • Assignment 1

    • the compile-time type of variable s1 is SLList (according to the left hand side)
    • the compile-time type of the right hand side (RHS) (the expression begins with new) is VengefulSLList
    • A VengefulSLList is-a SLList , so the assignment is allowed.
  • Assignment 2

    • the compile-time type of variable vs1 is VengefulSLList (according to the left hand side)
    • the compile-time type of the right hand side (RHS) (the expression begins with new) is SLList
    • A SLList is not necessarily VengefulSLList , so the **assignment is not allowed and results compilation error **.
  • Conclusion

    • If we want to assign ClassA<type> v1 = new ClassB<type>() successfully , either ClassA and ClassB are the same class or ClassB is-a ClassA.
  • Expressions have compile-time type : Method calls have compile-time type equal to their declared type

    // a static method 
    public static Dog maxDog(Dog d1, Dog d2){ ... } // any call to maxDog will have compile-time type Dog.
    // Poodle is a subclass of Dog, then we got an example 
    Poodle frank = new Poodle("Frank", 5);
    Poodle frankjr = new Poodle("Frank Jr.", 15);
    Dog largerDog = maxDog(frank, frankjr);
    Poodle largerPoodle = maxDog(frank, frankjr); // COMPILATION ERROR , RHS HAS COMPILE-TIME Dog
    

Casting

  • Casting tells java to treat an expression as having a different compile-time type.
  • Casting does NOT change anything
// example 
Object o1 = (Dog) new ShowDog("M","T",2,5); // line0
Object o2 = new ShowDog("M","T",2,5); //line1
ShowDog sdx = ((ShowDog) o2); //line2
sdx.bark(); //line3
Dog dx = ((Dog) o2); //line4
dx.bark(); //line5
((Dog) o2).bark(); //line6
Object o3 = (Dog) o2; //line7
o3.bark(); //line8
variablestatic typedynamic type
o1ObjectShowDog
o2ObjectShowDog
sdxShowDogShowDog
dxDogShowDog
((Dog) o2)DogShowDog
o3ObjectShowDog
  • Background
    • All classes inherit from Object
    • Object does not have bark() method
    • ShowDog is a Dog and they both have bark() method while behave differently , which means ShowDog extends Dog and has an overridden method called bark()
    • ShowDog.bark() returns “Show!”
    • Dog.bark() returns “bark!”
  • Conculsion
    • If we use the keyword new to create a new instance , casting will not change anything ( eg: line0 ) .
    • If we create an object whose dynamic type and static type are different and the code runs successfully, these two type must have the “is-a” relationship , that is (dynamic type) is-a (static type) (eg : line1)
      • For the code to run and compile successfully , the dynamic type must be a subclass of the static type or must implement the interface that the static type represents.
    • When we use CASTING in an assignment , the assigned object will get the orginal dynamic type of the variable and the static type of the assigned object will be determined by the LEFT HAND SIDE if there exists. (eg : line2 , line4, line7)
    • If static type does NOT have the method A() while dynamic type does , when we call a.A(), it will get compilation error. (eg: line8 compilation error)
    • Static type determines the Signiture while Dynamic type finally determines which method will be called.
  • line3, line5 and line6 return “Show!” ;

Higher Order Function in Java

Higher Order Function : A function that treats another function as data.

# python
def tenX(x):
	return 10 * x
def do_twice(f, x):
	return f(f(x))

print (do_twice(tenX, 2))
// higher order function using interface in java

public interface IntUnaryFunction{
	int apply(int x);
}

public class TenX implements IntUnaryFunction{
	public int apply(int x){
		return 10 * x;
	}
}

public class HoFDemo{
	public static int do_twice(IntUnaryFunction f , int x){
		return f.apply(f.apply(x));
	}
	public static void main(String[] args){
		System.out.println(do_twice(new TenX(), 2));
	}
}

Implementation Inheritance Cheatsheet

  • Extends
    • VengefulSLList extends SLList means a VengefulSLList is-a SLList and inherits all members:
      • Variables , methods , nested classes ( no private)
      • Not constructors
      • Subclass constructor must invoke superclass constructor first
      • Use super to invoke overridden superclass methods and constructors
    • Invocation of overridden methods follows two simple rules:
      • Compiler plays it safe and only lets us do things allowed by static type
      • For overridden methods the actual method invoked is based on dynamic type of invoking expression
      • Can use casting to overrules compiler type checking

Inheritance3

Subtype Polymorphism

  • Polymorphism : providing a single interface to entities of different types ( that is , making multiple things inherit from one generic interface)
  • Subtype Polymorphism vs. Explicit Higher Order Function
# python 
# Explicit HoF Approach : pass the outside function
def print_larger_hof(x, y, compare, stringify):
	if compare(x, y):
		return stringify(x)
	return stringify(y)
# Subtype Polymorphism Approach 
def print_larger_sp(x, y):
	if x.largerThan(y):
		return x.str()
	return y.str()

Inheritance4

Explicit Exceptions

Using throw keyword. ( throw … catch)

if (x == null){
	throw new IllegalArgumentException("cannot be null");
}

Iterator

  • Iterator Interface

    • The Iterator interface is part of the java.util package. Before we use it , we must import java.util.Iterator; at the top of the java file.
    • And the Iterator provides three main methods:
      • boolean hasNext() : returns true if the iteration has more elements.
      • T next() : returns the next element in the iteration.
      • void remove() : removes the last element returned by this iterator (optional operation)
  • Example:

    Set<Integer> javaset = new HashSet<Interger>();
    
    // first method : simple way
    for (int x : javaset){
    	System.out.println(x);
    }
    
    // second method
    // print all the items in the target iterator
    Iterator<Integer> seer = javaset.iterator();
    while(see.hasNext()){
    	System.out.println(seer.next());
    }
    
  • And the above code , compiler will check the following two parts:

    • Does the Set interface have an iterator() method
    • Does the iterator interface have next()/ hasNext() method
  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值