An Introduction to Refactoring with IntelliJ IDEA – 使用IntelliJ IDEA进行重构的介绍

最后修改: 2019年 4月 3日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Keeping the code tidy is not always easy. Fortunately for us, our IDEs are pretty smart nowadays and can help us in achieving this. In this tutorial, we’re going to focus on IntelliJ IDEA, the JetBrains Java code editor.

保持代码的整洁并不总是容易的。幸运的是,现在我们的IDE相当聪明,可以帮助我们实现这个目标。在本教程中,我们将重点介绍IntelliJ IDEA,即JetBrains的Java代码编辑器。

We’ll see a few features offered by the editor to refactor code, from renaming variables to changing a method signature.

我们将看到编辑器提供的一些功能,以重构代码,从重命名变量到改变方法签名。

2. Renaming

2.重新命名

2.1. Basic Renaming

2.1.基本重命名

First, let’s start with the basics: renaming. IntelliJ offers us the possibility to rename different elements of our code: types, variables, methods, and even packages.

首先,让我们从基础知识开始。重命名IntelliJ为我们提供了重命名代码中不同元素的可能性:类型、变量、方法,甚至是包。

To rename an element, we need to follow these steps:

要重命名一个元素,我们需要遵循这些步骤。

  • Right-click the element
  • Trigger the Refactor > Rename option
  • Type the new element name
  • Press Enter

By the way, we can replace the first two steps by selecting the element and pressing Shift + F6.

顺便说一下,我们可以通过选择元素并按Shift + F6来取代前两个步骤。

When triggered, the renaming action will search across the code for every usage of the element and then change them with the provided value.

当被触发时,重命名动作将在整个代码中搜索该元素的每个用法,然后用所提供的值改变它们

Let’s imagine a SimpleClass class with a poorly named addition method, someAdditionMethod, called in the main method:

让我们想象一个SimpleClass类,它有一个名字很差的加法方法,someAdditionMethod,在main方法中被调用。

public class SimpleClass {
    public static void main(String[] args) {
        new SimpleClass().someAdditionMethod(1, 2);
    }

    public int someAdditionMethod(int a, int b) {
        return a + b;
    }
}

Thus, if we choose to rename this method into add, IntelliJ will produce the following code:

因此,如果我们选择将这个方法重命名为add,IntelliJ将产生以下代码。

public class SimpleClass() {
    public static void main(String[] args) {
        new SimpleClass().add(1, 2);
    }

    public int add(int a, int b) {
        return a + b;
    }
}

2.2. Advanced Renaming

2.2.高级重命名

However, IntelliJ does more than searching for code usages of our elements and rename them. As a matter of fact, a few more options are available. IntelliJ can also search for occurrences in comments and strings, and even in files that don’t contain source code. As for parameters, it can rename them in the class hierarchy in case of overridden methods.

然而,IntelliJ所做的不仅仅是搜索我们元素的代码使用情况和重命名它们。事实上,还有一些选项可用。IntelliJ 还可以搜索注释和字符串中的出现,甚至是不包含源代码的文件中的出现。至于参数,如果是重载方法,它可以在类的层次结构中重命名它们。

Those options are available by hitting Shift + F6 once more before renaming our element and a popup will appear:

这些选项可以在重命名我们的元素之前再敲一次Shift + F6,就会出现一个弹出窗口。

renaming

The Search in comments and strings option is available for any renaming. As for the Search for text occurrences option, it’s not available for method parameters and local variables. Finally, the Rename parameters in hierarchy option is available for method parameters only.

在注释和字符串中搜索选项可用于任何重命名。至于搜索文本出现次数选项,它不适用于方法参数和局部变量。最后,在层次结构中重命名参数选项只适用于方法参数。

So, if any match is found with one of those two options, IntelliJ will show them and offer us the possibility to opt out of some of the changes (say, in case it matches something unrelated with our renaming).

