我有一个界面:
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());
}
}
答案 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();
}
}