java generics in Android - java

I don't understand the following code:
public class EventAdapter extends ArrayAdapter<Event>
{
public EventAdapter(Context context, int textViewResourceId,
List<Event> objects)
{
super(context, textViewResourceId, objects);
this.resource = textViewResourceId;
}
}
I am confused about the <Event> part in both cases. I understand it has something to do with Generics, but I don't understand it. I read http://docs.oracle.com/javase/tutorial/java/generics/, but still don't understand.
I do understand that objects is an ArrayList of objects of the type Event.
The part I don't understand is extending an ArrayAdapter with the Type <Event>. What does this signify?

extends ArrayAdapter<Event>
The type restriction here will influence on the return types of methods in the class, and the argument types of methods.
Here is an example, if you have a class:
class SomeClass<T> {
protected T value;
public void setValue (T value) {
this.value = value;
}
public T getValue () {
return value;
}
}
And if you have another class:
class SubClass extends SomeClass {
#Override
public void setValue (Event value) { // Fail! It is not overriding the super class' method.
this.value = value; // Warning! Unchecked types (maybe inconsistent).
}
}
If you remove the #Override annotation, it will run. But the extends SomeClass is useless and might cause problem if you keep it there -- there will be two very similar methods: setValue(Event) and super.setValue(T). Now the question is will the subclass have access to the super.setValue(T) method? I will explain it in the end, see "A missing type parameter bounding example".
So, you need to specify the type in declaration:
class SubClass extends SomeClass<Event> {
#Override
public void setValue (Event value) { // Correct now!
this.value = value;
}
}
Also, if you declare an inconsistent type:
class SubClass extends SomeClass<String> {
#Override
public void setValue (Event value) { // Fail! Not overriding.
this.value = value; // Fail! Inconsistent types.
}
}
So the type restricts the behavior of class body.
A missing type parameter bounding example:
import java.lang.reflect.*;
class Super<T> {
public void method (T t) {
System.out.println("Hello");
}
public void method2 () {
}
}
public class Test extends Super {
/*public void method (Object t) {
System.out.println("world");
}*/
/*public <T> void method (T t) {
}*/
public static void main (String args[]) {
new Test().method("");
for (Method m : Test.class.getMethods()) {
System.out.println(m.toGenericString());
}
}
}
If I comment method() in the subclass, it is compiled with a warning: Test.java uses unchecked or unsafe opertations. In the running result, it turned the generic type T into Object: public void Test.method(java.lang.Object).
If I only uncomment the first method() in the subclass, it is compiled with no warnings. In the running result, the subclass owns one public void Test.method(java.lang.Object). But it doesn't allow #Override annotation.
If I only uncomment the second method() in the subclass (which also has a generic type bounding), the compile fails with an error: name clash. It also doesn't allow #Override annotation. If you do so, it throws a different error: method does not override.
method2() is inherited by the subclass unanimously. But you also can't write the following code:
in superclass: public void method2 (Object obj) and in subclass: public <T> void method2 (T obj). They are also ambiguous and is not allowed by the compiler.

Here's my simplistic way of looking at generics in this case. Given the definition:
public class EventAdapter extends ArrayAdapter<Event>
I read it as: "An EventAdapter IS-A ArrayAdapter OF Event objects."
And I take List<Event> objects to mean a List of Event objects.
Collections are containers for objects, while Generics define what they can contain.

This assigns a value for the generic parameter in ArrayAdapter in a way that takes away control from the user of the EventAdapter class.
Any method overriding here can then replace T with Event and Event can be used inplace of T without casts.
This is the general definition of generics.
That this is allowed in this case is defined in the spec. While the exact behaviour is not defined in that section I think it is in line with all other generic behaviour as far as I can see.
While I see the construct here the first time, after some thinking it really isn't anything unusual.

Related

Use generic Wildcard in interface level java