因此,如果发现与这两个选项之一相匹配,IntelliJ将显示它们,并为我们提供选择退出一些变化的可能性(例如,如果它与我们的重命名不相关的东西相匹配)。

Let’s add some Javadoc to our method, and then rename its first parameter, a:

让我们给我们的方法添加一些Javadoc,然后重新命名它的第一个参数,a

/**
  * Adds a and b
  * @param a the first number
  * @param b the second number
  */
public int add(int a, int b) {...}

By checking the first option in the confirmation pop-up, IntelliJ matches any mention of the parameters in the Javadoc comment of the method and offers to rename them as well:

通过勾选确认弹出窗口中的第一个选项,IntelliJ会匹配方法的Javadoc注释中提到的任何参数,并提供对它们的重命名。

/**
  * Adds firstNumber and b
  * @param firstNumber the first number
  * @param b the second number
  */
public int add(int firstNumber, int b) {...}

Finally, we must note that IntelliJ is smart and searches mostly for usages in the scope of the renamed element. In our case, that would mean that a comment situated outside the method (except for the Javadoc) and containing a mention to a would not have been considered for renaming.

最后,我们必须注意到,IntelliJ是很聪明的,它主要搜索重命名元素范围内的使用。在我们的案例中,这将意味着一个位于方法之外(除了Javadoc)并包含提及a的注释将不会被考虑重命名。

3. Extracting

3.提取

Now, let’s talk about extraction. Extraction enables us to grab a piece of code and put it into a variable, a method or even a class. IntelliJ handles this pretty smartly as it searches for similar pieces of code and offers to extract them in the same way.

现在,让我们来谈谈提取的问题。提取使我们能够抓取一段代码,并将其放入一个变量、一个方法甚至一个类中。IntelliJ相当聪明地处理了这一点,因为它搜索了类似的代码片断,并提供了以相同方式提取它们。

So, in this section, we’ll learn how to leverage the extraction feature offered by IntelliJ.

因此,在本节中,我们将学习如何利用IntelliJ提供的提取功能。

3.1. Variables

3.1. 变量

First, let’s start with variables extraction. That means local variables, parameters, fields, and constants. To extract a variable, we must follow these steps:

首先,让我们从提取变量开始。这意味着局部变量、参数、字段和常量。要提取一个变量,我们必须遵循这些步骤。

  • Select an expression that fits in a variable
  • Right-click the selected area
  • Trigger the Refactor > Extract > Variable/Parameter/Field/Constant option
  • Choose between the Replace this occurrence only or Replace all x occurrences options, if proposed
  • Enter a name for the extracted expression (if the chosen one doesn’t suit us)
  • Press Enter

As for renaming, it’s possible to use keyboard shortcuts instead of using the menu. The default shortcuts are, respectively, Ctrl + Alt + V, Ctrl + Alt + P, Ctrl + Alt + F and Ctrl + Alt + C.

至于重命名,可以使用键盘快捷键而不是使用菜单。默认的快捷键分别是:Ctrl + Alt + V, Ctrl + Alt + P, Ctrl + Alt + FCtrl + Alt + C

IntelliJ will try to guess a name for our extracted expression, based on what the expression returns. If it doesn’t match our needs, we’re free to change it before confirming the extraction.

IntelliJ 将根据表达式返回的内容,尝试为我们提取的表达式猜一个名字。如果它不符合我们的需要,我们可以在确认提取之前自由地改变它。

Let’s illustrate with an example. We could imagine adding a method to our SimpleClass class telling us if the current date is between two given dates:

让我们用一个例子来说明。我们可以想象在我们的SimpleClass类中添加一个方法,告诉我们当前日期是否在两个给定日期之间。

public static boolean isNowBetween(LocalDate startingDate, LocalDate endingDate) {
    return LocalDate.now().isAfter(startingDate) && LocalDate.now().isBefore(endingDate);
}

Let’s say we want to change our implementation because we use LocalDate.now() twice and we would like to make sure it has the exact same value in both evaluations. Let’s just select the expression and extract it in a local variable, now:

假设我们想改变我们的实现,因为我们使用了LocalDate.now()两次,我们想确保它在两次评估中的值完全相同。让我们选择表达式并将其提取到一个局部变量中,now:

extract local variable

Then, our LocalDate.now() call is captured in a local variable:

然后,我们的LocalDate.now()调用被捕获在一个本地变量中。

public static boolean isNowBetween(LocalDate startingDate, LocalDate endingDate) {
    LocalDate now = LocalDate.now();
    return now.isAfter(startingDate) && now.isBefore(endingDate);
}

By checking the Replace all option, we made sure that both expressions have been replaced at once.

通过检查Replace all选项,我们确保两个表达式都被一次性替换。

3.2. Methods

3.2.方法

Let’s now check how to extract methods using IntelliJ:

现在让我们看看如何使用IntelliJ提取方法。

  • Select the expression or lines of code fitting the method we want to create
  • Right-click the selected area
  • Trigger the Refactor > Extract > Method option
  • Type in the method information: its name, its visibility and its parameters
  • Press Enter

Hitting Ctrl + Alt + M after selecting the method body works as well.

在选择方法主体后,点击Ctrl + Alt + M也可以。

Let’s reuse our previous example and say we want to have a method checking if any date is between to other dates. Then, we would just have to select our last line in the isNowBetween method and trigger the method extraction feature.

让我们重新使用我们之前的例子,假设我们想有一个方法来检查任何日期是否在其他日期之间。那么,我们只需要在isNowBetween方法中选择最后一行,并触发方法提取功能。

In the opened dialog, we can see that IntelliJ has already spotted the three needed parameters: startingDate, endingDate and now. As we want this method to be as generic as possible, we rename the now parameter into date. And for cohesion purposes, we place it as the first parameter.

在打开的对话框中,我们可以看到IntelliJ已经发现了三个需要的参数。startingDate, endingDatenow。由于我们希望这个方法尽可能的通用,我们把now参数重命名为date。为了凝聚力量,我们把它作为第一个参数。

Finally, we give our method a name, isDateBetween, and finalize the extraction process:

最后,我们给我们的方法起一个名字,isDateBetween,并最终完成提取过程。

extract method

We would then obtain the following code:

然后我们将得到以下代码。

public static boolean isNowBetween(LocalDate startingDate, LocalDate endingDate) {
    LocalDate now = LocalDate.now();
    return isDateBetween(now, startingDate, endingDate);
}

private static boolean isDateBetween(LocalDate date, LocalDate startingDate, LocalDate endingDate) {
    return date.isBefore(endingDate) && date.isAfter(startingDate);
}

As we can see, the action triggered the creation of the new isDateBetween method, which is also called in the isNowBetween method. The method is private, by default. Of course, this could have been changed using the visibility option.

我们可以看到,这个动作触发了新的isDateBetween方法的创建,这个方法也被isNowBetween方法调用。默认情况下,该方法是私有的。当然,这可以通过可见性选项来改变。

3.3. Classes

3.3.类别

After all that, we might want to get our date-related methods in a specific class, focused on dates management, let’s say: DateUtils. Again, this is pretty easy:

在所有这些之后,我们可能想在一个特定的类中获得我们的日期相关方法,专注于日期管理,比方说。DateUtils。同样,这也很容易。

  • Right-click in the class that has our elements we want to move
  • Trigger the Refactor > Extract > Delegate option
  • Type in the class information: its name, its package, the elements to delegate, the visibility of those elements
  • Press Enter

By default, no keyboard shortcut is available for this feature.

默认情况下,该功能没有键盘快捷方式。

Let’s say, before triggering the feature, that we call our date-related methods in the main method:

比方说,在触发功能之前,我们在main方法中调用我们的日期相关方法。

isNowBetween(LocalDate.MIN, LocalDate.MAX);
isDateBetween(LocalDate.of(2019, 1, 1), LocalDate.MIN, LocalDate.MAX);

