简体   繁体   English

Java 反射是不好的做法吗?

[英]Is Java Reflection bad practice?

Consider this piece of code:考虑这段代码:

public void doSearch(ActionEvent event) {
    String query = searchTextField.getText();
    if (query.isEmpty()) {
        data = FXCollections.observableArrayList(dc.getJobCoachRepo().getList());
        usersTableView.setItems(data);
    } else {

        String searchOn = "search" + searchChoiceBox.getValue();
        try {
            Method m = this.getClass().getMethod(searchOn, String.class);
            m.invoke(this, query);
        } catch (Exception e) {

        }
    }
}

public void searchFirstName(String query) {
    data = FXCollections.observableArrayList(dc.getJobCoachRepo().searchFirstName(query));
    usersTableView.setItems(data);

}
...
...

I'm using java reflection here to avoid an if construct.我在这里使用 java 反射来避免 if 构造。 The choicebox is used to let the user decide on what attribute he wants to search, there are 6 possibilities right now.选择框用于让用户决定他要搜索的属性,目前有 6 种可能性。 I've gotten some comments from other students that using reflection is 'bad practice'.我从其他学生那里得到了一些评论,认为使用反射是“不好的做法”。 Is this the case?是这样吗? Why?为什么?

There are many reasons this is bad practice. 造成这种情况的原因有很多。 Among them: 其中:

  1. It is not robust. 它不健壮。 The text that the user types in the text field has to match the name of a method, which implies a horrendous level of coupling between things that should not be related at all 用户在文本字段中键入的文本必须与方法的名称匹配,这意味着在根本不应该相关的事物之间存在可怕的耦合程度
  2. Reflection performs badly. 反思表现很糟糕。 Probably not a big deal here, but if there is no good reason to use reflection, you shouldn't. 这里可能没什么大不了的,但如果没有充分的理由使用反射,你就不应该这样做。
  3. There is a ready-made better solution using lambda expressions. 使用lambda表达式有一个现成的更好的解决方案。

Consider instead populating your combo box with Consumer<String> objects: 请考虑使用Consumer<String>对象填充组合框:

ComboBox<Consumer<String>> searchChoiceBox = new ComboBox<>();
searchChoiceBox.getItems().add(createSearchOption(this::searchFirstName, "First Name"));

// ...

private Consumer<String> createSearchOption(Consumer<String> search, String name) {
    return new Consumer<String>() {
        @Override
        public void accept(String s) {
            search.accept(s);
        }
        @Override
        public String toString() {
            return name ;
        }
    };
}

Then you just do: 那你就做:

public void doSearch(ActionEvent event) {
    String query = searchTextField.getText();
    if (query.isEmpty()) {
        data = FXCollections.observableArrayList(dc.getJobCoachRepo().getList());
        usersTableView.setItems(data);
    } else {

        searchChoiceBox.getValue().accept(query);

    }
}

Yes, reflection is slow, and it creates fragile code when used in this way. 是的,反射很慢,并且在以这种方式使用时会产生脆弱的代码。

If you want to avoid the if statement, you should use polymorphism. 如果要避免使用if语句,则应使用多态。 Create an interface Searcher with public void search(String query) , create implementations for every type of search you want to do, and then put an instance of each implementation as the value of a Map<String, Searcher> , keyed by the value of the search choice box. 使用public void search(String query)创建一个接口Searcher ,为您想要执行的每种类型的搜索创建实现,然后将每个实现的实例作为Map<String, Searcher>的值,键入值搜索选择框。

Because Java enums are objects, you could also use an enum as your map. 因为Java枚举是对象,所以您也可以使用枚举作为地图。 Each enum value would define their own search(string) implementation. 每个枚举值都将定义自己的search(string)实现。 You could then call the implementation you want using SearchEnumTypeName.valueOf(searchChoiceBox.getValue()).search(query) 然后,您可以使用SearchEnumTypeName.valueOf(searchChoiceBox.getValue()).search(query)调用所需的实现SearchEnumTypeName.valueOf(searchChoiceBox.getValue()).search(query)

Native Image creation本机图像创建

If the world of Ahead of Time Compilation with GraalVM interests you (which is receiving more interest in the world of microservices), I can tell you that reflection is the biggest barrier.如果你对使用 GraalVM 的Ahead of Time Compilation世界感兴趣(这对微服务世界越来越感兴趣),我可以告诉你反射是最大的障碍。 And in my opinion it's unnecessary.在我看来,这是不必要的。

You have to identify classes manually (via reflection.json) that the Java linker has to retain as it tries to reduce unused code bloating the binary.您必须手动(通过反射.json)识别 Java linker 必须保留的类,因为它试图减少未使用的代码使二进制文件膨胀。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM