Understand Java generics and Unlimited variable length arguments. Both these facilities are used in the Android AsyncTask class.

Java generics

Search for: Java generics


ArrayList<String> als = new ArrayList<String>
List<String> ls = new ArrayList<String>
ls = als; //right
als = ls; //wrong

List<String> != List<Object>

void printCollection(Collection<?> c) 
{
   for (Object e : c) 
   {
      System.out.println(e);
   }
}

A 2004 PDF by Gilad Bracha

What is "?": an unknown type


public void drawAll(List<? extends Shape> shapes) { ... }

static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
for (T o : a) {
c.add(o); // correct
}}

java generics inheritance

Search for: java generics inheritance

This means a static variable must be mentioned based on the raw type. for example


SomeGenericType.Constant //good
and not
SomeGenericType<T>.Constant //error

http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html


public class MyGenericClass<T> 
{
static T somevariable; //wrong
static String variable2; //ok
...
}

If, for instance, you have a non-generic legacy method that takes a List as an argument, you can pass a parameterized type such as List to that method. Conversely, if you have a method that returns a List , you can assign the result to a reference variable of type List , provided you know for some reason that the returned list really is a list of strings.


public class GenericPair<X,Y> {
	public X varX;
	public Y varY;
	public GenericPair(X inVarX, Y inVarY)
	{
		varX = inVarX;
		varY = inVarY;
	}
	public X getFirst()
	{
		return varX;
	}
	public Y getSecond()
	{
		return varY;
	}
}

public void testGenerics()
{
    GenericPair<String, Integer> myPair = 
        new GenericPair<String, Integer>("satya",55);

    Log.d(tag, myPair.getFirst());
    this.mReportTo.reportBack(tag, myPair.getFirst());
    
    Log.d(tag, myPair.getSecond().toString());
    this.mReportTo.reportBack(tag, myPair.getSecond().toString());
}

public class DerivedPair 
extends GenericPair<String, Integer>
{
    DerivedPair(String a, Integer i)
    {
        super(a,i);
    }
}

public void testDerivedGenerics()
{

    DerivedPair myPair = 
        new DerivedPair("satya",55);

    Log.d(tag, myPair.getFirst());
    this.mReportTo.reportBack(tag, myPair.getFirst());
    
    Log.d(tag, myPair.getSecond().toString());
    this.mReportTo.reportBack(tag, myPair.getSecond().toString());
    
}

public void testParams(String s1, String... strings)
{
    this.mReportTo.reportBack(tag, "Parent:" + s1);
    for(String s : strings)
    {
        this.mReportTo.reportBack(tag, "Child:" + s);
    }
}

When there are variable number of arguments, that argument needs to be the last or the only argument to the function. The argument then is passed to the function as an array that is indexable.


testParams("Parent", "Child1");
// or
testParams("Parent", "Child1", "Child2");
//or
testParams("Parent", "Child1", "Child2", "Child3");

void printCollection(Collection<Object> c) 
{
  for (Object e : c) 
  {
   System.out.println(e);
  }
}

void printCollection(Collection<?> c) 
{
  for (Object e : c) 
  {
   System.out.println(e);
  }
}

The first one will be useless as you cannot pass a collection of strings. you can only strictly pass a collection of objects.

From a generic "confusion" the second one says let me pass a collection of any type of object.

By extension


void draw(Collection<Shape> shapes) 
{
}

will not be of much value. Because I could not pass a Collection to the draw function. By very definition the type Collection is not the same as Collection. In most cases a signature like this is in most likely not what you want.

However the same meaning can be implied by the following


void draw(Collection<? extends Shape> shapes) 
{
}

So in short


Collection<?>

is equivalent to


Colelction<? extends Object)

SomeClass<String> gcString;
SomeClass<int> gcInt;

At run time both gcString and gcInt will point to the same type of class. So it doesn't make sense to type cast generic class variables at run time like this


SomeClass<String> gcString1 = (SomeClass<String>)gcString

