Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to understand final, finally and finalize

2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article focuses on "how to understand final, finally and finalize". Interested friends may wish to have a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn how to understand final, finally and finalize.

1. Final, finally and finalize

I believe all of you here are experienced programmers, so there is no need to say much about the basic keyword final. However, we still have to take care of rookie readers. After all, we all came here from rookies.

(1) final modifies classes, attributes and methods

Final can be used to modify classes, and final-decorated classes do not allow other classes to inherit, that is, final-decorated classes are unique. As shown below

We first define a FinalUsage class, which is decorated with final, and at the same time we define a FinalUsageExtend class that wants to inherit (extend) FinalUsage. After we inherit as above, the compiler won't let us play like this. It suggests that we can't inherit from the FinalUsage class. Why? Never mind, this is the agreement of Java, there are some reasons why it is not necessary, just follow it.

Final can be used to modify methods, but final-modified methods are not allowed to be rewritten. Let's demonstrate how to modify methods without the final keyword.

As shown in the figure above, we use the FinalUsageExtend class to inherit the FinalUsage class and provide an override of the writeArticle method. There is no problem with compiling in this way, and the key point of rewriting is the consistency of the @ Override annotation with method modifiers, names, and return values.

Note: many programmers ignore @ Override when rewriting methods, which makes it more difficult to read the code, which is not recommended.

When we use the final decorating method, the method cannot be overridden, as shown below

When we declare the writeArticle method as void, the overridden method will report an error and cannot override the writeArticle method.

Final can modify variables, and final-modified variables cannot be modified once defined, as shown below

The error prompted by the compiler is that you cannot inherit a class decorated by final.

What we use above is the string String, and String is final by default, but it doesn't make much sense to decorate it with or without final, because strings can't be rewritten in the first place, which doesn't mean anything.

Let's rewrite it and use basic data types to demonstrate

Similarly, you can see that the compiler still gives the hint that age cannot be rewritten, thus proving that variables modified by final cannot be rewritten.

In Java, there are not only basic data types, but also reference data types, so what happens when reference types are modified by final? Let's take a look at the following code

First construct a Person class:

Public class Person {int id; String name; get () and set ()... ToString (). }

Then we define a Person variable for final.

Static final Person person = new Person (25, "cxuan"); public static void main (String [] args) {System.out.println (person); person.setId (26); person.setName ("cxuan001"); System.out.println (person);}

Output, you will find a strange phenomenon, why we obviously changed the id and name in person, but the compiler did not report an error?

This is because the reference type modified by final simply ensures that the reference to the object does not change. The data inside the object can be changed. This involves the allocation of objects in memory, which we'll talk about later.

(2) the finally guarantee program must be executed.

Finally is a mechanism that ensures that a program must be executed. Similarly, it is also a keyword in Java. Generally speaking, finally is not used alone. It is generally used with a try block. For example, the following is a try...finally code block:

Try {lock.lock ();} finally {lock.unlock ();}

This is an example of locking / unlocking code. After lock is locked, unlock operation is performed in finally. Because finally can guarantee that the code must be executed, some important code is generally put in finally, such as unlock operation, stream close operation, connection release operation and so on.

You can also use it with try...catch...finally when lock.lock () generates an exception:

Try {lock.lock ();} catch (Exception e) {e.printStackTrace ();} finally {lock.unlock ();}

Before try...finally is suitable for JDK1.7, a new operation to close the stream was introduced in JDK1.7, that is, try...with...resources,Java introduced a try-with-resources declaration to simplify try-catch-finally to try-catch, which is actually a syntax sugar, not an extra syntax. Try...with...resources is still converted to try-catch-finally statements at compile time.

Syntactic sugar, also translated as sugar-coated grammar, refers to a grammar added to a computer language that does not affect the function of the language, but is more convenient for programmers to use. Generally speaking, the use of syntax sugar can increase the readability of the program, thus reducing the chance of error in the program code.

In Java, there are some syntax sweets to simplify the syntax used by programmers, which we'll talk about later.

(3) the function of finalize

Finalize is a method of the ancestral class Object, which is designed to ensure that objects complete the collection of specific resources before garbage collection. Finalize is no longer recommended and has been explicitly marked as deprecated in JDK 1.9.

two。 In-depth understanding of final, finally and finalize

(1) final design

Many programming languages have a way to tell the compiler that a piece of data is constant. Sometimes constant data is useful, such as

A compile-time constant that will never change. For example, static final int num = 1024

A value that is initialized at runtime, and you don't want to change it

