简体   繁体   English

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

[英]How to initializing Class<T> at interface default method?

I have an interface: 我有一个界面:

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 error message the starred line: 错误消息加星号的行:

The local variable s may not have been initialized 局部变量s可能尚未初始化

The local variable t may not have been initialized 局部变量t可能尚未初始化

I would like to use this method to return a string with [S.classname][T.classname] . 我想使用此方法返回带有[S.classname] [T.classname]的字符串。 Please let me know how to achieve this or is this impossible to do at interface ? 请让我知道如何实现此目标,或者在接口上无法做到这一点?

Update: Jan 12 更新:1月12日

My purpose of doing this is due to the fact that this class will be in framework and I want to reduce the human error as much as possible.. I am changing the code as follows: 我这样做的目的是由于该类将在框架中,并且我想尽可能减少人为错误。.我将代码更改如下:

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

}

In order to demonstrate why this can't work, you may change your class to 为了说明为什么这行不通,您可以将课程更改为

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

Running this will print true . 运行此命令将打印true In other words, both functions are represented by the same instances, so there can't be and property allowing to recognize their different type. 换句话说,两个函数都由相同的实例表示,因此不能存在和属性来允许识别它们的不同类型。

Generally, when two functions (lambda expressions or method references) exhibit the same behavior , a JVM may represent them by the same implementation type or even the same instance. 通常,当两个函数(lambda表达式或方法引用)表现出相同的行为时 ,JVM可能会通过相同的实现类型甚至相同的实例来表示它们。

Even for non-interface classes, this doesn't work due to Type Erasure . 即使对于非接口类,由于Type Erasure也无法使用。 It only works when you have a reifiable (ie non-generic) type extending or implementing a generic type. 仅当您具有可扩展 (即非泛型)类型扩展或实现泛型类型时,它才起作用。

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

It's a little bit dangerous and I wouldn't used this in production (because you should cover in your code all possible use cases of your interface), but you can use reflection for it: 这有点危险,我不会在生产中使用它(因为您应该在代码中涵盖接口的所有可能用例),但是您可以使用反射:

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

Output for this snippet: 此代码段的输出:

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


java.lang.IllegalStateException: !

This code has one restriction, you should say implements ITransformer<S, T> for all implementations of ITransformer. 此代码有一个限制,您应该说对ITransformer的所有实现都实现implements ITransformer<S, T> That why I have got IllegalStateException for this line ITransformer<String, Double> doubleTransformer = new StringToNumberTransfomer<Double>() . 这就是为什么我在此行ITransformer<String, Double> doubleTransformer = new StringToNumberTransfomer<Double>()获得IllegalStateException原因。 But you can improve this code. 但是您可以改进此代码。

Better option is to use some base implementation of interface and pass source and target classes into constructor: 更好的选择是使用接口的一些基本实现,并将源类和目标类传递到构造函数中:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM