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。つまり、両方の関数が同じインスタンスで表されるため、異なる型を認識できるプロパティは存在しません。

一般に、2 つの関数 (ラムダ式またはメソッド参照) が同じ動作を示す場合、JVM はそれらを同じ実装タイプまたは同じインスタンスで表す場合があります。

非インターフェース クラスの場合でも、これはType Erasureのために機能しません。ジェネリック型を拡張または実装する具体化可能な (つまり、非ジェネリックな) 型がある場合にのみ機能します。

于 2017-01-11T11:11:28.420 に答える
1

Java では、どのクラスがどのクラスであるかを知っているか、またはどのクラスがどのクラスであるかを知っている別の何かがあなたに与えClass<S>ない限り、を取得することは不可能です。SS

于 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: !

このコードには 1 つの制限があります 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 に答える