有人建议我不要在这里使用反射...为什么不呢?

发布于 2024-12-27 07:58:31 字数 747 浏览 2 评论 0原文

该代码用于对列表进行排序。该列表可以包含数千个元素,但少于 10k。

protected <E> int compareFields(E o1, E o2, String fieldName){
    try { 
        Comparable o1Data = (Comparable) o1.getClass().getMethod(fieldName).invoke(o1);
        Comparable o2Data = (Comparable) o2.getClass().getMethod(fieldName).invoke(o2);
        return o1Data == null ? o2Data == null ? 0 : 1 :
               o2Data == null ? -1 : o1Data.compareTo(o2Data);
    } catch(Exception e) {
        throw new RuntimeException(e);
    }
}

我被建议

“请不要将反射用于此类事情!! 要么为该方法提供合适的比较器,要么为该方法提供提取相关属性的方法(可能以原始类型不支持的方式计算),或两者兼而有之。”

兼而有之。”最好提供一个更好的方法

示例 。 : 我有很多带有数据表的屏幕。每个都是从列表构建的。每个数据表都需要可按其 6 列中的每一列进行排序。这些列是日期或字符串。

This code is used to sort a List. The list could contain in the thousands of elements but less than 10k.

protected <E> int compareFields(E o1, E o2, String fieldName){
    try { 
        Comparable o1Data = (Comparable) o1.getClass().getMethod(fieldName).invoke(o1);
        Comparable o2Data = (Comparable) o2.getClass().getMethod(fieldName).invoke(o2);
        return o1Data == null ? o2Data == null ? 0 : 1 :
               o2Data == null ? -1 : o1Data.compareTo(o2Data);
    } catch(Exception e) {
        throw new RuntimeException(e);
    }
}

I was advised to

"Please don't use reflection for things like this!!
Either supply the method with a suitable Comparator, or a method to extract the relevant property (may be computed in a way not supported by the original type), or both."

An example of a better way to do this would be nice.

Context:
I've got many screens with data tables. Each one is build from a List. Each data table needs to be sortable by each of its 6 columns. The columns are either Date or String.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

焚却相思 2025-01-03 07:58:32

在没有上下文的情况下很难给出一个好的例子,所以现在这里列出了为什么它不是最好的想法:

  1. 提供的字段不能保证可比较(不确定为什么这里的代码需要捕获该异常并重新命名它) 。
  2. 如果提供的对象类型不打算以这种方式进行比较怎么办? (这是一个过于通用的方法名称,无法知道它应该如何使用)。
  3. 它不是强类型的。以字符串形式提供字段名称意味着每当属性名称发生更改时,您都必须更改代码,并且很难找到需要进行这些更改的位置。
  4. 反射可能比以强类型方式实现要慢。

It's hard to give a good example without context, so for now here's a small list of why it's not the best idea:

  1. The field provided has no guarantee of being Comparable (not sure why the code here needs to catch that exception and rebrand it).
  2. What if the type of objects provided are not meant to be compared in this way? (It's an overly generic method name to know how it's supposed to be used).
  3. It's not strongly typed. Providing the field name as a string means you'll have to change your code everywhere whenever the property name changes, and it'll be hard to track down where you need to make those changes.
  4. Reflection is potentially slower than if implemented in a strongly typed manner.
梦行七里 2025-01-03 07:58:32

其他答案很好地描述了为什么不建议使用反射。我想添加一个使用更传统解决方案的示例。

您不应指定用于比较两个对象的字段,而应采用 Comparator 实例作为参数。这样使用此方法的客户端可以指定如何比较两个对象。

protected <E> int compareFields(E o1, E o2, Comparator<E> comparator) {
    return comparator.compare(o1, o2);
}

对此函数的调用示例如下所示:

MyClass a = ...;
MyClass b = ...;
Comparator<MyClass> intFieldComparator = new Comparator<MyClass> {
    public int compare(MyClass o1, MyClass o2) {
        int field1 = o1.getIntField();
        int field2 = o2.getIntField();

        return field2 - field1;
    }
};

compareFields(a, b, intFieldComparator);

如果要使用多个字段比较对象,则可以定义不同的比较器。

The other answers described well why it is not advised to use reflection. I want to add an example using a more conventional solution.

Instead of specifying the field that is used to compare the two objects, you should take a Comparator instance as an argument. This way the client who uses this method can specify how to compare the two objects.

protected <E> int compareFields(E o1, E o2, Comparator<E> comparator) {
    return comparator.compare(o1, o2);
}

And an example call to this function would look like this:

MyClass a = ...;
MyClass b = ...;
Comparator<MyClass> intFieldComparator = new Comparator<MyClass> {
    public int compare(MyClass o1, MyClass o2) {
        int field1 = o1.getIntField();
        int field2 = o2.getIntField();

        return field2 - field1;
    }
};

compareFields(a, b, intFieldComparator);

You can define different comparators if you want to compare the objects using several fields.

画中仙 2025-01-03 07:58:31

此处使用反射可能会慢得多,因为您通过使用 getClassgetMethodinvoke 向每次比较添加堆栈帧数,而不是使用对象的本机比较方法。

理想情况下,您应该编写方法以避免在签名中使用object。 “合适的比较器”至少会强烈绑定到对象的类型(您假设它们是相同的)。如果您必须进行动态字段比较(如图所示),那么至少可以将反射封装在该比较器中。

但是,如果您要调用此数千次,最好将比较器预先绑定到您要排序的字段。这样,您只需预先调用 getMethod 一次,而不是为每个单独的比较调用一次。

Using reflection here will potentially be much slower, as you are adding number of stack frames to each comparison by using getClass, getMethod and invoke rather than using the objects' native compare method.

Ideally, you would write the method to avoid the use of object in the signature. A "suitable Comparator" would at least be strongly bound to the objects' type (which you assume are the same). If you must have dynamic field comparison (as it appears), then at least the reflection could be encapsulated in that comparator.

If you are going to call this thousands of times, though, it would be best to pre-bind a Comparator to the field you are sorting by. This way, you only call getMethod once up front, rather than once for each individual comparison.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文