2

これで私を助けてくれることを願っています:私は...

  • と呼ばれるクラス名の文字列リストclassNameList
  • ジェネリック クラスGeography<T>
  • 静的ジェネリック メソッド<T> void read(Class<T> cl, Geography<T> geo)

文字列クラス名リストをループして、これらのクラスごとにジェネリック メソッドを呼び出したいと考えています。

私が試したことは明らかにうまくいきませんでした:

for (int i = 0; i < classNameList.length; i++) {
   Class<?> myClass = Class.forName(classNameList[i].getName());
   Geography<myClass.newInstance()> geo;
   read(myClass, geo);
}

エラー: myClass.newInstance を型に解決できません

私のコードは、ジェネリック関数の 1 回の呼び出しで完全に実行されます。

Geography<ExampleClass> ExampleGeo;
read(ExampleClass.class, ExampleGeo);

これを行う方法はありますか?

アップデート:

有益な情報をありがとうございます。それでも、実際のコードに採用するのは難しいです。したがって、これは単純化されていない問題です。

ShapefileLoader を使用して shapefile-Data を準備します。Shapefile の各機能について、クラス (GuadAgent) が事前定義されたクラス (PlantWind) で初期化されます。入力ディレクトリにシェープファイルがあり、それらの機能が表すクラスの名前が含まれています。Java がシェープファイルを読み込んで、それぞれのエージェント クラスを作成するようにします。(エージェントはコンテキストと地理にも配置されます。) 使用されるクラスは次のとおりです: ShapefileLoaderGeography、他のクラスは同じ Web サイトにあります。

この部分は main-method にあります。

Geography<GuadAgent> guadGeography = GeographyFactoryFinder.createGeographyFactory(null).createGeography("guadGeography", context, new GeographyParameters<GuadAgent>());
Context<GuadAgent> context = new DefaultContext<GuadAgent>();

FileFilter filter = new FileFilter() {
    @Override
    public boolean accept(File file) {
        return file.getName().endsWith(".shp"); // return .shp files
    }
};
String shapefileDir = System.getProperty("user.dir")+"\\input\\shp\\";
File folder = new File(shapefileDir);
File[] listOfFiles = folder.listFiles(filter);

