获取字段的名称

在Java中是否可以从实际字段中获取字符串中的字段名称? 喜欢:

public class mod { @ItemID public static ItemLinkTool linkTool; public void xxx{ String fieldsName = *getFieldsName(linkTool)*; } } 

PS:我不是在寻找字段的类/类名或从字符串中获取字段。


编辑:当我看着它时,我可能不需要一个方法来获取字段的名称,Field实例(来自字段的“代码名称”)就足够了。 [例如Field myField = getField(linkTool) ]

在Java本身可能没有我想要的东西。 我将看看ASM库,但最后我可能最终使用字符串作为字段的标识符:/


编辑2:我的英语不是很好(但即使用我的母语,我也有解释这个问题),所以我再添加一个例子。 希望现在会更清楚:

 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,但谁知道..)

不幸的是,没有办法做你想做的事。 为什么?

在我们仍然试图certificateJava不慢的时代,存储构造对象的位置或方式的元数据会产生很大的开销,并且因为它具有非常小的使用范围,所以它不存在。 不仅如此:还有许多技术原因。

一个原因是因为JVM的实现方式。 可以在此处找到Java class文件格式的规范。 这是非常满口的,但它提供了非常丰富的信息。

正如我之前所说,可以从任何地方构建对象,甚至是对象没有名称的情况 。 只有定义为类成员的对象才具有名称(出于显而易见的原因):在方法中构造的对象不具有名称。 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."":()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_membermy_local_field已被抽象为局部变量表中的索引1( this保留0)。

这本身对于调试器来说是一种痛苦,因此设计了一组属性(想想类文件的元数据)。 这些包括LocalVariableTable , LineNumberTable和LocalVariableTypeTable 。 这些属性对堆栈跟踪(LineNumberTable)和调试器(LocalVariableTable和LocalVariableTypeTable)非常有用。 但是,这些是完全可选的包含在文件中,并且不能保证它们是:

LineNumberTable属性是属性表中的可选变长属性

其他人也是如此。

此外,大多数编译器默认情况下除了LineNumberTable之外不会产生任何东西,所以即使可能,你也会运气不好。

基本上,对于开发人员来说,拥有一个getFieldName(object) (这在本地变量的首位是不可能的getFieldName(object)是非常令人沮丧的,并且只有当这些属性存在时才能使用它。

因此,在可预见的将来,使用带字符串的getField遇到getField 。 无耻的插件: IntelliJ似乎很好地处理了具有reflection的重构:编写Minecraft mods以及我知道这种感觉,并且可以说IntelliJ显着减少了重构工作。 但对于大多数现代IDE来说也是如此:我确信大型玩家Eclipse,Netbeans 等。 拥有良好实施的重构系统。

如果该字段是私有的,您可以访问它:

 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. 

如果您不知道该字段的名称……那么..那么您希望得到什么字段? :)您可以使用reflection获取所有字段然后循环它们。但是如果您不知道该字段,此操作中的实际意义和逻辑是什么?

这只能通过reflection来实现。

使用Class.getDeclaringFields ()和java.reflection.Field.getName()

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; } 

获取字段名称的动机是使用它来搜索键值数据库中的内容(如mongodb)。 我有一个结构,其成员(字段)代表保存的数据。 我使用成员名称来搜索数据库

我的建议是为每个重要成员放置一个静态getter。 例:

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

希望Java将来会有一些机制,因为现在,元数据可能是数据的一部分。 特别是在使用JSON时。

它可以使用运行时字节代码检测来完成,例如使用Byte Buddy库, 在Java中查看此等效答案名称

我想这就是你要找的东西。

 SomeClass data; // or List data; etc. List fieldNames = getFieldNamesForClass(data.get(0).getClass()); private static List getFieldNamesForClass(Class clazz) throws Exception { List fieldNames = new ArrayList(); Field[] fields = clazz.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { fieldNames.add(fields[i].getName()); } return fieldNames; }