Then we delegate those two methods to a DateUtils class using the delegate option:

然后我们使用委托选项将这两个方法委托给一个DateUtils类。

delegate

Trigger the feature would produce the following code:

触发该功能将产生以下代码。

public class DateUtils {
    public static boolean isNowBetween(LocalDate startingDate, LocalDate endingDate) {
        LocalDate now = LocalDate.now();
        return isDateBetween(now, startingDate, endingDate);
    }

    public static boolean isDateBetween(LocalDate date, LocalDate startingDate, LocalDate endingDate) {
        return date.isBefore(endingDate) && date.isAfter(startingDate);
    }
}

We can see that the isDateBetween method has been made public. That is the result of the visibility option, that is set to escalate by default. Escalate means that visibility will be changed in order to ensure current calls to the delegated elements are still compiling.

我们可以看到,isDateBetween方法已经被变成public。这是可见性选项的结果,该选项默认设置为escalateEscalate意味着可见性将被改变,以确保当前对委托元素的调用仍在编译。

In our case, isDateBetween is used in the main method of SimpleClass:

在我们的案例中,isDateBetween被用于SimpleClass的mainmethod:

DateUtils.isNowBetween(LocalDate.MIN, LocalDate.MAX);
DateUtils.isDateBetween(LocalDate.of(2019, 1, 1), LocalDate.MIN, LocalDate.MAX);

Thus, when moving the method it’s necessary to make it not private.

因此,在移动该方法时,有必要使其成为非私有的。

However, it’s possible to give specific visibility to our elements by selecting the other options.

然而,通过选择其他选项,可以给我们的元素以特定的可见性。

4. Inlining

4.内衬

Now that we covered extraction, let’s talk about its counterpart: inlining. Inlining is all about taking a code element and replace it with what it’s made of. For a variable, this would be the expression it has been assigned. For a method, it would be its body.Earlier, we saw how to create a new class and delegate some of our code elements to it. But there are times we might want to delegate a method to an existing class. That’s what this section is about.

现在我们已经涵盖了提取,让我们来谈谈它的对应部分。内联内联是指将一个代码元素替换成它的内容。对于一个变量来说,这将是它被分配的表达式。早些时候,我们看到了如何创建一个新的类并将一些代码元素委托给它。但有时我们可能想将一个方法委托给一个现有的类。这就是本节的内容。

In order to inline an element, we must right-click this element – either its definition or a reference to it – and trigger the Refactor > Inline option. We can also achieve this by selecting the element and hitting the Ctrl + Alt + N keys.

为了内联一个元素,我们必须右击这个元素–无论是它的定义还是它的引用–并触发Refactor > Inline选项。我们也可以通过选择该元素并点击Ctrl + Alt + N 键来实现。

At this point, IntelliJ will offer us multiple options, whether we wish to inline a variable or a method, whether we selected a definition or a reference. These options are:

在这一点上,IntelliJ将为我们提供多个选项,无论我们希望内联一个变量还是一个方法,无论我们选择一个定义还是一个引用。这些选项是:。

  • Inline all the references and remove the element
  • Inline all the references, but keep the element
  • Only inline the selected reference and keep the element

Let’s take our isNowBetween method and get rid of the now variable, which now seems a bit overkill:

让我们采取我们的isNowBetween方法,去掉now变量,现在看来有点多此一举。

inline local variable

By inlining this variable, we would obtain the following result:

通过内联这个变量,我们将得到以下结果。

public static boolean isNowBetween(LocalDate startingDate, LocalDate endingDate) {
    return isDateBetween(LocalDate.now(), startingDate, endingDate);
}

In our case, the only option was to remove all the references and remove the element. But let’s imagine we also want to get rid of the isDateBetween call and choose to inline it. Then, IntelliJ would offer us the three possibilities we spoke about before:

在我们的案例中,唯一的选择是删除所有的引用并删除该元素。但让我们想象一下,我们也想摆脱isDateBetween调用,并选择内联它。然后,IntelliJ会给我们提供我们之前谈到的三种可能性。

extract method 1

Choosing the first one would replace all calls with the method body and delete the method. As for the second one, it would replace all calls with the method body but keep the method. And finally, the last one would only replace the current call with the method body:

选择第一种将用方法主体替换所有的调用,并删除该方法。至于第二种,它将用方法主体替换所有的调用,但保留方法。最后,最后一个将只用方法主体来替换当前的调用

public class DateUtils {
    public static boolean isNowBetween(LocalDate startingDate, LocalDate endingDate) {
        LocalDate date = LocalDate.now();
        return date.isBefore(endingDate) && date.isAfter(startingDate);
    }

    public static boolean isDateBetween(LocalDate date, LocalDate startingDate, LocalDate endingDate) {
        return date.isBefore(endingDate) && date.isAfter(startingDate);
    }
}

Our main method in the SimpleClass remains untouched as well.

我们在SimpleClass中的main方法也保持不动。

5. Moving

5.搬家

Earlier, we saw how to create a new class and delegate some of our code elements to it. But there are times we might want to delegate a method to an existing class. That’s what this section is about.

早些时候,我们看到了如何创建一个新的类并将我们的一些代码元素委托给它。但有些时候,我们可能想要将一个方法委托给一个现有的类。这就是本节的内容。

In order to move an element, we must follow these steps:

为了移动一个元素,我们必须遵循这些步骤。

  • Select the element to move
  • Right-click the element
  • Trigger the Refactor > Move option
  • Choose the recipient class and the method visibility
  • Press Enter

We can also achieve this by pressing F6 after selecting the element.

我们也可以通过在选择元素后按F6来实现。

Let’s say we add a new method to our SimpleClass, isDateOutstide(), that will tell us if a date is situated outside an interval of dates:

假设我们为SimpleClass添加一个新的方法,isDateOutstide(),它将告诉我们一个日期是否位于一个日期区间之外。

public static boolean isDateOutside(LocalDate date, LocalDate startingDate, LocalDate endingDate) {
    return !DateUtils.isDateBetween(date, startingDate, endingDate);
}

We then realize that its place should be in our DateUtils class. So we decide to move it:

然后我们意识到,它的位置应该在我们的DateUtils类中。所以我们决定移动它。

move method

Our method is now in the DateUtils class. We can see that the reference to DateUtils inside the method has disappeared as it’s no longer needed:

我们的方法现在是在DateUtils类中。我们可以看到,方法中对DateUtils的引用已经消失了,因为它不再需要了。

public static boolean isDateOutside(LocalDate date, LocalDate startingDate, LocalDate endingDate) {
    return !isDateBetween(date, startingDate, endingDate);
}

The example we just did works well as it concerns a static method. However, in the case of an instance method, things are not so straight-forward.

我们刚才的例子很有效,因为它涉及一个静态方法。然而,在实例方法的情况下,事情就不那么简单了。

If we want to move an instance method, IntelliJ will search for classes referenced in the fields of the current class and offer to move the method to one of those classes (provided they are ours to modify).

如果我们想移动一个实例方法IntelliJ将搜索在当前类的字段中引用的类,并提供将该方法移动到这些类中的一个(只要它们是我们可以修改的)。

If no modifiable class is referenced in the fields, then IntelliJ proposes making the method static before moving it.

如果在字段中没有引用可修改的类,那么IntelliJ建议在移动该方法之前使其成为静态

6. Changing a Method Signature

6.改变一个方法的签名

Finally, we’ll talk about a feature allowing us to change a method signature. The purpose of this feature is to manipulate every aspect of a method signature.

最后,我们将讨论一个允许我们改变方法签名的功能。该功能的目的是为了操作方法签名的每一个方面。

As usual, we must go through a few steps to trigger the feature:

