0

我有一个界面:

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());
    }
    
}
4

3 回答 3

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,这也不起作用。它仅在您具有扩展或实现泛型类型的可具体化(即非泛型)类型时才有效。

于 2017-01-11T11:11:28.420 回答
1

在 Java 中,不可能获得Class<S>,除非您已经知道哪个类S是,或者其他知道哪个类S的东西会给您一个。

于 2017-01-11T10:29:47.240 回答
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: !

这段代码有一个限制,你应该说 implements ITransformer<S, T>对于 ITransformer 的所有实现。这就是为什么我有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();
    }
}
于 2017-01-11T11:08:29.407 回答