Back to Basics – Subtler Nuances – Generics

public class Person {
	String person;

	public Person() {
	}

	public Person(String person) {
		this.person = person;
	}

	public String getName() {
		return this.person;
	}
}

public class Driver extends Person {
	String driver;

	public Driver(String driver) {
		this.driver = driver;
	}

	public String getDriver() {
		return this.driver;
	}

	public String getName() {
		return this.driver;
	}
}
import java.util.*;

public class Test {
	public void test() {
		List<String> list = new ArrayList<String>();
		list.add("Matty");
		for (String s : list) {
			System.out.println(s);
		}
	}

	public static void main(String[] args) {
		new Test().test();
	}
}
/*

The correct way to use a simple generic type

D:\work\projects\generics>java Test
Matty
*/

import java.util.*;

public class Test3 {
	public void test() {
		List<String> list = new ArrayList<String>();
		List<Object> object = list;
		object.add("jacob");
		list.add("Matty");
		for (String s : list) {
			System.out.println(s);
		}
	}

	public static void main(String[] args) {
		new Test3().test();
	}
}
/*

List<Object> is not a supertype of List<String> or List of any type for that matter!

Test3.java:7: incompatible types
found   : java.util.List<java.lang.String>
required: java.util.List<java.lang.Object>
List<Object> object = list;
*/
import java.util.*;

public class Test4 {
	public void test() {
		List<String> stringList = new ArrayList<String>();
		stringList.add("jacob");
		stringList.add("Matty");
		List<?> list = new ArrayList<String>();
		list = stringList;
		for (Object s : list) {
			System.out.println(s);
		}
	}

	public static void main(String[] args) {
		new Test4().test();
	}
}
/*

List<?> is a supertype of any List<genericType> It is used as a wildcard.
We can read elements from this list and assign them Object since whatever type of collection, it always contain objects
However it is not safe to add any element to this list including Object because
the added element would have to be a subtype of the actual type of this list
and since we dont know the actual type it is illegal to add any element to it! Except null.

D:\work\projects\generics>java Test4
jacob
Matty
*/
import java.util.*;

public class Test5 {
	public void test() {
		List<String> stringList = new ArrayList<String>();
		stringList.add("jacob");
		stringList.add("Matty");
		List<?> list = new ArrayList<String>();
		list.add((Object) ("Matty"));
		list = stringList;
		for (Object s : list) {
			System.out.println(s);
		}
	}

	public static void main(String[] args) {
		new Test5().test();
	}
}
/*

List<?> is a supertype of any List<genericType>
We can read elements from this list and assign them Object since whatever type of collection, it always contain objects
However it is not safe to add any element to this list including Object because
the added element would have to be a subtype of the actual type of this list
and since we dont know the actual type it is illegal to add any element to it! Except null

Test5.java:10: cannot find symbol
symbol  : method add(java.lang.Object)
location: interface java.util.List<capture#145 of ?>
list.add((Object)("Matty"));

*/

import java.util.*;

public class Test6 {
	public void test() {
		List<String> stringList = new ArrayList<String>();
		stringList.add("jacob");
		stringList.add("Matty");
		List<?> list = new ArrayList<String>();
		list.add(("Matty"));
		list = stringList;
		for (Object s : list) {
			System.out.println(s);
		}
	}

	public static void main(String[] args) {
		new Test6().test();
	}
}
/*

List<?> is a supertype of any List<genericType>
We can read elements from this list and assign them Object since whatever type of collection, it always contain objects
However it is not safe to add any element to this list including Object because
the added element would have to be a subtype of the actual type of this list
and since we dont know the actual type it is illegal to add any element to it! Except null

Test6.java:10: cannot find symbol
symbol  : method add(java.lang.String)
location: interface java.util.List<capture#145 of ?>
list.add(("Matty"));

*/
import java.util.*;

public class Test7 {
	public void test() {
		List<?> driverList = new ArrayList<Driver>();
		driverList.add(new Driver("jacob"));
		driverList.add(new Driver("Matty"));
		for (Driver s : driverList) {
			System.out.println(s);
		}
	}

	public static void main(String[] args) {
		new Test7().test();
	}
}
/*
List<?> is a supertype of any List<genericType>
We can read elements from this list and assign them Object since whatever type of collection, it always contain objects
However it is not safe to add any element to this list including Object because
the added element would have to be a subtype of the actual type of this list
and since we dont know the actual type it is illegal to add any element to it! Except null

D:\work\projects\generics>javac Test7.java
Test7.java:7: cannot find symbol
symbol  : method add(Driver)
location: interface java.util.List<capture#466 of ?>
driverList.add(new Driver("jacob"));
^
Test7.java:8: cannot find symbol
symbol  : method add(Driver)
location: interface java.util.List<capture#145 of ?>
driverList.add(new Driver("Matty"));
^
Test7.java:9: incompatible types
found   : java.lang.Object
required: Driver
for(Driver s:driverList)
^
3 errors
*/


import java.util.*;

public class Test8 {
	public void test() {
		List<Driver> driverList = new ArrayList<Driver>();
		driverList.add(new Driver("jacob"));
		driverList.add(new Driver("Matty"));
		List<?> genericList = driverList;
		for (Object s : genericList) {
			System.out.println(s);
		}
	}

	public static void main(String[] args) {
		new Test8().test();
	}
}
/*

List<?> is a supertype of any List<genericType>
We can read elements from this list and assign them Object since whatever type of collection, it always contain objects
However it is not safe to add any element to this list including Object because
the added element would have to be a subtype of the actual type of this list
and since we dont know the actual type it is illegal to add any element to it! Except null

D:\work\projects\generics>java Test8
Driver@addbf1
Driver@42e816
*/

import java.util.*;

public class Test9 {
	public void test() {
		List<Driver> driverList = new ArrayList<Driver>();
		driverList.add(new Driver("jacob"));
		driverList.add(new Driver("Matty"));
		List<?> genericList = driverList;
		for (Object s : genericList) {
			System.out.println(((Driver) s).getDriver());
		}
	}

	public static void main(String[] args) {
		new Test9().test();
	}
}
/*

List<?> is a supertype of any List<genericType>
We can read elements from this list and assign them Object since whatever type of collection, it always contain objects
However it is not safe to add any element to this list including Object because
the added element would have to be a subtype of the actual type of this list
and since we dont know the actual type it is illegal to add any element to it! Except null

D:\work\projects\generics>java Test9
jacob
Matty
*/
import java.util.*;

public class Test11 {
	public void test() {
		List<Driver> driverList = new ArrayList<Driver>();
		driverList.add(new Driver("jacob"));
		driverList.add(new Driver("Matty"));
		List<Driver> genericList = driverList;
		for (Driver s : genericList) {
			System.out.println(s.getDriver());
		}
	}

	public static void main(String[] args) {
		new Test11().test();
	}
}
/*
The correct way to assign a generic list to another when we dont use wildcards

D:\work\projects\generics>java Test11
jacob
Matty
*/

import java.util.*;

public class Test12 {
	public void test() {
		List<Driver> list1 = new ArrayList<Driver>();
		list1.add(new Driver("jacob"));
		list1.add(new Driver("Matty"));
		List<Person> list2 = new ArrayList<Person>();
		list2.add(new Person("Jimmy"));
		printName(list1);
		printName(list2);
	}

	public void printName(List<? extends Person> list) {
		for (Person s : list) {
			System.out.println(s.getName());
		}
	}

	public static void main(String[] args) {
		new Test12().test();
	}
}
/*

The list of generic type <? extends Person> can accept any object which is a subtype of Person
The disadvanatage is illegal to add objects to this generic list

D:\work\projects\generics>java Test12
jacob
Matty
Jimmy
*/
import java.util.*;

public class Test13 {
	public void test() {
		List<Driver> list1 = new ArrayList<Driver>();
		list1.add(new Driver("jacob"));
		list1.add(new Driver("Matty"));
		addName(list1);
	}

	public void addName(List<? extends Person> list) {
		list.add(new Driver("abc"));
		list.add(new Person("xyz"));
	}

	public static void main(String[] args) {
		new Test13().test();
	}
}
/*

The list of generic type <? extends Person>  can accept any object which is a subtype of Person
The disadvanatage is illegal to add objects to this generic list

D:\work\projects\generics>javac Test13.java
Test13.java:13: cannot find symbol
symbol  : method add(Driver)
location: interface java.util.List<capture#145 of ? extends Person>
list.add(new Driver("abc"));
^
Test13.java:14: cannot find symbol
symbol  : method add(Person)
location: interface java.util.List<capture#339 of ? extends Person>
list.add(new Person("xyz"));
*/
import java.util.*;

public class Test15 {
	public void test() {
		List<Driver> list = new ArrayList<Driver>();
		list.add(new Driver("jacob"));
		list.add(new Driver("Matty"));
		String[] arr = new String[1];
		arr[0] = "mj";
		addArrToList(arr, list);
	}

	public void addArrToList(String[] arr, List<? extends Person> list) {
		for (String name : arr) {
			list.add(name);
		}
	}