The design of final conflicts with the design of abstract, because the abstract keyword mainly modifies abstract classes, which need to be implemented by concrete classes. Final says that inheritance is prohibited and there is no problem of being implemented. Because only after inheritance can the subclass implement the methods of the parent class.

All private in the class are implicitly specified as final, and there is no extra meaning to use final in private-decorated code.

(2) Blank final

Java allows blank final, which means that it is declared as final, but it is not assigned to initialize it. But in any case, the compiler needs to initialize the final, so the task of initialization is left to the constructor, and the blank final gives final more flexibility. The code is as follows:

Public class FinalTest {final Integer finalNum; public FinalTest () {finalNum = 11;} public FinalTest (int num) {finalNum = num;} public static void main (String [] args) {new FinalTest (); new FinalTest (25);}}

Initializing different final in different constructors makes the use of finalNum more flexible.

There are two main ways to use final: immutability and efficiency

Immutable: immutability means locking a method (not locking it), with an emphasis on preventing other methods from being overridden.

Efficiency: this is mainly for earlier versions of Java. In the early implementation of Java, if a method was declared as final, it was agreed that the compiler would change the call to this method to an inline call, but did not bring significant performance optimization. In Java5/6, the hotspot virtual machine automatically detects embedded calls and optimizes them, so there is one main way to use final modification: immutable.

Note: final is not Immutable, Immutable is truly immutable.

Final is not a real Immutable because the objects referenced by the final keyword can be changed. If we really want the object to be immutable, we usually need the corresponding class to support immutable behavior, such as the following code:

Final List fList = new ArrayList (); fList.add ("Hello"); fList.add ("World"); List unmodfiableList = List.of ("hello", "world"); unmodfiableList.add ("again")

The List.of method creates an immutable List. Immutable Immutable is a good choice in many cases. Generally speaking, the following points should be paid attention to when implementing Immutable

Declare the class as final to prevent other classes from extending.

If you declare member variables within a class (including instance variables and class variables) as private or final, do not provide methods that can modify member variables, that is, the setter method.

When constructing an object, you usually use deep-clone, which helps prevent others from modifying the input object when assigning values directly to the object.

Adhere to the copy-on-write principle and create private copies.

(3) can final improve performance?

Whether final can improve performance has always been a controversial point in the industry. Many books have described that it can improve performance in specific scenarios, such as final may be used to help JVM inline methods, can transform the compiler's ability to compile, etc., but many of these conclusions are based on assumptions.

Roughly speaking, the efficiency of accessing local variables is the same regardless of whether they are declared with the final keyword or not.

For example, the following code (version without final):

Static int foo () {int a = someValueA (); int b = someValueB (); return a + b; / access the local variable} here

Version with final:

Static int foo () {final int a = someValueA (); final int b = someValueB (); return a + b; / access the local variable here}

Compiled with javac, the result is exactly the same.

Invokestatic someValueA: () I istore_0 / / set the value of an invokestatic someValueB: () I istore_1 / / set the value of b iload_0 / / read the value of an iload_1 / / read the value of b iadd ireturn

Because the reference type is used above, the bytecode is the same.

If it's a constant type, let's take a look at:

/ with final static int foo () {final int a = 11; final int b = 12; return a + b;} / without final static int foo () {int a = 11; int b = 12; return a + b;}

If we compile the two foo methods separately, we will find the following bytecode:

On the left is the code with non-final keyword modification, and on the right is the code with final keyword modification. Comparing these two bytecodes, we can draw the following conclusion.

With or without final modification, int a = 11 or int a = 12 is treated as a constant.

At the return point of return, a + b without final is treated as a variable; a + b modified with final is treated directly as a constant.

In fact, this level of difference only has a greater impact on the relatively simple JVM, because such VM is more dependent on the interpreter, and it executes the bytecode in the original Class file; it has no impact on high-performance JVM (such as HotSpot, J9, etc.).

Therefore, most of the effects of final on performance optimization can be ignored directly, and we use final to consider more about its immutability.

(4) deeply understand finally

We talked about the use of finally in general above, and its purpose is to ensure that the statements in finally are executed after the code in the try block is executed. Regardless of whether an exception is thrown in the try block.

So let's take a closer look at finally, what the bytecode of finally is, and the nature of when finally is executed.

First of all, we know that the finally block will only be executed when the try block is executed, and the finally will not exist alone.

There is no need to explain this too much. it is a well-known rule. Finally must be used with try blocks or try catch blocks.

Second, the finally block executes before the control transfer statement when either the try block execution is complete or the try block execution is not completed but then the control transfer statement (return/continue/break)

This one actually shows the timing of the execution of finally. Let's take return as an example to see if this is the case.

The code is as follows:

Static int mayThrowException () {try {return 1;} finally {System.out.println ("finally");}} public static void main (String [] args) {System.out.println (FinallyTest.mayThrowException ());}

From the execution result, it can be proved that finally should be executed before return.

When finally has a return value, it returns directly. The return value in try or catch is no longer returned.

Static int mayThrowException () {try {return 1;} finally {return 2;}} public static void main (String [] args) {System.out.println (FinallyTest.mayThrowException ());}

Before executing the finally statement, the control transfer statement stores the return value in the local variable

Look at the following code:

Static int mayThrowException () {int I = 100; try {return I;} finally {+ + I;}} public static void main (String [] args) {System.out.println (FinallyTest.mayThrowException ());}

The above code shows that return I is executed before + I, and return I temporarily stores the value of I and returns it with finally.

(5) the essence of finally

Let's look at a piece of code:

Public static void main (String [] args) {int A1 = 0; try {A1 = 1;} catch (Exception e) {A1 = 2;} finally {A1 = 3;} System.out.println (A1);}

What is the result of this code output? The answer is 3, why?

In doubt, let's first take a look at the bytecode of this code.

I have marked out the Chinese comments for the bytecode for you. It should be noted that the following Exception table,Exception table is an exception table. Each entry in the exception table represents an exception generator, which is composed of From pointer, To pointer, Target pointer and the type of exception that should be caught.

So there are three execution paths to the above code.

If an exception belonging to exception and its subclasses occurs in the try statement block, jump to catch processing

If there is an exception in the try statement block that does not belong to exception and its subclasses, jump to finally processing

If a new exception occurs in the catch statement block, jump to finally processing

At this point, we haven't said what the essence of finally is. If you take a closer look at the bytecode above, you will find that finally actually puts the A1 = 3 bytecode iconst_3 and istore_1 after the try block and the catch block, so the above code is similar to:

Public static void main (String [] args) {int A1 = 0; try {A1 = 1; / / finally A1 = 3} catch (Exception e) {A1 = 2; / finally A1 = 3} finally {A1 = 3;} System.out.println (A1);}

The Exception table above is an exception table in which only exception and error subclasses of Throwable perform exception walkthrough. Normally, there is no exception table without try blocks. Let's verify this:

Public static void main (String [] args) {int A1 = 1; System.out.println (A1);}

For example, above we use a very simple program to verify. After compilation, let's take a look at its bytecode.

As you can see, there is no abnormal table.

(6) will finally be implemented?

What we have discussed above is the situation in which finally must be executed, so will finally be executed? Probably not.

In addition to the power outage of the computer room, the explosion of the computer room, the influx of water into the computer room, the lightning strike in the computer room, the forced shutdown, and the unplugging of the power supply, there are several other situations that can prevent finally from being carried out.

Call the System.exit method

Call the Runtime.getRuntime () .halt (exitStatus) method

JVM downtime (funny face)

If JVM reaches an infinite loop (or other uninterrupted, non-terminating statement) in a try or catch block

Whether the operating system forcibly terminated the JVM process; for example, execute kill-9 pid on UNIX

If the host system crashes; for example, power failure, hardware error, operating system panic, etc., will not be executed

If the finally block is executed by a daemon thread, all non-daemon threads exit before the finally call.

(7) is finalize really useless?

We briefly introduced the finalize method above and explained that it is a bad practice. So when is the timing of the finalize call? Why is finalize useless?

We know that a significant difference between Java and C++ is that Java can automatically manage memory. In Java, because of the automatic collection mechanism of GC, there is no guarantee that finalize methods will be executed in time (the timing of garbage collection is uncertain), and there is no guarantee that they will be executed.

In other words, the execution period of finalize is uncertain, and we cannot rely on the finalize method to help us with garbage collection. What may happen is that gc is not triggered before we run out of resources, so it is recommended to use the method of releasing resources as soon as they are used up, such as the close method. In addition, the finalize method can also swallow exceptions alive.

Finalize works like this: once the garbage collector is ready to free up the storage space occupied by the object, the finalize method will be called first, and the memory occupied by the object will not be actually reclaimed until the next garbage collection action occurs. Garbage collection is only related to memory.

We do not advocate the use of the finalize method in our daily development, and where we can use the finalize method, we will handle it better with try...finally.

At this point, I believe you have a deeper understanding of "how to understand final, finally and finalize". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report