This is related to java generic wild card. I need to understand how this happens and need solution.
Ex : I have a interface names Processer.
public interface Processer<X> {
<P> void process(P parent, X result);
}
I want to make P as wildcard. but it is not allowed to use wildcard ( ? ) when defining.
When I implement this interface and let IDE to generate implemented methods it generate as follow.
public class FirstProcesser implements Processer<String> {
#Override
public <P> void process(P parent, String result) {
}
}
I want to modify this implementation as this.
public class FirstProcesser implements Processer<String> {
#Override
public void process(User parent, String result) {
}
}
But it gives compile errors that FirstProcesser should be abstract or implement all the abstract methods.
I need to know why this is happening and a solution.
Overriding
You can't override a method
(generic or not)
with one that takes a narrower parameter type.
If you could, it would be impossible for the compiler to tell whether any given method call would be
(future tense)
legal.
An example without any generics at all, which will fail with exactly the same error:
public class X {
public void f(Object o) {
}
}
class Y extends X {
#Override
public void f(String s) {
}
}
Compiling this fails with:
X.java:8: error: method does not override or implement a method from a supertype
#Override
^
1 error
If it were legal, then it would be impossible to reliably compile even very simple methods like:
public static void f(X x) {
x.f(5);
}
If x were an actual X object, that code would work fine, but if x were a Y subtype, it would fail, because 5 is not a String.
This is why the above definition of Y.f is not allowed to override X.f.
By changing FirstProcesser to accept only User objects, you are causing the same problem.
Chain of Responsibility
The
chain of responsibility pattern on Wikipedia
doesn't look much like what you're trying to build.
I can think of two things you might be trying to do...
1.
If the parent parameter is supposed to be the previous handler in the chain, then it should be of type Processer<X>:
public interface Processer<X> {
void process(Processer<X> parent, X result);
}
class StringProcesser implements Processer<String> {
#Override
public void process(Processer<String> parent, String result) {
}
}
2.
If the type of parent is part of the decision-making process, each handler should store a collection of the Class objects it can handle.
The process method should then see if parent.getClass() is in that collection.
A partial definition might look something like:
public interface Processer<X> {
void process(Class<?> parent, X result);
}
class StringProcesser implements Processer<String> {
private Set<Class<?>> classes = new HashSet<Class<?>>();
public StringProcesser(final Iterable<Class<?>> classes) {
for (final Class<?> c : classes) {
this.classes.add(c);
}
}
#Override
public void process(Class<?> parent, String result) {
if (this.classes.contains(parent)) {
System.err.println("Handling...");
System.out.println(result);
return;
}
System.err.println(
"Can't handle. Try next Processer."
);
// ...
}
}
Note that where the generic type parameter <X> and where the wildcard <?> show up depends on what you're trying to do.
PS: "Processer" should be spelled "Processor".

Make sure Type instance represents a type assignable from certain class

