当前位置: 首页 > 知识库问答 >
问题:

为什么java没有。场和。方法反射关键字,如。班

席乐童
2023-03-14

假设我们有这样一门课:

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

示例用例

我最近创建了一个名为EasyTableModel的类,它允许您定义自己的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 row类设置表的内容,而不必担心列索引

如果你认为这是对反射的滥用,那么你会认为很多像谷歌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);
}

如果你认为这个特性不会为有用的编程工具打开一个可能性的世界,你就缺乏想象力;)

共有3个答案

申屠宗清
2023-03-14

这目前是不可能的,并且很难用这些关键字来实现。

表情

SomeClass.class

被称为类文本并返回一个class对象。Java语言规范对此进行了描述。

假定

Field xField = A.x.field;

A是类型为Class的变量,这是没有意义的,因为Class类没有一个名为x的可见字段。

假设A是实际的类,同样没有意义,因为类A不一定有一个名为x静态字段。如果是这样,您将访问变量本身,而不是其相应的字段对象。

现在添加字段关键字到

A.x.field;

无法使用实例字段,因为无法从静态上下文访问它们。

同样的推理方法。

很多事情都需要改变<代码>。类可以与类/接口/枚举或原语的名称一起使用。什么是。字段。方法是否与一起使用?在我看来,这会破坏变量访问和方法调用的语法。

段干昊然
2023-03-14

以下是一些原因:

  1. 方法foIntmethod=A. foo(int). method;在语法上是不正确的
  2. Field xField=A.x.field;现在,在x类中不能有一个名为field的字段。如果人们的代码里已经有这个了呢?这将不向后兼容。
  3. 同样的事情适用于A. foo(). method。如果响应已经有一个名为method的字段,该怎么办?
贺宜修
2023-03-14

在Java中引入关键字是很困难的,但是您可以引入新的符号组合。例如,在Java8中,您可以编写

 MyClass::myMethod

要获得方法引用,这是Java 7中无法做到的。

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

你甚至可以写

 HashSet<String>::new

获取对构造函数ALAnewhashset的引用

可以使用MethodHandles将方法转换为MethodHandle。查找。取消反射(Method),您可以使用MethodHandles将构造函数转换为MethodHandle。查找。未反射构造函数(构造函数)

一旦有了MethodHandle,您就可以为它设置一个要调用的对象。

 类似资料:
  • 这样对吗?这就是它的初衷吗?

  • 问题内容: 什么是java反射,为什么有用? 问题答案: 名称反射用于描述能够检查同一系统(或本身)中其他代码的代码。 例如,假设你在Java中有一个未知类型的对象,并且你想在该对象上调用“ doSomething”方法(如果存在)。除非对象符合已知的接口,否则Java的静态类型化系统并不是真正为支持该类型而设计的,但是使用反射,你的代码可以查看该对象并确定其是否具有名为“ doSomething

  • 问题内容: 为什么没有用于同步/并发的关键字? 到目前为止,我的研究为我提供了一种解决方案,您包装了一些高级类并使用它们来处理并发。 给定一个纯Kotlin项目,如果需要一个小型的高度优化的组件来处理并发等,该怎么办? 我的印象是Kotlin是Java的辅助语言,可以用Kotlin编写90%的代码,但有一些Java语言无法用Kotlin表示。 这是正确的吗?这是原来的样子吗? 问题答案: Kotl

  • 为什么没有同步和并发的关键字? 到目前为止,我的研究给了我一个解决方案,你包装一些高级类,并用它们来处理并发。 给定一个纯Kotlin的项目,如果需要一个以线程安全方式处理并发的小型、高度优化的组件,应该怎么做? 我的印象是,Kotlin是Java的一种辅助语言,可以用Kotlin编写90%的代码,但有一些Java代码无法用Kotling表达。 这是对的吗?这就是它的目的吗?

  • 问题内容: 什么是反射,为什么有用? 我对Java特别感兴趣,但是我认为原理在任何语言中都是相同的。 问题答案: 名称反射用于描述能够检查同一系统(或本身)中的其他代码的代码。 例如,假设您在Java中有一个未知类型的对象,并且想在该对象上调用“ doSomething”方法(如果存在)。除非对象符合已知的接口,否则Java的静态类型化系统并不是真正为支持该类型而设计的,但是使用反射,您的代码可以

  • 问题内容: 当在方法参数上使用关键字时,我无法理解该关键字在哪里真正方便。 如果我们排除使用匿名类,可读性和意图声明,那么对我来说几乎毫无用处。 强制某些数据保持不变并不像看起来那样强大。 如果参数是原始参数,则它将无效,因为参数作为值传递给方法,并且在范围之外进行更改将无效。 如果我们通过引用传递参数,则引用本身就是一个局部变量,并且如果在方法内部更改了引用,则不会在方法范围之外产生任何影响。