如何在接口默认方法中初始化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(即非通用)类型时才有效。
我有一个接口:
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(即非通用)类型时才有效。