public class GenericPair<X,Y> 
{
    public X varX;
    public Y varY;
    public GenericPair(X inVarX, Y inVarY)
    {
        varX = inVarX;
        varY = inVarY;
        
        //Let's do something with varX of type X
        
        //Lets look for a valid function on a string object
        String s="";
        s.concat("ddd");
        
        //See if such a method is allowed
        varX.concat("ddd"); //Compile error
    }
    public X getFirst()
    {
        return varX;
    }
    public Y getSecond()
    {
        return varY;
    }
}

public class MyBase
{
   public String s = "";
}
class MyDerived1 extends MyBase{}
class MyDerived2 extends MyBase{}

public class GenericStringBasedPair<X extends MyBase, Y extends MyBase> 
{
    public X varX;
    public Y varY;
    public GenericStringBasedPair(X inVarX, Y inVarY)
    {
        varX = inVarX;
        varY = inVarY;

        varX.s.concat("abc");
        varY.s.concat("xyz");

    }
    public X getFirst()
    {
        return varX;
    }
    public Y getSecond()
    {
        return varY;
    }
}

What does the following mean


void somemethod(SomeType<T super String> st)

This method will take any "SomeType" whose generic type is not a derived class of "String" but a String itsels or its base class.

Functions and classes generally take fixed types as input and return fixed types.

Java generics extend this idea where functions and classes can be written they are "applicable" to more than one type, and the type is explicitly codified in the source code for documentation and compile time checking.

When the type is not explicitly stated in a generic type there are only a few things you can do with that typed object other than basic operations and the methods available on the base object class

One can give hints to the compiler that a generic type can be a sub type or a super type so that operations on those types can be allowed

A generic type instantiated or realized with two distinct parameterized types whether those types are extended from each other or otherwise are not related. So a collection of circles is not the same as a collection of shapes even though a circle is a shape.

Funtions or classes that take generic types as arguments could consider compile hints through wild cards

The available wild cards are: ?, ? extends someBaseclass, ? super someDerivedClass

There is only one instance of the generic class

The static variables in a generic class is referred with out the generic type argument

It is wrong to ask the instance type of a generic class object at run time

Both classes and functions can be genericized

netmite ArrayAdapter source code

Search for: netmite ArrayAdapter source code

Study this class how a parameterized class is developed


//You cannot override when raw types are the same
public class Example {
    public void print(Set<String> strSet) { }
    public void print(Set<Integer> intSet) { }
}

? is called a wild card


//This is called a bounded wild card
<? extends SomeBaseClass>

/*
    * Test the state change methods on collections
    */
   void addAllSimples(List<? extends Simple> simpleDerivedList)
   {
      Simple s = new Simple();
      Derived d = new Derived();
      Object so = s;
      
      //Following fails: compile error
      //simpleDerivedList.add(s);
      //simpleDerivedList.add(so);
      
      //So all adds are prevented 
   }

public void addRectangle(List<? extends Shape> shapes) {
    shapes.add(0, new Rectangle()); // compile-time error!
}

Bounded wild cards allow you to pass a list of any type as long as it extends the base class

So it can be a list of shapes

it can be a list of triangles

it can be a list of rectangles

It makes perfect sense to read the shapes as they are all shapes

But adding a basic shape to a list of rectangles will be wrong and violates the contract that all are rectangles.

Similarly adding a triangle to a list of rectangles is clearly wrong.

So as you service many types of lists, you cannot be sure what list it is.

Even adding an object is caught at compile time.


<T> void addAllSimplesFixed(
    List<T> genericizedList, List<T> fromList)
{}

void <T> addAllSimplesFixed(
    List<T> genericizedList, List<T> fromList)
{}

<T> void addAllSimplesFixed(List<T> toList, T object)
   {
      //You cannot do this because you don't know what type the list is
      //Simple s = new Simple();
      //Derived d = new Derived();
      //Object so = s;
      //genericizedList.add(s);
      toList.add(object);
   }

