38

Javaで実際のフィールドから文字列でフィールドの名前を取得することは可能ですか?お気に入り:

public class mod {
    @ItemID
    public static ItemLinkTool linkTool;

    public void xxx{
        String fieldsName = *getFieldsName(linkTool)*;
    }
}

PS:フィールドのクラス/クラス名を探したり、文字列の名前からフィールドを取得したりしていません。


編集:私がそれを見ているとき、私はおそらくフィールドの名前を取得するためのメソッドを必要としないでしょう、フィールドインスタンス(フィールドの「コードネーム」から)で十分でしょう。[例Field myField = getField(linkTool)]

おそらく、Java自体に私が望むようなものはないでしょう。ASMライブラリを見ていきますが、最終的には文字列をフィールドの識別子として使用することになります:/


EDIT2:私の英語は上手ではありません(しかし、私の母国語でもこれを説明するのに問題があります)ので、もう1つの例を追加します。うまくいけば、それは今より明確になるでしょう:

public class mod2 {
    @ItemID
    public static ItemLinkTool linkTool;

    @ItemID
    public static ItemLinkTool linkTool2;

    @ItemID
    public static ItemPipeWrench pipeWrench;

    public void constructItems() {
        // most trivial way
        linkTool = new ItemLinkTool(getId("linkTool"));
        linkTool2 = new ItemLinkTool(getId("linkTool2"));
        pipeWrench = new ItemPipeWrench(getId("pipeWrench"));

        // or when constructItem would directly write into field just
        constructItem("linkTool");
        constructItem("linkTool2");
        constructItem("pipeWrench");

        // but I'd like to be able to have it like this
        constructItemIdeal(linkTool);
        constructItemIdeal(linkTool2);
        constructItemIdeal(pipeWrench);
    }

    // not tested, just example of how I see it
    private void constructItem(String name){
        Field f = getClass().getField(name);
        int id = getId(name);

        // this could be rewritten if constructors take same parameters
        // to create a new instance using reflection
        if (f.getDeclaringClass() == ItemLinkTool){
            f.set(null, new ItemLinkTool(id));
        }else{
            f.set(null, new ItemPipeWrench(id));
        }
    }
}

問題は、constructItemIdealメソッドをどのように見ることができるかということです。(答えと周りのグーグルから、Javaでは不可能だと思いますが、誰が知っていますか..)

4

8 に答える 8

24

残念ながら、あなたが望むことをする方法はありません。なんで?

Javaが遅くないことを証明しようとしている時代では、オブジェクトが構築された場所や方法のメタデータを格納すると、オーバーヘッドが大きくなり、使用範囲が非常に狭いため、存在しません。それだけでなく、技術的な理由もたくさんあります。

1つの理由は、JVMの実装方法によるものです。Javaclassファイル形式の仕様はここにあります。それはかなり一口ですが、それは非常に有益です。

前に述べたように、オブジェクトに名前がない場合でも、オブジェクトはどこからでも構築できます。クラスメンバーとして定義されたオブジェクトのみが名前を持ちます(アクセスの明らかな理由のため):メソッドで構築されたオブジェクトは名前を持ちません。JVMには、最大65535エントリのローカル変数テーブルがあります。これらはスタックにロードされ、*loadおよび*storeオペコードを介してテーブルに格納されます。

言い換えれば、のようなクラス

public class Test {
int class_member = 42;

   public Test() {
      int my_local_field = 42;
   }
}

にコンパイルされます

public class Test extends java.lang.Object
  SourceFile: "Test.java"
  minor version: 0
  major version: 50
  Constant pool:
  --snip--

{
int class_member;

public Test();
  Code:
   Stack=2, Locals=2, Args_size=1
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   bipush  42
   7:   putfield        #2; //Field class_member:I
   10:  bipush  42
   12:  istore_1
   13:  return
  LineNumberTable:
   --snip--    
}

javap -v Testここでは、名前class_memberが保持されmy_local_fieldている間、ローカル変数テーブルのインデックス1に抽象化されているという明確な例を見ることができます(0はのために予約されていますthis)。

これ自体がデバッガーなどにとって苦痛になるため、一連の属性(クラスファイルのメタデータを考えてください)が設計されました。これらには、LocalVariableTableLineNumberTable、およびLocalVariableTypeTableが含まれます。これらの属性は、スタックトレース(LineNumberTable)およびデバッガー(LocalVariableTableおよびLocalVariableTypeTable)に役立ちます。ただし、これらをファイルに含めることは完全にオプションであり、次のことを保証するものではありません。

