[英]Get name of a field
在Java中是否可以從實際字段中獲取字符串中的字段名稱? 喜歡:
public class mod {
@ItemID
public static ItemLinkTool linkTool;
public void xxx{
String fieldsName = *getFieldsName(linkTool)*;
}
}
PS:我不是在尋找字段的類/類名稱或從字符串中的名稱獲取字段。
編輯:當我查看它時,我可能不需要獲取字段名稱的方法,Field 實例(來自字段的“代號”)就足夠了。 [例如Field myField = getField(linkTool)
]
Java 本身可能沒有我想要的東西。 我將看一下 ASM 庫,但最后我可能最終會使用字符串作為字段的標識符:/
EDIT2:我的英語不是很好(但即使用我的母語我也很難解釋這一點),所以我再添加一個例子。 希望現在會更清楚:
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 中是不可能的,但誰知道......)
不幸的是,沒有辦法做你想做的事。 為什么?
在我們仍然試圖證明Java不慢的時代,存儲構造對象的位置或方式的元數據會產生很大的開銷,並且因為它具有非常小的使用范圍,所以它不存在。 不僅如此:還有許多技術原因。
一個原因是因為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."<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( this
保留0)。
這本身對於調試器來說是一種痛苦,因此設計了一組屬性(想想類文件的元數據)。 這些包括LocalVariableTable , LineNumberTable和LocalVariableTypeTable 。 這些屬性對堆棧跟蹤(LineNumberTable)和調試器(LocalVariableTable和LocalVariableTypeTable)非常有用。 但是,這些是完全可選的包含在文件中,並且不能保證它們是:
LineNumberTable屬性是屬性表中的可選變長屬性
其他人也是如此。
此外,大多數編譯器默認情況下除了LineNumberTable之外不會產生任何東西,所以即使可能,你也會運氣不好。
基本上,對於開發人員來說,擁有一個getFieldName(object)
(這在本地變量的首位是不可能的getFieldName(object)
是非常令人沮喪的,並且只有當這些屬性存在時才能使用它。
因此,在可預見的將來,使用帶字符串的getField
遇到getField
。 無恥的插件: IntelliJ似乎很好地處理具有反射的重構:編寫Minecraft mods以及我知道這種感覺,並且可以說IntelliJ顯着減少了重構工作。 但對於大多數現代IDE來說也是如此:我確信大型玩家Eclipse,Netbeans 等。 擁有良好實施的重構系統。
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;
}
如果該字段是私有的,您可以訪問它:
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.
如果您不知道該字段的名稱......那么..那么您希望得到什么字段? :)您可以使用反射獲取所有字段然后循環它們。但是如果您不知道該字段,此操作中的實際意義和邏輯是什么?
這只能通過反射來實現。
使用Class.getDeclaringFields
()和java.reflection.Field.getName()
我想這就是你要找的東西。
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;
}
如何使用lombok注釋@FieldNameConstants
然后您可以通過以下方式訪問您的字段名稱: mod.Field.linkTool
這樣我們就不需要維護獲取字段名稱的代碼(lombok 為我們做的),當我們刪除該字段時,編譯器會抱怨它的使用。
請注意,此功能被標記為實驗性的。
獲取字段名稱的動機是使用它來搜索鍵值數據庫中的內容(如mongodb)。 我有一個結構,其成員(字段)代表保存的數據。 我使用成員名稱來搜索數據庫 。
我的建議是為每個重要成員放置一個靜態getter。 例:
public class Data {
public static String getMember1Key() {
return "member1";
}
public String member1;
}
希望Java將來會有一些機制,因為現在,元數據可能是數據的一部分。 特別是在使用JSON時。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.