像往常一样,我们必须通过几个步骤来触发该功能。

  • Select the method to change
  • Right-click the method
  • Trigger the Refactor > Change signature option
  • Bring changes to the method signature
  • Press Enter

If we prefer to use keyboards shortcut, it’s possible to use Ctrl + F6 as well.

如果我们喜欢使用键盘快捷方式,也可以使用Ctrl + F6

This feature will open a dialog very similar to the method extraction feature. And so we have the same possibilities that when we extract a method: changing its name, its visibility and also adding/removing parameters and fine-tuning them.

这个功能将打开一个与方法提取功能非常相似的对话框。因此,我们拥有与提取方法时相同的可能性:改变其名称、可见性以及添加/删除参数并对其进行微调。

Let’s imagine we want to change our implementation of isDateBetween to either consider the date bounds as inclusive or exclusive. In order to do that we want to add a boolean parameter to our method:

让我们设想一下,我们想改变isDateBetween的实现,将日期界线视为包容或排斥。为了做到这一点,我们要给我们的方法添加一个boolean参数。

change signature

By changing the method signature we can add this parameter, name it and give it a default value:

通过改变方法签名,我们可以添加这个参数,为其命名,并给它一个默认值。

public static boolean isDateBetween(LocalDate date, LocalDate startingDate,
   LocalDate endingDate, boolean inclusive) {
    return date.isBefore(endingDate) && date.isAfter(startingDate);
}

After that, we just have to adapt the method body according to our needs.

之后,我们只需根据自己的需要来调整方法体。

If we wanted, we could have checked the Delegate via overloading method option in order to create another method with the parameter instead of modifying the current one.

如果我们愿意,我们可以选中通过重载方法授权选项,以便用参数创建另一个方法,而不是修改当前方法。

7. Pull Up & Push Down

7.拉起和推下

Our Java code typically has class hierarchies – derived classes extend a base class.

我们的Java代码通常有类的层次结构–派生类扩展基类

Sometimes we want to move members (methods, fields, and constants) between these classes. That is where the last refactoring comes in handy: it allows us to pull up members from a derived class into the base class or push them down from a base class into each derived class.

有时我们想在这些类之间移动成员(方法、字段和常量)。这就是最后一个重构的用武之地:它允许我们将成员从派生类中拉升到基类中,或者将它们从基类中推下到每个派生类中

7.1. Pull Up

7.1 拉升

First, let’s pull up a method to the base class:

首先,让我们把一个方法拉到基类。

  • Select a member of a derived class to pull up
  • Right-click the member
  • Trigger the Refactor > Pull Members Up… option
  • Push the Refactor button

By default, no keyboard shortcut is available for this feature.

默认情况下,该功能没有键盘快捷方式。

Let’s say we have a derived class called Derived. It uses a private doubleValue() method:

假设我们有一个名为Derived的派生类。它使用一个私有的doubleValue()方法。

public class Derived extends Base {

    public static void main(String[] args) {
        Derived subject = new Derived();
        System.out.println("Doubling 21. Result: " + subject.doubleValue(21));
    }

    private int doubleValue(int number) {
        return number + number;
    }
}

The base class Base is empty.

基类Base是空的。

So, what happens when we pull up doubleValue() into Base?

那么,当我们把doubleValue()拉到Base时会发生什么?

Refactoring with IntelliJ IDEA Pull Up

Refactoring with IntelliJ IDEA Pull Up

Two things happen to doubleValue() when we push “Refactor” in the above dialog:

当我们在上述对话框中按下 “重构 “时,doubleValue()会发生两件事。

  • it moves to the Base class
  • its visibility changes from private to protected so that the Derived class can still use it

The Base class afterward now has the method:

之后的Base类现在有了这个方法。

public class Base {
    protected int doubleValue(int number) {
        return number + number;
    }
}

The dialog for pulling up members (pictured above) gives us some more options:

