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

How to initializing Class<T> at interface 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();  //*********
    }
    
}

带星号的错误消息:

The local variable s may not have been initialized

The local variable t may not have been initialized

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

更新:1 月 12 日

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

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

在 Java 中不可能得到 Class<S>,除非你已经知道 class S 是哪个,或者其他知道 [=16= 是哪个的东西] S给你一个。

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

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

为了演示为什么这行不通,您可以将 class 更改为

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 可以用相同的实现类型甚至相同的实例来表示它们。

即使对于非接口 classes,由于 Type Erasure,这也不起作用。它仅在您具有扩展或实现通用类型的 reifiable(即非通用)类型时才有效。