private void test9()
   {
      //See c.addAllSimples() mehod to see what it does
      GenericMethodTestClass1 c = new GenericMethodTestClass1();
      c.addAllSimplesWrong(new ArrayList<Simple>());
      
      Simple s = new Simple();
      Derived d = new Derived();
      GenericPair<Integer,Integer> intPair = new GenericPair<>(1,2);
      
      List<Simple> simples = new ArrayList<>();
      c.addAllSimplesFixed(simples, s);
      c.addAllSimplesFixed(simples, d);
      
      //Compiler error
      //Method type is inferred
      //c.addAllSimplesFixed(simples, intPair);
      
      List<Derived> deriveds = new ArrayList<>();
      //fails
      //c.addAllSimplesFixed(deriveds, s);
      c.addAllSimplesFixed(deriveds, d);
      
      System.out.println("Test9:" + simples);
   }

Notice that we don?t have to pass an actual type argument to a generic method. 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.

So, Reads can be accommodated with wild cards. We need generic typed methods to allow adds.


//functions that take specific objects
//These functions serve only ONE type of client
f1(String...)
f1(List<Object> ...)

//functions that work for multiple inputs
//These serve number of typed clients
//But they can't add
f1(List<?>...)
f1(List<? extends baseclass ....)


//(generic) functions with types specified
//allows adds
<T> f1(List<T>....)

//For the following
List<String>

//List is a rawtype

//consider 
void m1(List stringList){}

//you can call it with
List<String> stringList = new ArrayList<>();
m1(stringList)

//Exactly a list of objects
List<Object>

//List of any set of objects
//List of strings, List of fruits
List<?>
List

//So
List (kind of) == List<?>

List <String> l1 = new ArrayList<String>();
List<Integer> l2 = new ArrayList<Integer>();
System.out.println(l1.getClass() == l2.getClass());

//Start with a plain collection
Collection cs = new ArrayList<String>();

// illegal
if (cs instanceof Collection<String>) { ...} 

//Unchecked warning
Collection<String> cstr = (Collection<String>) cs;

Collection<EmpInfo> emps =
sqlUtility.select(EmpInfo.class, ?select * from emps?);
...
public static <T> Collection<T> select(Class<T>c, String sqlStatement) {

  Collection<T> result = new ArrayList<T>();

  /* run sql query using jdbc */
  for ( /* iterate over jdbc results */ ) {
    T item = c.newInstance();

    /* use reflection and set all of item?s fields from sql results */
    result.add(item);
  }

  return result;
}

//Example of a class literal
Class<T> c;

Those that look like <? extends Baseclass>

Bounded wildcards were useful when reading from a data structure.


function(<Object>)
function(<? extends String)
function(<T>)
function(<? extends T)
function(<? super T)

//Following sets a lower bound
//Don't send me any classes below String
//Anything derived from String is fine
function(<? extends String>)

//This sets an upper bound
//Only send me classes that are parents of SpecialString
//all the way to Object
function(<? super SpecialString>)

I am guaranteed everything passed to me are my parents.

Because I am the grandest, I can behave like any of my parents in the hierarchy

So if I have a list of my parents, irrespective of their type, I can be added to that list.

So this is the opposite of "read" (in the lower bound case)

I can also add any of my derived classes to the parent lists as well.

Read them reverse, just the names, the rest works.


Sink<Object> s;
Collection<String> cs;

//signature of a function
public static <T> 
T writeAll(Collection<T> coll, Sink<? super T> snk){...}

//Call...
String str = writeAll(cs, s); // Yes!

//T gets resolved to "String"
//Type inference of generic methods

//How to read:
1. Take a string collection
2. Take a sink that can absorb Strings
3. Sink of Objects can absorb Strings

In general, if you have an API that only uses a type parameter T as an argument, its uses should take advantage of lower bounded wildcards (? super T). Conversely, if the API only returns T, you?ll give your clients more flexibility by using upper bounded wildcards (? extends T)

What are covariant returns?

Search for: What are covariant returns?

Behavior of arrays

Ignore generics for the moment

You are writing a function

this is a function that is reusable

this is a function that works for any type

this is a function that works for any super type of this type

this is a function that works for any sub type of this type

The rest is unnecessary detail!