拉出成员的对话框(如上图)为我们提供了一些更多的选择。

  • we can select other members and pull them up all at once
  • we can preview our changes with the “Preview” button
  • only methods have a checkbox in the “Make abstract” column. If checked, this option will give the base class an abstract method definition during the pull-up. The actual method will remain in the derived class but gain an @Override annotation. Consequently, other derived classes won’t compile anymore then because they’re missing implementation of that new, abstract base method

7.2. Push Down

7.2.下推

Lastly, let’s push down a member to the derived class. This is the opposite of the pulling up we just performed:

最后,让我们把推倒一个成员到派生类中。这与我们刚刚进行的上拉相反。

  • Select a member of a base class to push down
  • Right-click the member
  • Trigger the Refactor > Push Members Down… option
  • Push the Refactor button

As with pulling members up, no keyboard shortcut is available for this feature by default.

与拉升成员一样,默认情况下,该功能没有键盘快捷键可用。

Let’s push down the method again that we just pulled up. The Base class looked like this at the end of the previous section:

让我们再把刚才拉上来的方法推下去。在上一节的最后,Base类看起来是这样的。

public class Base {
    protected int doubleValue(int number) {
        return number + number;
    }
}

Now, let’s push doubleValue() down to the Derived class:

现在,让我们把doubleValue()下推到Derived类。

Refactoring with IntelliJ IDEA Push Down

This is the Derived class after pushing “Refactor” in the above dialog. The doubleValue() method is back:

这是在上述对话框中按下 “重构 “后的Derived类。doubleValue()方法回来了。

public class Derived extends Base {
    private int theField = 5;

    public static void main(String[] args) {
        Derived subject = new Derived();
        System.out.println( "Doubling 21. Result: " + subject.doubleValue(21));
    }

    protected int doubleValue(int number) {
        return number + number;
    }
}

Now both the Base class and the Derived class are back to where they started in the previous “Pull Up” section. Nearly, that is – doubleValue() kept the protected visibility it had in Base (it was private originally).

现在,Base类和Derived类都回到了它们在上一节 “拉升 “中的起点。差不多,也就是–doubleValue()保持了它在Base中的protected可见性(它最初是private)。

IntelliJ 2019.3.4 actually brings up a warning when pushing down doubleValue(): “Pushed members will not be visible from certain call sites”. But as we can see in the Derived class above, doubleValue() is visible indeed to the main() method.

IntelliJ 2019.3.4实际上在推倒doubleValue()时提出了一个警告:”推倒的成员在某些调用站点将不可见”。但正如我们在上面的Derived类中看到的,doubleValue()对于main()方法来说确实是可见的。

The dialog for pushing down members (pictured above) also gives us some more options:

推倒成员的对话框(如上图)也给了我们一些更多的选择。

  • if we have multiple derived classes, then IntelliJ will push members into each derived class
  • we can push multiple members down
  • we can preview our changes with the “Preview” button
  • only methods have a checkbox in the “Keep abstract” column – That is similar to pulling up members: If checked, this option will leave an abstract method in the base class. Unlike pulling up members, this option will put method implementations into all derived classes. These methods will also gain an @Override annotation

8. Conclusion

8.结语

In this article, we had the chance to deep dive into some of the refactoring features offered by IntelliJ. Of course, we didn’t cover all the possibilities as IntelliJ is a very powerful tool. To learn more about this editor, we can always refer to its documentation.

在这篇文章中,我们有机会深入了解了IntelliJ所提供的一些重构功能。当然,我们并没有涵盖所有的可能性,因为IntelliJ是一个非常强大的工具。要了解有关该编辑器的更多信息,我们可以随时参考其文档

We saw a few things like how to rename our code elements and how to extract some behaviors into variables, methods or classes. We also learned how to inline some elements if we didn’t need them standing alone, move some code elsewhere or even fully change an existing method signature.

我们看到了一些东西,比如如何重命名我们的代码元素,如何将一些行为提取到变量、方法或类中。我们还学习了如何内联一些元素,如果我们不需要它们单独存在,将一些代码移到其他地方,甚至完全改变现有的方法签名。