LineNumberTable属性は、属性テーブルのオプションの可変長属性です。

同じことが残りの人にも当てはまります。

さらに、ほとんどのコンパイラはデフォルトでLineNumberTable以外のものを生成しないため、可能であったとしても運が悪いでしょう。

getFieldName(object)基本的に、開発者が(ローカル変数ではそもそも不可能である)を持ち、それらの属性が存在する場合にのみ機能することは非常に苛立たしいことです。

getFieldそのため、 Stringsでの使用は、当面の間行き詰まります。恥知らずなプラグイン:IntelliJはリファクタリングを非常にうまく処理しているようです:Minecraft modを書いたことも私はその感覚を知っており、リファクタリングの作業はIntelliJによって大幅に削減されたと言えます。しかし、同じことがおそらくほとんどの最新のIDEにも当てはまります。大きなプレーヤーであるEclipse、Netbeansなどだと確信しています。適切に実装されたリファクタリングシステムがあります。

于 2013-02-20T00:10:39.480 に答える
12

フィールドがプライベートの場合は、アクセス可能にすることができます。

Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
String value = (String)field.get(object); // to get the value, if needed. In the example is string type

フィールドの名前を取得するには、次のようにします。

//use the field object from the example above
field.getName(); // it is in String.

フィールドの名前がわからない場合は...まあ..では、どのフィールドを取得しますか?:)リフレクションを使用してすべてのフィールドを取得し、それらをループすることができます。しかし、フィールドがわからない場合、このアクションの実際の意味とロジックは何ですか?

于 2013-02-18T20:04:56.823 に答える
10

String fieldName = getFieldName(linkTool、this);

private static String getFieldName(Object fieldObject, Object parent) {

    java.lang.reflect.Field[] allFields = parent.getClass().getFields();
    for (java.lang.reflect.Field field : allFields) {
        Object currentFieldObject;
        try {
            currentFieldObject = field.get(parent);
        } catch (Exception e) {
            return null;
        }
        boolean isWantedField = fieldObject.equals(currentFieldObject);
        if (isWantedField) {
            String fieldName = field.getName();
            return fieldName;
        }
    }
    return null;
}
于 2016-02-15T18:32:53.367 に答える
7

これは、リフレクションを介してのみ可能です。

Class.getDeclaringFields)とjava.reflection.Field.getName()

于 2013-02-18T20:03:41.533 に答える
7

これがあなたが探しているものだと思います。

SomeClass data; // or List<SomeClass> data; etc.
List<String> fieldNames = getFieldNamesForClass(data.get(0).getClass());

private static List<String> getFieldNamesForClass(Class<?> clazz) throws Exception {
    List<String> fieldNames = new ArrayList<String>();
    Field[] fields = clazz.getDeclaredFields();
    for (int i = 0; i < fields.length; i++) {
        fieldNames.add(fields[i].getName());
    }
    return fieldNames;
}
于 2018-05-22T10:43:22.510 に答える
4

ロンボクアノテーションを使ってみませんか@FieldNameConstants

@FieldNameConstants
public class Mod {
    public ItemLinkTool linkTool;
}
...
String fieldName = Mod.Fields.linkTool; //fieldName == "linkTool"

この機能を使用すると、フィールド名を取得するためのコードを維持する必要がありません(lombokがそれを行います)。フィールドを削除した後、コンパイラはその使用法について文句を言います。

この機能は実験的なものとしてマークされていることに注意してください。

于 2021-08-06T16:32:35.063 に答える
1

フィールド名を取得する私の動機は、それを使用してKey-Valueデータベース(mongodbなど)内のものを検索することです。保存されたデータを表すメンバー(フィールド)を持つ構造体があります。メンバー名を使用してdbを検索します。

私の提案は、重要なメンバーごとに静的ゲッターを配置することです。例:

public class Data {
  public static String getMember1Key() {
    return "member1";
  }
  public String member1;
}

うまくいけば、Javaには将来、このための何らかのメカニズムがあります。これは、現在、メタデータがデータの一部である可能性があるためです。特にJSONで何かをするとき。

于 2015-08-26T09:06:48.130 に答える
0

これは、ランタイムバイトコードインストルメンテーションを使用して実行できます。たとえば、ByteBuddyライブラリを使用します。Javaで同等のこの回答名を参照してください。

于 2017-11-22T12:32:11.257 に答える