General method for types

I have the following interface:

public interface Caster{

    public boolean tryCast(Object value);

}

      

and its implementation:

public class IntegerCaster{

    public boolean tryCast(Object value){
        try{
            Integer.class.cast(value);
            return true;
        } catch (ClassCastException e){
            return false;
        }
   }
}
public class DateCaster{

        public boolean tryCast(Object value){
            try{
                Date.class.cast(value);
                return true;
            } catch (ClassCastException e){
                return false;
            }
       }
}

      

Can this implementation be generalized? We cannot take and declare Caster with a type parameter because we cannot implement it like this:

public interface Caster<T>{

    public boolean tryCast(Object value);

}

public class CasterImpl<T> implements Caster<T>{

    public boolean tryCast(Object value){
        try{
            T.class.cast(value); //fail
            return true;
        } catch (ClassCastException e){
            return false;
        }
   }
}

      

+3


source to share


6 answers


You need to enter the value Class

parameterized T

in your Generic CasterImpl

.

Something like that:



public class CasterImpl<T> implements Caster<T> {

    private Clazz<T> clazz;

    public CasterImpl(Class<T> clazz) {
        this.clazz = clazz;
    }

    public boolean tryCast(Object value){
        try{
            clazz.cast(value);
            return true;
        } catch (ClassCastException e){
            return false;
        }
   }
}

      

As a side note: I see no reason why the interface Caster

is generic since you are not using the type parameter in the interface.

+4


source


This can be done without an interface at all using the standard method Class.isInstance

. If you still want to implement this interface use

public Caster getCaster(final Class<?> clazz) {
     return new Caster() {
         public boolean tryCast(Object value) {
             return clazz.isInstance(value);
         }
     };
}

      



Or simpler in Java 8:

public Caster getCaster(final Class<?> clazz) {
     return clazz::isInstance;
}

      

+4


source


Generics in Java are implemented by erasure. Java generates one bytecode for everyone T

.

So this:

return T.class.cast(value);

      

would - if it were allowed - became essentially

return Object.class.cast(value);

      

no matter which one T

you specify. If you want to test for a specific class, you need an object Class<T>

.

Use instead someclass.isInstance(obj)

.

You are currently inventing the APIClass<T>

.

+3


source


Of course, just save the class T

for later use in the constructor:

public interface Caster<T>{

    public boolean tryCast(Object value);

}

public class CasterImpl<T> implements Caster<T>{
   private Class<? extends T> cls;
   public CasterImpl(Class<? extends T> cl) {
      this.cls = cl;
   }

    public boolean tryCast(Object value){
        try{
            cls.cast(value); //fail
            return true;
        } catch (ClassCastException e){
            return false;
        }
   }
}

      

+1


source


Generic type instances do not retain their generic type parameter.

You can keep the class as instructed by kocko, or you can store this type of type in a new type this way:

public abstract class CasterImpl<T> implements Caster<T>{

    public boolean tryCast(Object value){
        try{
            getValueClass().cast(value);
            return true;
        } catch (ClassCastException e){
            return false;
        }
    }

    @SuppressWarnings("unchecked")
    public Class<T> getValueClass() {
        Class<? extends CasterImpl<T>> c = (Class<? extends CasterImpl<T>>) this.getClass();
        ParameterizedType x = (ParameterizedType) c.getGenericSuperclass();
        return (Class<T>) x.getActualTypeArguments()[0];
    }
}

      

This will only work with subclasses that store the type in their own type definition:

public class CasterIntegerImpl extends CasterImpl<Integer> {
    // No need to implement anything
}

      

Test:

    System.out.println(new CasterIntegerImpl().tryCast(1)); // true
    System.out.println(new CasterIntegerImpl().tryCast("")); // false

      

+1


source


Try this, use T instead of Object

public interface Caster<T>{

    public boolean tryCast(T value);

}


public class CasterImpl<T> implements Caster<T>{
   private Class<? extends T> cls;
   public CasterImpl(Class<? extends T> cl) {
      this.cls = cl;
   }

    public boolean tryCast(T value){
        try{
            cls.cast(value); //fail
            return true;
        } catch (ClassCastException e){
            return false;
        }
   }

      

0


source







All Articles