什么是内联方法?

Tar*_*rik 40 java methods function

我一直试图理解这意味着什么:

内联函数

在C++中,类声明中定义的成员函数.(2)编译器替换函数实际代码的函数调用.关键字inline可用于提示编译器执行成员或非成员函数体的内联扩展.

排队

在编译期间用函数代码的副本替换函数调用.

例如,它写的类似于:

当方法是最终的时,它可以是内联的.

这里:http://www.roseindia.net/javatutorials/final_methods.shtml

你能给我一个例子或者什么,或者基本上帮助我理解"它可能被内联"的含义.

谢谢.

Tom*_*sky 64

内联是由Java Just-In-Time编译器执行的优化.

如果你有一个方法:

public int addPlusOne(int a, int b) {
  return a + b + 1;
}
Run Code Online (Sandbox Code Playgroud)

你这样称呼:

public void testAddPlusOne() {
  int v1 = addPlusOne(2, 5);
  int v2 = addPlusOne(7, 13);

  // do something with v1, v2
}
Run Code Online (Sandbox Code Playgroud)

编译器可能决定用函数体替换你的函数调用,所以结果实际上如下所示:

public void testAddPlusOne() {
  int v1 = 2 + 5 + 1;
  int v2 = 7 + 13 + 1

  // do something with v1, v2
}
Run Code Online (Sandbox Code Playgroud)

编译器这样做是为了节省实际进行函数调用的开销,这将涉及将每个参数推送到堆栈.

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

另外,请在引用中注明单词may.最终方法不保证可以内联.有多种方法可以保证方法无法内联,但无法强制编译器内联.无论如何,当内联将有助于破坏最终代码的速度时,它几乎总会比你更清楚.

有关优点和问题的详细信息,请参阅维基百科.

  • 很好的答案,但作为一个注释:如果你有一个非最终的方法,你*不*覆盖,一个好的JIT可以解决这个问题,无论如何内联它.如果然后加载一个覆盖它的类,它可以撤消内联. (13认同)

Chr*_*dge 11

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

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


aio*_*obe 10

假设你有一个看起来像这样的类:

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

    public void printMessage() {
        System.out.println("Hello World");
    }
}
Run Code Online (Sandbox Code Playgroud)

printMessage可以通过以下方式"内联" 调用:

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

    public void printMessage() {
        System.out.println("Hello World");
    }
}
Run Code Online (Sandbox Code Playgroud)

(这实际上不是在Java级别上完成的(甚至不是在字节码级别上),而是在JIT编译期间,但上面的示例说明了内联的概念.)

现在考虑如果该printMessage方法被另一个类重载会发生什么,如下所示:

class SubDemo extends Demo {
    public void printMessage() {
        System.out.println("Something else");
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果编译器内联调用Demo.printMessage它将被卡住,如果该对象实际上是一个实例,System.out.println("Hello World");那将是错误SubDemo.

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