1. Overview
1.概述
In this tutorial, we’re going to take an overview of three Java keywords: final, finally and finalize.
在本教程中,我们将对三个Java关键字进行概述。final、finally和finalize。最后
While these keywords resemble each other each has a very different meaning in Java. We’ll learn the purpose of each of them and see some examples through a bit of code.
虽然这些关键字彼此相似,但它们在Java中的含义却大不相同。我们将学习它们各自的用途,并通过一些代码看到一些例子。
2. final Keyword
2.最终关键词
Let’s first take a look at the final keyword, where to use it and why. We can apply the final keyword to class, method, field, variable and method parameter declarations.
让我们先来看看final关键字,在哪里使用它以及为什么。我们可以将final关键字应用于类、方法、字段、变量和方法参数的声明。
It doesn’t have the same effect on each of them though:
虽然对他们每个人的影响都不一样。
- Making a class final means that it won’t be possible to extend that class
- Adding final to a method means that it won’t be possible to override that method
- Finally, putting final in front of a field, a variable or a parameter means that once the reference has been assigned then it cannot be changed (however, if the reference is to a mutable object, it’s internal state could change despite being final)
A detailed article about the final keyword can be found here.
关于 final关键字的详细文章可以在这里找到。
Let’s see how the final keyword works through some examples.
让我们通过一些例子看看final关键字是如何工作的。
2.1. final Fields, Parameters, and Variables
2.1.最终字段、参数和变量
Let’s create a Parent class with two int fields, a final one, and a regular non-final one:
让我们创建一个有两个int字段的Parent类,一个final字段和一个普通的非final字段。
public class Parent {
int field1 = 1;
final int field2 = 2;
Parent() {
field1 = 2; // OK
field2 = 3; // Compilation error
}
}
As we can see, the compiler forbids us to assign a new value to field2.
我们可以看到,编译器禁止我们给field2分配一个新的值。
Let’s now add a method with a regular and a final argument:
现在让我们添加一个带有常规参数和最终参数的方法。
void method1(int arg1, final int arg2) {
arg1 = 2; // OK
arg2 = 3; // Compilation error
}
Similarly to fields, it’s not possible to assign something to arg2 as it’s declared final.
与字段类似,不可能给arg2分配东西,因为它被声明为final。
We can now add a second method to illustrate how this works with local variables:
我们现在可以添加第二个方法来说明如何使用局部变量。
void method2() {
final int localVar = 2; // OK
localVar = 3; // Compilation error
}
Nothing surprising happens, the compiler doesn’t let us assign a new value to localVar after its first assignation.
没有什么令人惊讶的事情发生,编译器不让我们在localVar的第一次赋值后给它赋一个新值。
2.2. final Method
2.2.最终方法
Now suppose we make method2 final and create a subclass of Parent, let’s say Child, in which we try to override both its superclass methods:
现在假设我们将method2设为final,并创建一个Parent的子类,比方说Child,在这个子类中我们试图覆盖其超类的两个方法。
public class Child extends Parent {
@Override
void method1(int arg1, int arg2) {
// OK
}
@Override
final void method2() {
// Compilation error
}
}
As we can see, there’s no problem with overriding method1(), but we get a compilation error when trying to override method2().
我们可以看到,覆盖method1()没有问题,但是当我们试图覆盖method2()时,会得到一个编译错误。
2.3. final Class
2.3.final类
And finally, let’s make the Child class final and try to create a subclass of it, GrandChild:
最后,让我们把Child类变成final,并尝试创建它的一个子类,GrandChild。
public final class Child extends Parent {
// ...
}
public class GrandChild extends Child {
// Compilation error
}
Once again, the compiler complains. The Child class is final and therefore impossible to extend.
编译器又一次抱怨了。Child类是最终的,因此无法扩展。
3. finally Block
3.最后块
The finally block is an optional block to use with a try/catch statement. In this block, we include code to execute after the try/catch structure, whether an exception is thrown or not.
finally块是一个可选的块,可与try/catch语句一起使用。在这个块中,我们包含了在try/catch结构之后执行的代码,无论是否抛出了一个异常。
It’s even possible to use it with the try block without any catch block provided we include a finally block. The code will then be executed after the try or after an exception is thrown.
我们甚至可以在没有任何catch块的情况下使用它,只要我们包含一个finally块。然后,代码将在try之后或抛出异常之后被执行。
We have an in-depth article about exception handling in Java here.
我们有一篇关于Java中异常处理的深度文章这里。
Now let’s demonstrate a finally block in a short example. We’ll create a dummy main() method with a try/catch/finally structure:
现在让我们通过一个简短的例子来演示finally块。我们将创建一个带有try/catch/finally结构的假main()方法。
public static void main(String args[]) {
try {
System.out.println("Execute try block");
throw new Exception();
} catch (Exception e) {
System.out.println("Execute catch block");
} finally {
System.out.println("Execute finally block");
}
}
If we run this code, it’ll output the following:
如果我们运行这段代码,它将输出以下内容。
Execute try block
Execute catch block
Execute finally block
Let’s now modify the method by removing the catch block (and add throws Exception to the signature):
现在让我们修改这个方法,删除catch块(并在签名中添加throws Exception)。
public static void main(String args[]) throws Exception {
try {
System.out.println("Execute try block");
throw new Exception();
} finally {
System.out.println("Execute finally block");
}
}
The output is now:
现在的输出是。
Execute try block
Execute finally block
If we now remove the throw new Exception() instruction, we can observe that the output stays the same. Our finally block execution occurs every time.
如果我们现在删除throw new Exception()指令,我们可以观察到输出保持不变。我们的finally块执行每次都会发生。
4. finalize Method
4.finalize方法
And finally, the finalize method is a protected method, defined in the Object class. It’s called by the garbage collector on objects that aren’t referenced anymore and have been selected for garbage collection.
最后,finalize方法是一个受保护的方法,定义在对象类中。它被垃圾收集器调用,用于不再被引用并被选定为垃圾收集的对象。
Like any other non-final method we can override this method to define the behavior an object must have when collected by the garbage collector.
像其他非最终方法一样,我们可以覆盖这个方法来定义一个对象在被垃圾收集器收集时必须具有的行为。
Again, a detailed article covering the finalize method can be found here.
同样,涵盖finalize方法的详细文章可以在这里找到。
Let’s see an example of how it works. We’ll use System.gc() to suggest the JVM to trigger garbage collection:
让我们看看它是如何工作的一个例子。我们将使用System.gc()来建议JVM来触发垃圾收集。
@Override
protected void finalize() throws Throwable {
System.out.println("Execute finalize method");
super.finalize();
}
public static void main(String[] args) throws Exception {
FinalizeObject object = new FinalizeObject();
object = null;
System.gc();
Thread.sleep(1000);
}
In this example, we override finalize() method in our object and create a main() method which instantiates our object and immediately drops the reference by setting the created variable to null.
在这个例子中,我们在我们的对象中覆盖了finalize()方法,并创建了一个main()方法,该方法将我们的对象实例化并通过将创建的变量设置为null来立即放弃引用。
After that, we call System.gc() to run the garbage collector (at least we expect it to run) and wait for a second (just to ensure that the JVM doesn’t shut down before garbage collector has the chance to call finalize() method).
之后,我们调用System.gc()来运行垃圾收集器(至少我们希望它能运行)并等待一秒钟(只是为了确保JVM不会在垃圾收集器有机会调用finalize()方法之前关闭)。
The output of this code execution should be:
这个代码执行的输出应该是。
Execute finalize method
Note that it’s considered bad practice to override finalize() method as its execution depends on garbage collection which is in the hand of the JVM. Plus, this method has been deprecated since Java 9.
请注意,覆盖finalize()方法被认为是不好的做法,因为它的执行取决于垃圾收集,而垃圾收集是在JVM的手中。此外,自Java 9.以来,该方法已被弃用。
5. Conclusion
5.总结
In this article, we’ve briefly discussed the differences between the three Java alike keywords: final, finally and finalize.
在这篇文章中,我们简单地讨论了三个Java相似的关键字之间的区别。final, finally和finalize。
The full code of the article can be found over on GitHub.
文章的完整代码可以在GitHub上找到over。。