Java 什么是方法内联?

Java 什么是方法内联?,java,function,methods,Java,Function,Methods,我一直在努力理解这到底意味着什么: 内联函数 在C++中,定义了一个成员函数 类声明。(2) 函数 编译器替换为的调用 函数的实际代码。这个 关键字inline可用于提示 要内联执行的编译器 膨胀一个构件或构件的主体的膨胀 非成员函数 内联 用副本替换函数调用的步骤 函数的代码在 汇编 例如,它是这样写的: 当一个方法是最终的,它可能是最终的 内联的 在这里: 你能给我举个例子或什么的,或者基本上帮我理解“它可能是内联的”是什么意思 谢谢。假设您有一个如下所示的类: public class D

我一直在努力理解这到底意味着什么:

内联函数

在C++中,定义了一个成员函数 类声明。(2) 函数 编译器替换为的调用 函数的实际代码。这个 关键字inline可用于提示 要内联执行的编译器 膨胀一个构件或构件的主体的膨胀 非成员函数

内联

用副本替换函数调用的步骤 函数的代码在 汇编

例如,它是这样写的:

当一个方法是最终的,它可能是最终的 内联的

在这里:

你能给我举个例子或什么的,或者基本上帮我理解“它可能是内联的”是什么意思


谢谢。

假设您有一个如下所示的类:

public class Demo {
    public void method() {
        // call printMessage
        printMessage();
    }

    public void printMessage() {
        System.out.println("Hello World");
    }
}
class SubDemo extends Demo {
    public void printMessage() {
        System.out.println("Something else");
    }
}
public void testAddPlusOne() {
  int v1 = addPlusOne(2, 5);
  int v2 = addPlusOne(7, 13);

  // do something with v1, v2
}
public void testAddPlusOne() {
  int v1 = 2 + 5 + 1;
  int v2 = 7 + 13 + 1

  // do something with v1, v2
}
printMessage
的调用可以通过以下方式“内联”:

public class Demo {
    public void method() {
        // call printMessage
        System.out.println("Hello World"); // <-- inlined
    }

    public void printMessage() {
        System.out.println("Hello World");
    }
}
现在,如果编译器将调用内联到
Demo.printMessage
,它将被
System.out.println(“Hello World”)卡住
如果对象实际上是
子演示
的实例,那么将是错误的


但是,如果该方法被宣布为
final
,则在任何情况下都不会出现这种情况。如果该方法是“final”,这意味着它永远不能被新定义覆盖,因此,内联它是安全的

内联是由Java实时编译器执行的优化

如果您有一个方法:

public int addPlusOne(int a, int b) {
  return a + b + 1;
}
你这样称呼它:

public class Demo {
    public void method() {
        // call printMessage
        printMessage();
    }

    public void printMessage() {
        System.out.println("Hello World");
    }
}
class SubDemo extends Demo {
    public void printMessage() {
        System.out.println("Something else");
    }
}
public void testAddPlusOne() {
  int v1 = addPlusOne(2, 5);
  int v2 = addPlusOne(7, 13);

  // do something with v1, v2
}
public void testAddPlusOne() {
  int v1 = 2 + 5 + 1;
  int v2 = 7 + 13 + 1

  // do something with v1, v2
}
编译器可能决定用函数体替换函数调用,因此结果实际上如下所示:

public class Demo {
    public void method() {
        // call printMessage
        printMessage();
    }

    public void printMessage() {
        System.out.println("Hello World");
    }
}
class SubDemo extends Demo {
    public void printMessage() {
        System.out.println("Something else");
    }
}
public void testAddPlusOne() {
  int v1 = addPlusOne(2, 5);
  int v2 = addPlusOne(7, 13);

  // do something with v1, v2
}
public void testAddPlusOne() {
  int v1 = 2 + 5 + 1;
  int v2 = 7 + 13 + 1

  // do something with v1, v2
}
编译器这样做是为了节省实际进行函数调用的开销,这将涉及将每个参数推送到堆栈上

这显然只能用于非虚拟函数。考虑如果在子类中重写该方法会发生什么,并且包含该方法的对象的类型直到运行时才知道…编译器将如何知道要复制什么代码:基类的方法体还是子类的方法体?由于Java中的所有方法在默认情况下都是虚拟的,因此可以显式地将无法重写的方法标记为
final
(或者将它们放入
final
类中)。这将帮助编译器了解该方法永远不会被重写,并且内联是安全的。(请注意,编译器有时也可以对非final方法进行此确定。)

另外,请注意引号中的单词may。最终方法不能保证是内联的。有多种方法可以保证方法不能内联,但无法强制编译器内联。不管怎样,当内联有助于或有损于生成代码的速度时,它几乎总是比您更清楚


有关好处和问题的详细概述,请参阅。

调用函数不是免费的。机器必须维护堆栈帧,以便在被调用函数完成时返回到代码的调用部分。维护堆栈(包括在此堆栈上传递函数参数)需要时间


当函数处于内联状态时,编译器会用函数的代码替换对函数的调用,这样就可以避免在运行时函数调用的性能损失。这是编程中的一个经典权衡:运行时代码变得更大(占用更多内存),但它运行得更快。

这会有所帮助:回答得好,但需要注意的是:如果您有一个非final方法,您不需要重写,那么好的JIT可以解决这个问题并将其内联。如果你加载了一个覆盖它的类,它就可以撤销内联。很好的一点,我将它添加到了答案正文中。这是一个很好的解释,感谢这个伟大的答案。也是一个很好的答案,但正如从另一个答案复制的注释:如果你有一个不覆盖的非final方法,一个好的JIT可以解决这个问题并将其内联。如果你加载了一个覆盖它的类,它可以撤销内联。这是非常解释性的,谢谢你的回答。谢谢。在第一段,你真的是对的。