-
Notifications
You must be signed in to change notification settings - Fork 4
Covariance and Contravariance
An easy-to-remember (and extremely informal) definition of covariance and contravariance is (source):
- Covariance: accept subtypes
- Contravariance: accept supertypes
To achieve covariance for a list, a wildcard declared as ? extends T is used (or upper-bounded wildcard).
For example, List<? extends Number> represents a list of Number or its sub-types such as Integer and Double. Number is the 'upper-bound'.
//possible and valid list assignments from ? extends Number
List<? extends Number> f = new ArrayList<Number>(); // Number "extends" Number
List<? extends Number> f = new ArrayList<Integer>(); // Integer extends Number
List<? extends Number> f = new ArrayList<Double>(); //Double extends Number
In covariance, we can get but we cannot put.
//getting is valid because we have an extent of guarantee that the value is Number or a subtype of Number
Number n = f.get(0); //Number is the upperbound so e.g. even if f is a list of Integers or Doubles, Number n = Integer/Double is valid
Integer i = f.get(0); //invalid because f could be a List of Doubles and e.g. Integer i = 2.56 is invalid as they are incompatible types
Double d = f.get(0) //invalid because f could be a List of Integer and e.g. Double d = 2 is invalid as they are incompatible types
//putting is invalid because we cannot guarantee what kind of list f is actually pointing to due to the possibilities with "? extends Number"
f.add(1.0) //invalid because f could be a list of Integers
f.add(1) //invalid because f could be a list of Doubles
By using extends, only T or subclasses of T (? extends T) can be read (e.g. using ? extends Number, using Number n = f.get(0), we can read Numbers, Integers, Doubles)
We use a a lower-bounded wildcard: ? super T For example, List<? extends Integer> represents a list of Integer or its super-types such as Number or Object. Integer is the 'lower-bound'. In contravariance, we cannot get but we can put.
List<? super Integer> f1 = new ArrayList<Integer>(); // Integer is a "superclass" of Integer
List<? super Integer> f1 = new ArrayList<Number>(); // Number is a superclass of Integer
List<? super Integer> f1 = new ArrayList<Object>(); // Object is a superclass of Integer
Integer i = f1.get(0); //invalid because f1 could be pointing to a list of Number, which can include Doubles
Number n = f1.get(0); //invalid because f1 could be pointing to a list of Objects, which can include Strings
Object o = f1.get(0); // this is valid but redundant because every class is a subclass of Object
//putting is invalid because we cannot guarantee what kind of list f is actually pointing to due to the possibilities with "? extends Number"
f.add(1) //valid because f could be a list of Integers, list of Numbers or Objects but they all are compatible with Integer
By using super, only T or subclasses of T can be added (e.g. for ? super Integer, we can only add Integer or subclasses of Integer)
Peer Learning
Guides
Setting Up Checkstyle
Setting Up Java
Setting Up MacVim
Setting Up Stu
Setting Up Unix For Mac
Setting Up Unix For Windows
Setting Up Vim
Setting up SSH Config
SSH Without Password
Copying Files From PE Nodes
Using tmux
CS2030 Contents
Lecture 1 SummaryLecture 2 Summary
Access Modifiers
Lecture 3 Summary (Polymorphism)
Compile Time Type VS Runtime Type
Abstraction, Encapsulation, Inheritance, and Polymorphism
SOLID Principles
Class VS Abstract Class VS Interface
Comparable VS Comparator
Generic Types T
HashMap
Raw Types with Generic
Lambda expression
PECS (Producer Extends Consumer Super)
Optional
Streams
Parallel Streams
Monad
Functors and Monads with Category Theory