	public static void main(String[] args) {
		new Test15().test();
	}
}
/*
The list of generic type <? extends Person> can accept any object which is a subtype of Person
The disadvanatage is illegal to add objects to this generic list

D:\work\projects\generics>javac Test15.java
Test15.java:17: cannot find symbol
symbol  : method add(java.lang.String)
location: interface java.util.List<capture#145 of ? extends Person>
list.add(name);
^
1 error
*/

import java.util.*;

public class Test16 {
	public void test() {
		Collection<Person> list = new ArrayList<Person>();
		list.add(new Person("jacob"));
		list.add(new Person("Matty"));
		Driver[] arr = new Driver[1];
		arr[0] = new Driver("mj");
		addArrToList(arr, list);// T inferred to be Person
	}

	public <T> void addArrToList(T[] arr, Collection<T> list)// generic method
																// declaration
	{
		for (T t : arr) {
			list.add(t);
		}
		for (T x : list) {
			System.out.println(((Person) x).getName());
		}
	}

	public static void main(String[] args) {
		new Test16().test();
	}
}
/*

addArrToList is a generic method. Just like type declarations, method declarations can be generic.
The method overcomes the disadvantage that was encountered in the previous example.
i.e. it allows objects to be added to generic list.
The compiler infers the type argument for us, based on the types of the actual arguments. It
will generally infer the most specific type argument that will make the call type-correct.

Object[] oa = new Object[100];
Collection<Object> co = new ArrayList<Object>();
fromArrayToCollection(oa, co);// T inferred to be Object
String[] sa = new String[100];
Collection<String> cs = new ArrayList<String>();
fromArrayToCollection(sa, cs);// T inferred to be String
fromArrayToCollection(sa, co);// T inferred to be Object
Integer[] ia = new Integer[100];
Float[] fa = new Float[100];
Number[] na = new Number[100];
Collection<Number> cn = new ArrayList<Number>();
fromArrayToCollection(ia, cn);// T inferred to be Number
fromArrayToCollection(fa, cn);// T inferred to be Number
fromArrayToCollection(na, cn);// T inferred to be Number
fromArrayToCollection(na, co);// T inferred to be Object
fromArrayToCollection(na, cs);// compile-time error

D:\work\projects\generics>java Test16
jacob
Matty
mj
*/

Back to Basics – Subtler Nuances – Part Two

FinalReferenceInitializer.java

public class FinalReferenceInitializer {
	static String staticVar;

	public FinalReferenceInitializer() {
		initializeFinalVar();
		staticVar = "new Value for static var";
		System.out.println(staticVar);
	}

	public static void initializeFinalVar() {
		staticVar = new String("Static var Initializes");
		System.out.println(staticVar);
	}

	public static void main(String args[]) {
		FinalReferenceInitializer fri = new FinalReferenceInitializer();
		System.out.println(FinalReferenceInitializer.staticVar);
	}
}
/*
Only static variables and static methods can be called before a constructor completes.
D:\appletree>java FinalReferenceInitializer
Static var Initializes
new Value for static var
new Value for static var
*/

CallTest.java

class Factory {
	{
		System.out.println("A1");// 7 - instance init blocks run - right after
									// call to super()
	}
	static {// 1 static block executes - when Factory class is loaded - first
			// one to do so
		System.out.println("A9");// 1.a
	}

	public Factory() {// 6 default constructor called - which calls super()
		System.out.println("A2");// 8
	}
};

class CementFactory extends Factory {
	{
		System.out.println("A8");// 9 - instance init blocks run right after
									// call to super()
	}
	static {// 2 static block executes - when CementFactory class is loaded
			// -second to do so
		System.out.println("A3");// 2.a
	}

	public CementFactory() {// 5 default constructor called - which calls
							// super()
		System.out.println("A4");// 10
	}

	static {// 3 second static block executes in sequence- at class loading time
		System.out.println("A5");// 3.a
	}
};

class MyCementFactory extends CementFactory {
	public static void main(String args[]) {
		System.out.println("A6");// 4 first line in main executed after class is
									// loaded
		new MyCementFactory();// calls default constructor which in turn calls
								// super()
		System.out.println("A7");// 9
	}
};
/**
D:\appletree>java MyCementFactory
A9
A3
A5
A6
A1
A2
A8
A4
A7
**/

WidenTest.java

public class WidenTest {
	static void overload(int x) {
		System.out.println("Integer");
	}

	static void overload(float x) {
		System.out.println("float");
	}

	public static void main(String[] args) {
		byte b = 5;
		overload(b);
	}
}

/**
When an exact match is not found in an overloaded the smallest arg that is wider than the parameter is selected

D:\appletree>java WidenTest
Integer
*/

NarrowTest.java

