gpt4 book ai didi

java - 为什么java没有.class之类的.field和.method反射关键字?

转载 作者:搜寻专家 更新时间:2023-10-31 19:33:27 25 4
gpt4 key购买 nike

假设我们有这个类:

public abstract class A {
int x;
public int foo();
public int foo(int x);
}

众所周知,A.classClass.forName("A") 相比有一个明显的优势:如果 的名称仍然有效A 通过重构或混淆改变。

但是,没有办法用字段和方法来获得这个优势。你有没有希望你能做到这一点:(在下面的编辑中看到一个更好的建议语法!)

Field xField = A.x.field;
Method fooMethod = A.foo().method;
Method fooIntMethod = A.foo(int).method;

而不是这个?

Field xField = A.getField("x");
Method fooMethod = A.getMethod("foo");
Method fooIntMethod = A.getMethod("foo", int.class);

所以这是我的问题:有谁知道这个功能是否已经计划或讨论过,或者 Sun/Oracle 是否出于某种原因特别决定反对它?

编辑: 这个语法怎么样?它避免了人们提到的问题:

Field xField = A..x;
Method fooMethod = A..foo();
Method fooIntMethod = A..foo(int);

示例用例

我最近创建了一个名为 EasyTableModelAbstractTableModel 类,它允许您定义自己的 POJO 行类型。它的getValueAt(...)setValueAt(...) 等使用反射来获取/设置POJO 中字段的值。

public class EasyTableModel<T> extends AbstractTableModel {
private RowFormat<T> prototypeFormat;

private final ArrayList<T> rows = new ArrayList<T>();

...

public static interface RowFormat<T> {
Object getValueAt(T row, int columnIndex);

void setValueAt(T row, Object value, int columnIndex);

...
}

...

public static class ReflectionRowFormat<T> implements RowFormat<T> {
private Field[] fields;

...

public Object getValueAt(T row, int column) {
try {
return fields[column].get(row);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

public void setValueAt(T row, Object value, Field field) {
if (!field.getDeclaringClass().isInstance(this)) {
throw new IllegalArgumentException("field is not a member of this class");
}
setValueAt(row, value, getColumnIndex(field));
}

...
}

...

@Override
public Object getValueAt(int rowIndex, int columnIndex) {
return getRowFormat(rowIndex).getValueAt(rows.get(rowIndex), columnIndex);
}

@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
getRowFormat(rowIndex).setValueAt(rows.get(rowIndex), aValue, columnIndex);
fireTableRowsUpdated(rowIndex, rowIndex);
}

public void fireTableCellUpdated(T row, String columnName) {
fireTableCellUpdated(row, indexOfColumn(columnName));
}

public void fireTableCellUpdated(T row, Field field) {
fireTableCellUpdated(row, indexOfColumn(field));
}
}

使用这个基类,创建你的表非常容易:

public abstract class QuoteMonitorTableModel<R extends QuoteMonitorTableModel<R>.Row> extends EasyTableModel<R> {
...

protected static final String NUM_QUOTES_RECEIVED = "# Quotes Received";
protected static final String LAST_QUOTE_TIME = "Last Quote Time";

public class Row {
public Row() {

}

@ColumnName(NUM_QUOTES_RECEIVED)
private Integer numQuotesReceived;

@ColumnName(LAST_QUOTE_TIME)
private Long lastQuoteTimeMillis;

public Integer getNumQuotesReceived() {
return numQuotesReceived;
}

public void setNumQuotesReceived(Integer numQuotesReceived) {
this.numQuotesReceived = numQuotesReceived;
fireTableCellUpdated((R) this, NUM_QUOTES_RECEIVED);
}

public Long getLastQuoteTimeMillis() {
return lastQuoteTimeMillis;
}

public void setLastQuoteTimeMillis(Long lastQuoteTimeMillis) {
this.lastQuoteTimeMillis = lastQuoteTimeMillis;
fireTableCellUpdated((R) this, LAST_QUOTE_TIME);
}
}
}

这一切有什么好处?

  • 您可以通过自己的 POJO 行类设置表的内容,而无需不必担心列索引
  • 使用您自己的 POJO 行类来设置值是类型安全的,这与 getValueAt(...)setValueAt(...)
  • 不同
  • 您可以使用一些预先存在的 POJO 类为行格式轻松创建一个表

如果您认为这是对反射的滥用,那么您会认为许多使用良好的库(例如 Google GSON)也是对反射的滥用。

现在,请注意派生类如何指示在通过字符串而不是字段触发事件时哪个字段已更改:

    public void setNumQuotesReceived(Integer numQuotesReceived) {
this.numQuotesReceived = numQuotesReceived;
fireTableCellUpdated((R) this, NUM_QUOTES_RECEIVED);
}

如果我们可以只使用字段就好了。但是用 getDeclaredField() 做这件事会很糟糕:

public void setNumQuotesReceived(Integer numQuotesReceived) {
this.numQuotesReceived = numQuotesReceived;
try {
// what if obfuscation changes the name of the numQuotesReceived field?
fireTableCellUpdated((R) this, getClass().getDeclaredField("numQuotesReceived"));
} catch (NoSuchFieldException e) {
}
}

但是,使用我提出的功能,它会像蛋糕一样简单:

public void setNumQuotesReceived(Integer numQuotesReceived) {
this.numQuotesReceived = numQuotesReceived;
// if obfuscation changes the name of the numQuotesReceived it will
// not break the compiled form of this code
fireTableCellUpdated((R) this, QuoteMonitorTableModel..numQuotesReceived);
}

如果您认为此功能不会为有用的编程工具打开一个充满可能性的世界,那您就缺乏想象力;)

最佳答案

在 Java 中引入关键字会很困难,但是您可以引入新的符号组合。例如在 Java 8 中你可以这样写

 MyClass::myMethod

获取Method Reference ,这是您在 Java 7 中无法做到的。

您可以对字段执行类似的操作,并且有人建议支持属性引用。

你甚至可以写

 HashSet<String>::new

获取对构造函数 ALA 的引用 new HashSet<String>()

您可以使用 MethodHandles.Lookup.unreflect(Method) 将 Method 转换为 MethodHandle您可以使用 MethodHandles.Lookup.unreflectConstructor(Constructor) 将 Constructor 转换为 MethodHandle

一旦您有了 MethodHandle,您就可以设置一个对象供其调用。

关于java - 为什么java没有.class之类的.field和.method反射关键字?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21738363/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com