3

I have the following interface:

public interface Caster{

    public boolean tryCast(Object value);

}

and its implementations:

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;
            }
       }
}

Is it possible to make such implementation generic? We can't quite take and declare Caster with type parameter, because we won't be able implement it as follows:

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;
        }
   }
}
1
  • 2
    Why not using Integer.class.isInstance, Date.class.isInstance, etc instead of this interface? Commented May 14, 2015 at 10:47

6 Answers 6

4

You have to inject the Class value, parameterized by T, within your Generic CasterImpl.

Something like this:

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 don't see a reason why the Caster interface is Generic, since you don't use the type-parameter within the interface.

Sign up to request clarification or add additional context in comments.

4 Comments

tryCast(Object value) must be written as tryCast(T value)
Yes, if the method signature in the interface is changed.
Actually, pretty simple. I'll do it that way.
@prashantthakre: if the object to be casted is already T, then what's the point of casting it to T?
4

This can be done without interface at all using standard Class.isInstance method. 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;
}

Comments

3

Generics in Java are implemented by erasure. Java produces a single bytecode for all T.

So this:

return T.class.cast(value);

would - if it were allowed - become essentially a

return Object.class.cast(value);

no matter which T you specify. If you want to check a specific class, you need a Class<T> object.

Use someclass.isInstance(obj) instead.

Right now, you are reinventing the Class<T> API.

Comments

1

Sure, just store the class of T to use later 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;
        }
   }
}

Comments

1

Instances of a generic type do not store their generic type parameter.

You can store the class as kocko said or you can store the generic type parameter inside 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];
    }
}

That will only work with subclasses like this, that store the type in it's 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

Comments

0

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;
        }
   }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.