public class NarrowTest {
	static void overload(byte x) {
		System.out.println("Integer");
	}

	static void overload(short x) {
		System.out.println("float");
	}

	public static void main(String[] args) {
		int b = 5;
		overload(b);
	}
}
/**

D:\appletree>javac NarrowTest.java
NarrowTest.java:12: cannot find symbol
symbol  : method overload(int)
location: class NarrowTest
overload(b);
^
1 error
*/

BoxTest.java

public class BoxTest {
	static void overload(Integer x) {
		System.out.println("Boxed");
	}

	static void overload(long x) {
		System.out.println("Widened");
	}

	public static void main(String[] args) {
		int b = 5;
		overload(b);
	}
}

/**
Widening beats auto boxing
reason -> widening existed prior to java 5 and hence backward compatibility is supported
D:\appletree>java BoxTest
Widened
*/

VarArgTest1.java

public class VarArgTest1 {
	static void overload(int x, int y) {
		System.out.println("Backward compatible");
	}

	static void overload(int... x) {
		System.out.println("Var arg");
	}

	public static void main(String[] args) {
		int b = 5;
		int c = 7;
		overload(b, c);
	}
}

/**
Method call is now backward compatible!
D:\appletree>java VarArgTest1
Backward compatible
*/

VarArgTest2.java

public class VarArgTest2 {
	static void overload(float x, float y) {
		System.out.println("Backward compatible");
	}

	static void overload(int... x) {
		System.out.println("Var arg");
	}

	public static void main(String[] args) {
		int b = 5;
		int c = 7;
		overload(b, c);
	}
}
/**
Method call is now backward compatible!
Widening beats var args
D:\appletree>java VarArgTest2
Backward compatible
*/

AutoBoxingVsVarArgs.java

public class AutoBoxingVsVarArgs {
	static void overload(Integer x, Integer y) {
		System.out.println("Boxed");
	}

	static void overload(int... x) {
		System.out.println("Var Arg");
	}

	public static void main(String[] args) {
		int b = 5;
		int c = 6;
		overload(b);
		overload(b, c);
	}
}

/**
var args are catch all arguments and have the lowest precedence

D:\appletree>java AutoBoxingVsVarArgs
Var Arg
Boxed
*/

WrapperWidening.java

class WrapperWidening {
	void widenWrapper(Integer y) {
		System.out.println("Accepted?");
	}

	public static void main(String[] args) {
		Short x = new Short(2 + "");
		widenWrapper(x);
	}
}
/**
D:\appletree>javac WrapperWidening.java
WrapperWidening.java:9: widenWrapper(java.lang.Integer) in WrapperWidening cannot be applied to (java.lang.Short)
widenWrapper(x);
^
1 error
*/

ArrayWidening.java

class ArrayWidening {
	void widenArray(int[] c) {
		System.out.println("Accepted?");
	}

	public static void main(String[] args) {
		byte[] b = new byte[2];
		widenArray(b);
	}
}
/**
D:\appletree>javac ArrayWidening.java
ArrayWidening.java:9: widenArray(int[]) in ArrayWidening cannot be applied to (byte[])
widenArray(b);
^
1 error
*/

BoxAndWiden.java

class BoxAndWiden {
	void boxAndWiden(Integer z) {
		System.out.println("Accepted?");
	}

	public static void main(String[] args) {
		short c = 4;
		boxAndWiden(c);
	}
}
/**
Fails because short would be boxed to Short but Short cannot be widened to Integer

D:\appletree>javac BoxAndWiden.java
BoxAndWiden.java:9: boxAndWiden(java.lang.Integer) in BoxAndWiden cannot be applied to (short)
boxAndWiden(c);
^
1 error
*/

WidenBox.java


class WidenBox {
	public static void main(String[] args) {
		int c = 1;
		boxInteger(c);
		widenBox(c);
		boxVarArg(c, c);
		widenVarArg(c, c);
	}

	static void boxInteger(Integer i) {// making this any other Wrapper type
										// won't work
		System.out.println(i.intValue());
	}

	static void widenBox(Object o) {
		Integer i = (Integer) o;
		System.out.println(i.intValue());
	}

	static void boxVarArg(Integer... i) {// making this any other Wrapper type
											// won't work
		System.out.println("int boxed to Integer and var-arged");
	}

	static void widenVarArg(long... i) {
		System.out.println("int widened to long and var-arged");
	}
}
/**
int c is boxed to Integer
int c is boxed to Integer, Integer widened to Object
int c is boxed and assigned to var arg
int c is widened and assigned to var arg

D:\appletree>java WidenBox
1
1
int boxed to Integer and var-arged
int widened to long and var-arged

*/