3

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.

feromakovi
  • 99
  • 2
  • 9
  • 1
    What errors are you getting? They may explain why each approach is not working... – tucuxi Dec 03 '14 at 10:17
  • 3
    I'm not sure what is the purpose of that code, but Void is a uninstanciable class, so that intanceof will always return false – Pablo Lozano Dec 03 '14 at 10:17
  • I would like to use it in order to ensure more detailed generic type in child classes of Request. I use it in other methods of parent and child classes – feromakovi Dec 03 '14 at 10:32

6 Answers6

2

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);
    }
}
Rob Meeuwisse
  • 2,847
  • 1
  • 17
  • 21
1

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.

Konstantin Yovkov
  • 62,134
  • 8
  • 100
  • 147
  • If I do it like your exmaple so it get me error on the line: if(member instanceof Void) //Incovertible types; cannot cast T to java.lang.Void – feromakovi Dec 03 '14 at 10:30
  • I don't get any **compilation** errors. Are you sure you haven't mixed up something? – Konstantin Yovkov Dec 03 '14 at 10:33
  • The "if" will always return false, because (null instanceof Anything) is false, by the definition of instanceof: http://stackoverflow.com/questions/2950319/is-null-check-needed-before-calling-instanceof – tucuxi Dec 03 '14 at 10:40
  • 1
    @kocko -- but that makes your answer a non-answer: "you can do it like this" + "it is always wrong to do it like this" == "do not do this" – tucuxi Dec 03 '14 at 10:43
0

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(){...}
}
loshad vtapkah
  • 429
  • 4
  • 11
0

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.

Community
  • 1
  • 1
tucuxi
  • 17,561
  • 2
  • 43
  • 74
0

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.
Lii
  • 11,553
  • 8
  • 64
  • 88
0

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() {...}
}
Usagi Miyamoto
  • 6,196
  • 1
  • 19
  • 33