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
java generics


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 to share


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 to share


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 to share


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 to share


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 to share


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 to share







All Articles
Loading...
X
Show
Funny
Dev
Pics