如何在接口默认方法下初始化Class <t>?

时间:2017-01-11 10:22:54

标签: java generics interface java-8 default-method

我有一个界面:

public interface ITransformer<S,T>{

    public void transform(S source,T target);

    default String getTransformerName(){
        Class<S> s;
        Class<T> t;

        return s.getName() + t.getName();  //*********
    }

}

加星标的错误信息:

  

本地变量s可能尚未初始化

     

局部变量t可能尚未初始化

我想使用此方法返回带有 [S.classname] [T.classname] 的字符串。请让我知道如何实现这一点,或者在界面上这是不可能做到的?

更新:1月12日

我这样做的目的是因为这个类将在框架中,我想尽可能地减少人为错误。我正在改变代码如下:

public interface ITransformer<S,T>{

    public void transform(S source,T target);

    public FieldEntry<S, T> getTransformerName();

}


public class FieldEntry<S,T> implements Comparable<FieldEntry> {

    private Class<S> s;
    private Class<T> t;

    public FieldEntry(Class<S> s,Class<T> t){
        this.s = s;
        this.t = t;
    }

    public String getEntryName(){
        return s.getName() + t.getName();

    }

    @Override
    public int compareTo(FieldEntry entry) {
        if(entry == null) throw new IllegalArgumentException("The argument to compare cannot be null!");

        return entry.getEntryName().compareTo(this.getEntryName());
    }

}

3 个答案:

答案 0 :(得分:2)

为了说明为什么这不起作用,您可以将课程改为

public interface ITransformer<S,T>{

    public void transform(S source,T target);

    static <In,Out> ITransformer<In,Out> noOp() {
        return (source,target) -> {};
    }
    static void main(String... arg) {
        ITransformer<String,Integer> t1 = noOp();
        ITransformer<Long,Thread> t2    = noOp();

        System.out.println(t1 == (Object)t2);
    }
}

运行此选项将打印true。换句话说,两个函数都由相同的实例表示,因此不能和属性允许识别它们的不同类型。

通常,当两个函数(lambda表达式或方法引用)展示相同的行为时,JVM可以用相同的实现类型或甚至相同的实例来表示它们。

即使对于非接口类,由于 Type Erasure ,这也不起作用。它只适用于扩展或实现泛型类型的可重新生成(即非泛型)类型。

答案 1 :(得分:1)

在Java中,除非您已经知道哪个类Class<S>,或者知道哪个类S给您一个,否则不可能得到S

答案 2 :(得分:1)

这有点危险,我不会在生产中使用它(因为你应该在你的代码中覆盖你的界面的所有可能用例),但你可以使用反射:

public interface ITransformer<S, T> {

    public void transform(S source, T target);

    default String getTransformerName() {
        Type[] genericInterfaces = this.getClass().getGenericInterfaces();

        ParameterizedType parameterizedType = null;

        for (Type genericInterface : genericInterfaces) {
            if (genericInterface instanceof ParameterizedType) {
                ParameterizedType paramInterface = (ParameterizedType) genericInterface;
                if (paramInterface.getRawType().equals(ITransformer.class)) {
                    parameterizedType = paramInterface;
                    break;
                }
            }
        }

        if (parameterizedType == null) {
            throw new IllegalStateException("!");
        }

        return parameterizedType.getActualTypeArguments()[0].getTypeName() + parameterizedType.getActualTypeArguments()[1].getTypeName();  

    }
}

public class StringToIntegerTransfomer implements ITransformer<String, Integer> {

    @Override
    public void transform(String source, Integer target) {

    }
}

public interface StringToNumberTransfomer<T extends Number> extends ITransformer<String, T> {

}

public class StringToLongTransfomer implements StringToNumberTransfomer<Long>, ITransformer<String, Long> {
    @Override
    public void transform(String source, Long target) {

    }
}

@Test
public void test() {
    ITransformer<String, Integer> intTransformer = new StringToIntegerTransfomer();
    ITransformer<String, Long> longTransformer = new StringToLongTransfomer();
    ITransformer<String, String> stringTransformer = new ITransformer<String, String>() {

        @Override
        public void transform(String source, String target) {

        }
    };
    ITransformer<String, Double> doubleTransformer = new StringToNumberTransfomer<Double>() {

        @Override
        public void transform(String source, Double target) {

        }
    };

    System.out.println(String.format("intTransformer: %s", intTransformer.getTransformerName()));
    System.out.println(String.format("longTransformer: %s", longTransformer.getTransformerName()));
    System.out.println(String.format("stringTransformer: %s", stringTransformer.getTransformerName()));
    System.out.println(String.format("doubleTransformer: %s", doubleTransformer.getTransformerName()));
}

此代码段的输出:

intTransformer: java.lang.Stringjava.lang.Integer
longTransformer: java.lang.Stringjava.lang.Long
stringTransformer: java.lang.Stringjava.lang.String


java.lang.IllegalStateException: !

此代码有一个限制,对于ITransformer的所有实现,您应该说implements ITransformer<S, T>。这就是我为此行IllegalStateException获得ITransformer<String, Double> doubleTransformer = new StringToNumberTransfomer<Double>()的原因。但是你可以改进这段代码。

更好的选择是使用接口的一些基本实现,并将源和目标类传递给构造函数:

public interface ITransformer<S, T> {

    void transform(S source, T target);

    String getTransformerName();
}

public abstract class BaseITransformer<S, T> implements ITransformer<S, T> {

    private final Class<S> sourceClass;
    private final Class<T> targetClass;

    public BaseITransformer(Class<S> sourceClass, Class<T> targetClass) {
        this.sourceClass = sourceClass;
        this.targetClass = targetClass;
    }

    public String getTransformerName() {
        return sourceClass.getName() + targetClass.getName();
    }
}