I'm primarily a Java programmer, so this would be one of those "what is this thing from Java equivalent to in C#" questions. So, in Java, you can restrain a Class type argument at compile time to extend a certain super-class, like so:
public <T extends BaseClass> void foo(Class<T> type) {
...
}
and even
public <T extends BaseClass> T foo(Class<T> type) {
...
}
You can even chain multiple interfaces:
public <T extends BaseClass & BaseInterface1 & BaseInterface2> void foo(Class<T> type) {
...
}
How is this done in C#? I know you can use "where T : BaseClass", but this is only applicable when you have an instance T. What about when you only have a Type instance?
EDIT:
For explanation, here is what I would like to do:
ASSEMBLY #1 (base.dll):
abstract class BaseClass {
abstract void Foo();
}
ASSEMBLY #2 (sub1.dll, references base.dll):
class SubClass1 : BaseClass {
void Foo() {
// some code
}
}
ASSEMBLY #3 (sub2.dll, references base.dll):
class SubClass2 : BaseClass {
void Foo() {
// some other code
}
}
ASSEMBLY #4 (main.dll, references base.dll):
class BaseClassUtil {
static void CallFoo(Type<T> type) where T : BaseClass {
T instance = (T)Activator.CreateInstance(type);
instance.Foo();
}
}
public static void Main(String[] args) {
// Here I use 'args' to get a class type,
// possibly loading it dynamically from a DLL
Type<? : BaseClass> type = LoadFromDll(args); // Loaded from DLL
BaseClassUtil.CallFoo(type);
}
So, in this example, I don't care what class the 'type' variable represents, as long as it is derived from BaseClass, so once I create an instance, can call Foo().
The parts that are not vaild C# code (but rather some Java mockup) are the "generic" Type classes: Type<T> and Type<? : BaseClass>.
No, there is no way to enforce at compile time that a Type be assignable to a generic type. If I understand correctly, what you want is:
void Foo<T>(Type type) { ... } //compile time error if an instace typed `type` is not assignable to `T`.
Which means:
void Foo<IFormattable>(typeof(string)); //ok
void Foo<IDisposable>(typeof(string)); //compile time error
Evidently at runtime it is trival, but the language has no support for this at compile time.
From what I understood you are talking about generic type constraint
public void Foo<T>(Type type) where T:BaseClass, BaseInterface1, BaseInterface2
{
//your code
}
Here another article:Constraints on Type Parameters (C# Programming Guide)
When you define a generic class, you can apply restrictions to the
kinds of types that client code can use for type arguments when it
instantiates your class. If client code tries to instantiate your
class by using a type that is not allowed by a constraint, the result
is a compile-time error.
EDIT:
Here your example. Now if you try to call BaseClassUtil.CallFoo<T> with something different from BaseClass and his derived classes you will receive an compile error. Here full example in dotNetFiddle. So the tricky part is the restriction of your class should happen in the Util class
public static void Main(string[] args)
{
//so your LoadFromDll method should return Type. Type doesn't have generic implementation !
Type type = typeof(SubClass1);
BaseClassUtil.CallFoo<BaseClass>(type);
Type type2 = typeof(SubClass2);
//you can write BaseClassUtil.CallFoo<SubClass2>(type2); if you want
BaseClassUtil.CallFoo<BaseClass>(type2);
}
public class BaseClassUtil
{
public static void CallFoo<T>(Type type) where T : BaseClass
{
T instance = (T)Activator.CreateInstance(type);
instance.Foo();
}
}
public class TestClass
{
public int ID { get; set; }
}
public abstract class BaseClass
{
public abstract void Foo();
}
public class SubClass1 : BaseClass
{
public override void Foo()
{
Console.WriteLine("SubClass 1");
}
}
public class SubClass2 : BaseClass
{
public override void Foo()
{
Console.WriteLine("SubClass 2");
}
}

Java compare generic type with Void

I have problem with comparing java generic type if it is type of Void or not. In other words I'm trying to ensure if my generic type T is Void or not.
My sample implementation:
public abstract class Request<T>{
private T member;
protected void comparing(){
if(T instanceof Void) // this make error "Expression expected"
runAnotherMethod();
//if I type
if(member instanceof Void) //Incovertible types; cannot cast T to java.lang.Void
runAnotherMethod();
}
protected void runAnotherMethod(){...}
}
public class ParticularRequest extends Request<Void>{
}
I've tried to compare id via instanceof, Class<T> and Class<Void>, T.class and Void.class.
But the AndroidStudio show me error in every tried case :(
can you help me how to compare it?
thanks.
When using java generics you often need to ask for the class of the generic type in the constructor so that you can actually work with the class. I guess, that is a confusing sentence so just see the example below:
public abstract class Request<T> {
private Class<T> clazz;
// constructor that asks for the class of the generic type
public Request(Class<T> clazz) {
this.clazz = clazz;
}
// helper function involving the class of the generic type.
// in this case we check if the generic type is of class java.lang.Void
protected boolean isVoidRequest(){
return clazz.equals(Void.class);
}
// functionality that depends on the generic type
protected void comparing() {
if (isVoidRequest()) {
runAnotherMethod();
}
}
// ...
}
When you subclass you must pass the class of the generic type to the super constructor.
public class LongRequest extends Request<Long> {
public LongRequest() {
super(Long.class);
}
}
public class VoidRequest extends Request<Void> {
public VoidRequest() {
super(Void.class);
}
}
You can store a private member that is of the generic type of the class.
public abstract class Request<T> {
private T memberOfGenericType;
protected void comparing() {
if (memberOfGenericType instanceof Sometype)
runAnotherMethod();
}
protected void runAnotherMethod() { ... }
public T getMemberOfGenericType() {
return memberOfGenericType;
}
public void setMemberOfGenericType(T value) {
this.memberOfGenericType = value;
}
}
This way, at Runtime, the memberOfGenericType will have the type of Sometype and you will be able to compile the if statement. You can also verify that the memberOfGenericType is Sometype at Runtime, by using the getter I've added.
Anyhow, as a side note, I would say that there's no need of generic type, if you don't use it as a type for a member, method or method parameter and then you should re-consider your design. Also, in particular, the type Void is not instantiable, so you wouldn't be able to pass a valid instance for the class member, which more or less makes the if statement useless.
You can't use T like that. You need some instance to compare. For example some member or parameter:
public abstract class Request<T> {
T member;
protected void comparing(T param){
if(member instanceof Void)
runAnotherMethod();
if(param instanceof Void)
runAnotherMethod();
}
protected void runAnotherMethod(){...}
}
A better approach to accessing the parameter class, used by Guice, is to use the fact that, while a generic class cannot access its own 'class' arguments, its subclasses do have access to these arguments: see https://stackoverflow.com/a/18610693/15472
If you need this, either use Guice' TypeLiterals, or reimplment their logic.
Since there are no objects that are instances of the Void type in Java you can't use instanceof here.
null is the only value that is a member of the type Void. So maybe what you want to do is this?:
if (memberOfGenericType == null)
runAnotherMethod();
About the type Void
No objects of type Void can be created because the class only has a private constructor and it is never invoked from within the class. Void is usually used in these situations:
To get a Class object that represents the return type of methods declared to return void.
As a placeholder type argument, when the fields and variables of that type are not meant to be used.
At run-time T is compiled as Object, and the actual class is unknown. As others said, you should maintain an instance of your parametrized type, but this is not automatic: You need to instantiate it, and the constructor T() cannot be used.
Also java.lang.Void cannot be instantiated, so you should use another class, like a self-made Void class.
Try something like this:
public final class Void {}; // cannot use java.lang.Void, so create another class...
public abstract class Request<T> {
protected abstract T member(); // A member would need to be initialized...
protected void comparing(T param){
if(member() instanceof Void) // Use our Void not java.lang.Void
runAnotherMethod();
}
protected void runAnotherMethod(){...}
}
public class ParticularRequest extends Request<Void>{
#Override
protected Void member() { return new Void(); } // Could be optimized...
}
Edit:
I do not see, why would you need this, however.
If you have different children for different types, then you also could have different implementations, too.
Something like this (types and methods are for example only):
public abstract class Request<T> {
protected abstract T method();
}
public class RequestInt extends Request<Integer> {
#Override
protected Integer method() {...}
}
public class RequestText extends Request<String> {
#Override
protected String method() {...}
}

Overloading / generics in Java

I want to run certain tests in Lists. The Lists can contain entirely different classes.
I have one method to check the consistency of the list - not null, not empty, no more than x elements. This is common to all the lists. Then I want to test each of the objects, using overloading.
The idea would be something like:
public static <T> void check(List<T> list) {
//do general checks
for (T element : list) {
check(element);
}
}
and then
public static void check(SomeType element) {...}
public static void check(SomeOtherType element) {...}
But I also had to add a method like this:
public static void check(T element) {...}
And this was called at runtime - not my other methods with the specific classes. Although the class was exactly the same. I'm evidently missing some generics understanding.
Now if I don't use the general method at all and try to solve it this way:
public static void check(List<SomeType> list) {...}
public static void check(List<SomeOtherType> list) {...}
Compiler error - "Method check(List) has the same erasure check(List) as another method..."
So is there any elegant solution for this? I could just use different method names but would like to know how it's possible without that.
Thanks!
This isn't something about generics that you're missing. Java does not have double dispatch. The call to check must be resolved at compile-time, and check(T) is the only match since the compiler can't tell if T is SomeType or SomeOtherType in a given scenario. It needs to choose one method to call that will work for all possible Ts.
This is sometimes solved using the visitor pattern.
The problem should be solved by the caller. When it instanciate your class with a concrete type for T, it should also pass an instance of Checker<T> with the same concrete type:
public class SomeClass<T> {
private List<T> list;
private Checker<T> checker;
public SomeClass(Checker<T> checker) {
this.checker = checker;
}
public void check() {
checker.check(list);
}
}
public interface Checker<T> {
public void check(List<T> list);
}
...
SomeClass<Foo> someClass = new SomeClass<Foo>(new Checker<Foo>() {
#Override
public void check(List<Foo> list) {
// do whatever you want here
}
});
You can use instanceof to dispatch:
public static <T> void check(List<T> list) {
for (T element : list) {
check(element);
}
}
public static void check(T t) {
if (t instanceof SomeType) {
SomeType someType = (SomeType) t;
// code for SomeType ...
} else if (t instanceof OtherType) {
OtherType otherType = (OtherType) t;
// code for OtherType ...
} else {
// we got a type that we don't have a method for
}
}
With generics, the type parameter is actually erased during compilation, and the list object don't know anything about the static type of the object it contains. Since it doesn't know it, it can not use overloading to call methods with different parameters, because Java doesn't support multiple dispatch.
You have then three choices:
Make your objects implement a Checked interface with a check method that does the check logic. Downside is that the check logic is now dispersed in several places and it is not practical if you have objects of classes you don't have control of.
Use instanceof to call explicitly the check methods according to the dynamic type of the object. Downside is you potentially end up with a big if/else block a bit harder to maintain.
Implement the visitor pattern. Downside is that you have to change the object classes too, but the check logic stay in a single place.
Since the type of the variable is lost in check(List<T> list) you have two options:
1. Do different things by checking runtime type
check(T element) {
if (element.getClass().equals(SomeType.class)) {
check((SomeType) element);
} elseif (element.getClass().equals(SomeOtherType.class)) {
check((SomeOtherType) element);
}
This can be made a little more sophisticated, for example by wrapping each check in a Callable and using a Map<Class, Callable>
This is similar to visitor pattern.
2. Calling a virtual method on the element to be checked itself
If the checking logic can be pushed to the object to be checked itself (this is not necessarily a bad thing) then you don't need to check types:
interface Checkable { void check(); }
class SomeType implements Checkable { .... }
class SomeOtherType implements Checkable { .... }
Then:
public static <T extends Checkable> void check(List<T> list) {
for (T element : list) {
element.check();
}
}
These are the only two options, any implementation has to be a variation on one of these

Method with typed list and inheritance

I have some troubles with a method having a typed List parameter, inherited from another (typed) class.
Let's keep it simple :
public class B<T> {
public void test(List<Integer> i) {
}
}
The B class has a useless generic T, and test() want an Integer List.
Now if I do :
public class A extends B {
// don't compile
#Override
public void test(List<Integer> i) {
}
}
I get a "The method test(List) of type A must override or implement a supertype method" error, that should not happen.
But removing the type of the list works... although it doesn't depend on the class generic.
public class A extends B {
// compile
#Override
public void test(List i) {
And also defining the useless generic below to use the typed list
public class A extends B<String> {
// compile
#Override
public void test(List<Integer> i) {
So I'm clueless, the generic of B should have no influence on the type of the test() list. Does anyone have an idea of what's happening?
Thanks
You're extending the raw type of B, not the generic one. The raw one effectively does not have a test(List<Integer> i) method, but a test(List) method.
If you switch to raw types, all generics are replaced by raws, regardless of whether their type was filled in or not.
To do it properly, do
public class A<T> extends B<T>
This will use the generic type B<T>, which includes the method you want to override.
When you remove use a class without generics (and use it raw), all generics from class methods are forgotten.
Due this reason when you inform the generic type on the second case you get it working.
This:
class T<G> {
public void test(G g);
}
in this case:
class A extends T {
}
will look like this:
class T {
public void test(Object g);
}
This was a java puzzle presented on Google IO 2011 you can see video here

Categories