for (File classFile : listOfFiles) {
        try {
            readForName(classFile,context,guadGeography);
        } catch (ClassNotFoundException | MalformedURLException
                | FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
}

名前を読み取る静的メソッド:

static <T> void readForName(File classFile, Context<GuadAgent> context,Geography<GuadAgent> guadGeography) throws ClassNotFoundException, MalformedURLException, FileNotFoundException {

        String shapefileDir = System.getProperty("user.dir")+"\\input\\shp\\";
        String className = classFile.getName().split("\\.(?=[^\\.]+$)")[0];
        File shapefile = null;
        shapefile = new File(shapefileDir+classFile.getName());

        if (!shapefile.exists()) {
            throw new FileNotFoundException("Could not find the given shapefile: " + shapefile.getAbsolutePath());
        }

        switch (className) {
        case "PlantWind":           
            ShapefileLoader<PlantWind> PlantWindLoader = new ShapefileLoader<PlantWind>(PlantWind.class,shapefile.toURI().toURL() , guadGeography, context);
            PlantWindLoader.load();
            PlantWindLoader.close();
            System.out.println(context.getObjects(PlantWind.class).size());                     
            break;
    // Todo Add other Agent types
    default:
        break;
    }

どうすればスイッチを外すことができますか? それらの数は有限ですが、非常に多くの異なるエージェントがいます...

4

3 に答える 3

1

残念ながら、あなたの意図に近い構文はありません (良いアイデアですが)。

基本的な問題は、これがClass.forName()不明を返すことです。そのため、どこかClass<?>にキャストする必要があります。それはあなたがそれを置く場所の問題です。

read()クラス名に基づいて実行することをバンドルするこのアプローチ(コンパイルする)をお勧めします。

static <T> void readForName(String className) throws ClassNotFoundException {
    Class<T> myClass = (Class<T>) Class.forName(className);
    Geography<T> geo = new Geography<T>();  // No code shown. Adjust as required
    read(myClass, geo);
}

コードを整理するために、 foreachループ構文を使用することもお勧めします。

for (String className : classNameList) {
    readForName(className.getName());
}
于 2014-10-10T02:23:53.330 に答える
1

実行時にジェネリック型からインスタンスを作成する

あなたが達成しようとしていることは完全にはわかりませんが、一見すると、最も単純な解決策が最善の解決策であるように見えます。

オブジェクトを作成するために任意のコードを動的に評価および実行できるスクリプト環境 (Groovy、JavaScript、JRuby、Jython) を使用して解決できますが、オブジェクトを作成するためだけに、非常に複雑で過度に複雑になりました。

しかし、残念ながら、私はそれが非常に平凡な解決策を持っていると思います.

サポートされているタイプの定義済みセットがある限り、Factoryパターンを使用できます。ここでは/パッケージのProvider<>Tインターフェースを利用しています。javax.injectcom.google.inject

Q26289147_ProviderPattern.java

public class Q26289147_ProviderPattern
{
    private static final List<String> CLASS_NAMES = ImmutableList.of("String", "Integer", "Boolean");
    private static final Map<String, Provider<StrawManParameterizedClass>> PROVIDERS;

    static
    {
        final ImmutableMap.Builder<String, Provider<StrawManParameterizedClass>> imb = ImmutableMap.builder();
        for (final String cn : CLASS_NAMES)
        {
            switch (cn)
            {
                case "String":
                    imb.put(cn, new Provider<StrawManParameterizedClass>()
                    {
                        @Override
                        public StrawManParameterizedClass<String> get() { return new StrawManParameterizedClass<String>() {}; }
                    });
                    break;
                case "Integer":
                    imb.put(cn, new Provider<StrawManParameterizedClass>()
                    {
                        @Override
                        public StrawManParameterizedClass<Integer> get() { return new StrawManParameterizedClass<Integer>() {}; }
                    });
                    break;
                case "Boolean":
                    imb.put(cn, new Provider<StrawManParameterizedClass>()
                    {
                        @Override
                        public StrawManParameterizedClass<Integer> get() { return new StrawManParameterizedClass<Integer>() {}; }
                    });
                    break;
                default:
                    throw new IllegalArgumentException(String.format("%s is not a supported type %s", cn, Joiner.on(",").join(CLASS_NAMES)));
            }
        }
        PROVIDERS = imb.build();
    }

    static <T> void read(@Nonnull final StrawManParameterizedClass<T> smpc) { System.out.println(smpc.type.toString()); }

    static abstract class StrawManParameterizedClass<T>
    {
        final TypeToken<T> type = new TypeToken<T>(getClass()) {};

        @Override
        public String toString() { return type.getRawType().getCanonicalName(); }
    }

    public static void main(final String[] args)
    {
        for (final String cn : CLASS_NAMES)
        {
            read(PROVIDERS.get(cn).get());
        }
    }
}

免責事項:

これは概念実証の例にすぎません。キーに基づいて作成する型のロジックをカプセル化するためにまたはパターンをswitch 使用するようなステートメントを本番コードで使用することは決してありません。Strategy PatternChain of ResponsibilityClassName

これは、最初はジェネリックの問題のように見えましたが、そうではなく、作成の問題です。

そうは言っても、Guavaを使用して実行時にパラメーター化されたクラスから情報Class<?>を取得できるインスタンスを渡す必要はありません。Generic TypeTypeToken

TypeTokenGuava ライブラリを使用して、実行時にジェネリック型のインスタンスを作成することもできます。

主な問題は、この構文がサポートされていないことです。上記の実装Geography<myClass.newInstance()> geo;以外に偽造する方法は考えられません。Provider

TypeTokenこれは、パラメーター化されたクラスが常にその型を認識できるようにするための使用方法のストローマンの例です!

Q26289147.java

import com.google.common.reflect.TypeToken;

public class Q26289147
{
    public static void main(final String[] args) throws IllegalAccessException, InstantiationException
    {
        final StrawManParameterizedClass<String> smpc = new StrawManParameterizedClass<String>() {};
        final String string = (String) smpc.type.getRawType().newInstance();
        System.out.format("string = \"%s\"",string);
    }

    static abstract class StrawManParameterizedClass<T>
    {
        final TypeToken<T> type = new TypeToken<T>(getClass()) {};
    }
}

ノート:

  1. デフォルトの引数なしコンストラクターを持つクラスに最適です。
  2. デフォルトの no arg コンストラクターがない場合は、単純なリフレクションを使用するよりもうまく機能します。
  3. Injector の ".getRawType() generatedClass to pass togetInstance()` を使用できるように、Guice とうまく連携する必要があります。これはまだ試していませんが、考えただけです!
  4. あちこちにClass<T>.cast()必要のないキャストを行うために使用できます。@SuppressWarning("unchecked")
于 2014-10-10T02:41:28.443 に答える