Final (Java)

Last updated

In the Java programming language, the final keyword is used in several contexts to define an entity that can only be assigned once.

Contents

Once a final variable has been assigned, it always contains the same value. If a final variable holds a reference to an object, then the state of the object may be changed by operations on the object, but the variable will always refer to the same object (this property of final is called non-transitivity [1] ). This applies also to arrays, because arrays are objects; if a final variable holds a reference to an array, then the components of the array may be changed by operations on the array, but the variable will always refer to the same array. [2]

Final classes

A final class cannot be subclassed. As doing this can confer security and efficiency benefits, many of the Java standard library classes are final, such as java.lang.System and java.lang.String .

Example:

publicfinalclassMyFinalClass{...}publicclassThisIsWrongextendsMyFinalClass{...}// forbidden

Final methods

A final method cannot be overridden or hidden by subclasses. [3] This is used to prevent unexpected behavior from a subclass altering a method that may be crucial to the function or consistency of the class. [4]

Example:

publicclassBase{publicvoidm1(){...}publicfinalvoidm2(){...}publicstaticvoidm3(){...}publicstaticfinalvoidm4(){...}}publicclassDerivedextendsBase{publicvoidm1(){...}// OK, overriding Base#m1()publicvoidm2(){...}// forbiddenpublicstaticvoidm3(){...}// OK, hiding Base#m3()publicstaticvoidm4(){...}// forbidden}

A common misconception is that declaring a method as final improves efficiency by allowing the compiler to directly insert the method wherever it is called (see inline expansion). Because the method is loaded at runtime, compilers are unable to do this. Only the runtime environment and JIT compiler know exactly which classes have been loaded, and so only they are able to make decisions about when to inline, whether or not the method is final. [5]

Machine code compilers that generate directly executable, platform-specific machine code, are an exception. When using static linking, the compiler can safely assume that methods and variables computable at compile-time may be inlined.

Final variables

A final variable can only be initialized once, either via an initializer or an assignment statement. It does not need to be initialized at the point of declaration: this is called a "blank final" variable. A blank final instance variable of a class must be definitely assigned in every constructor of the class in which it is declared; similarly, a blank final static variable must be definitely assigned in a static initializer of the class in which it is declared; otherwise, a compile-time error occurs in both cases. [6] (Note: If the variable is a reference, this means that the variable cannot be re-bound to reference another object. But the object that it references is still mutable, if it was originally mutable.)

Unlike the value of a constant, the value of a final variable is not necessarily known at compile time. It is considered good practice to represent final constants in all uppercase, using underscore to separate words. [7]

Example:

publicclassSphere{// pi is a universal constant, about as constant as anything can be.publicstaticfinaldoublePI=3.141592653589793;publicfinaldoubleradius;publicfinaldoublexPos;publicfinaldoubleyPos;publicfinaldoublezPos;Sphere(doublex,doubley,doublez,doubler){radius=r;xPos=x;yPos=y;zPos=z;}[...]}

Any attempt to reassign radius, xPos, yPos, or zPos will result in a compile error. In fact, even if the constructor doesn't set a final variable, attempting to set it outside the constructor will result in a compilation error.

To illustrate that finality doesn't guarantee immutability: suppose we replace the three position variables with a single one:

publicfinalPositionpos;

where pos is an object with three properties pos.x, pos.y and pos.z. Then pos cannot be assigned to, but the three properties can, unless they are final themselves.

Like full immutability, the use of final variables has great advantages, especially in optimization. For instance, Sphere will probably have a function returning its volume; knowing that its radius is constant allows us to memoize the computed volume. If we have relatively few Spheres and we need their volumes very often, the performance gain might be substantial. Making the radius of a Spherefinal informs developers and compilers that this sort of optimization is possible in all code that uses Spheres.

Though it appears to violate the final principle, the following is a legal statement:

for(finalSomeObjectobj:someList){// do something with obj}

Since the obj variable goes out of scope with each iteration of the loop, it is actually redeclared each iteration, allowing the same token (i.e. obj) to be used to represent multiple variables. [8]

Final variables in nested objects

Final variables can be used to construct trees of immutable objects. Once constructed, these objects are guaranteed not to change anymore. To achieve this, an immutable class must only have final fields, and these final fields may only have immutable types themselves. Java's primitive types are immutable, as are strings and several other classes.

If the above construction is violated by having an object in the tree that is not immutable, the expectation does not hold that anything reachable via the final variable is constant. For example, the following code defines a coordinate system whose origin should always be at (0, 0). The origin is implemented using a java.awt.Point though, and this class defines its fields as public and modifiable. This means that even when reaching the origin object over an access path with only final variables, that object can still be modified, as the below example code demonstrates.

importjava.awt.Point;publicclassFinalDemo{staticclassCoordinateSystem{privatefinalPointorigin=newPoint(0,0);publicPointgetOrigin(){returnorigin;}}publicstaticvoidmain(String[]args){CoordinateSystemcoordinateSystem=newCoordinateSystem();coordinateSystem.getOrigin().x=15;assertcoordinateSystem.getOrigin().getX()==0;}}

The reason for this is that declaring a variable final only means that this variable will point to the same object at any time. The object that the variable points to is not influenced by that final variable though. In the above example, the origin's x and y coordinates can be freely modified.

To prevent this undesirable situation, a common requirement is that all fields of an immutable object must be final, and that the types of these fields must be immutable themselves. This disqualifies java.util.Date and java.awt.Point and several other classes from being used in such immutable objects.

Final and inner classes

When an anonymous inner class is defined within the body of a method, all variables declared final in the scope of that method are accessible from within the inner class. For scalar values, once it has been assigned, the value of the final variable cannot change. For object values, the reference cannot change. This allows the Java compiler to "capture" the value of the variable at run-time and store a copy as a field in the inner class. Once the outer method has terminated and its stack frame has been removed, the original variable is gone but the inner class's private copy persists in the class's own memory.

importjavax.swing.*;publicclassFooGUI{publicstaticvoidmain(String[]args){//initialize GUI componentsfinalJFramejf=newJFrame("Hello world!");//allows jf to be accessed from inner class bodyjf.add(newJButton("Click me"));// pack and make visible on the Event-Dispatch ThreadSwingUtilities.invokeLater(newRunnable(){@Overridepublicvoidrun(){jf.pack();//this would be a compile-time error if jf were not finaljf.setLocationRelativeTo(null);jf.setVisible(true);}});}}

Blank final

The blank final, which was introduced in Java 1.1, is a final variable whose declaration lacks an initializer. [9] [10] Previous to Java 1.1, a final variable was required to have an initializer. A blank final, by definition of "final", can only be assigned once. i.e. it must be unassigned when an assignment occurs. In order to do this, a Java compiler runs a flow analysis to ensure that, for every assignment to a blank final variable, the variable is definitely unassigned before the assignment; otherwise a compile-time error occurs. [11]

finalbooleanhasTwoDigits;if(number>=10&&number<100){hasTwoDigits=true;}if(number>-100&&number<=-10){hasTwoDigits=true;// compile-error because the final variable might already be assigned.}

In addition, a blank final also has to be definitely assigned before being accessed. [11]

finalbooleanisEven;if(number%2==0){isEven=true;}System.out.println(isEven);// compile-error because the variable was not assigned in the else-case.

Note though that a non-final local variable also needs to be definitely assigned before being accessed. [11]

booleanisEven;// *not* finalif(number%2==0){isEven=true;}System.out.println(isEven);// Same compile-error because the non-final variable was not assigned in the else-case.

C/C++ analog of final variables

In C and C++, the analogous construct is the const keyword. This differs substantially from final in Java, most basically in being a type qualifier: const is part of the type, not only part of the identifier (variable). This also means that the constancy of a value can be changed by casting (explicit type conversion), in this case known as "const casting". Nonetheless, casting away constness and then modifying the object results in undefined behavior if the object was originally declared const. Java's final is a strict rule such that it is impossible to compile code that directly breaks or bypasses the final restrictions. Using reflection, however, it is often possible to still modify final variables. This feature is mostly made use of when deserializing objects with final members.

Further, because C and C++ expose pointers and references directly, there is a distinction between whether the pointer itself is constant, and whether the data pointed to by the pointer is constant. Applying const to a pointer itself, as in SomeClass * const ptr, means that the contents being referenced can be modified, but the reference itself cannot (without casting). This usage results in behaviour which mimics the behaviour of a final variable reference in Java. By contrast, when applying const to the referenced data only, as in const SomeClass * ptr, the contents cannot be modified (without casting), but the reference itself can. Both the reference and the contents being referenced can be declared as const.

C# analogs for final keyword

C# can be considered as similar to Java, in terms of its language features and basic syntax: Java has JVM, C# has .Net Framework; Java has bytecode, C# has MSIL; Java has no pointers (real memory) support, C# is the same.

Regarding the final keyword, C# has two related keywords:

  1. The equivalent keyword for methods and classes is sealed
  2. The equivalent keyword for variables is readonly [12]

Note that a key difference between the C/C++ derived keyword const and the C# keyword readonly is that const is evaluated at compile time, while readonly is evaluated at runtime, and thus can have an expression that is only calculated and fixed later (at runtime).

See also

Related Research Articles

In object-oriented (OO) and functional programming, an immutable object is an object whose state cannot be modified after it is created. This is in contrast to a mutable object, which can be modified after it is created. In some cases, an object is considered immutable even if some internally used attributes change, but the object's state appears unchanging from an external point of view. For example, an object that uses memoization to cache the results of expensive computations could still be considered an immutable object.

A method in object-oriented programming (OOP) is a procedure associated with an object, and generally also a message. An object consists of state data and behavior; these compose an interface, which specifies how the object may be used. A method is a behavior of an object parametrized by a user.

In object-oriented programming such as is often used in C++ and Object Pascal, a virtual function or virtual method is an inheritable and overridable function or method that is dispatched dynamically. Virtual functions are an important part of (runtime) polymorphism in object-oriented programming (OOP). They allow for the execution of target functions that were not precisely identified at compile time.

This article compares two programming languages: C# with Java. While the focus of this article is mainly the languages and their features, such a comparison will necessarily also consider some features of platforms and libraries. For a more detailed comparison of the platforms, see Comparison of the Java and .NET platforms.

In class-based, object-oriented programming, a constructor is a special type of function called to create an object. It prepares the new object for use, often accepting arguments that the constructor uses to set required member variables.

In the C++ programming language, a reference is a simple reference datatype that is less powerful but safer than the pointer type inherited from C. The name C++ reference may cause confusion, as in computer science a reference is a general concept datatype, with pointers and C++ references being specific reference datatype implementations. The definition of a reference in C++ is such that it does not need to exist. It can be implemented as a new name for an existing object.

<span class="mw-page-title-main">Java syntax</span> Set of rules defining correctly structured program

The syntax of Java is the set of rules defining how a Java program is written and interpreted.

In computer programming, a static variable is a variable that has been allocated "statically", meaning that its lifetime is the entire run of the program. This is in contrast to shorter-lived automatic variables, whose storage is stack allocated and deallocated on the call stack; and in contrast to objects, whose storage is dynamically allocated and deallocated in heap memory.

In some programming languages, const is a type qualifier, which indicates that the data is read-only. While this can be used to declare constants, const in the C family of languages differs from similar constructs in other languages in that it is part of the type, and thus has complicated behavior when combined with pointers, references, composite data types, and type-checking. In other languages, the data is not in a single memory location, but copied at compile time for each use. Languages which use it include C, C++, D, JavaScript, Julia, and Rust.

<span class="mw-page-title-main">JavaScript syntax</span> Set of rules defining correctly structured programs

The syntax of JavaScript is the set of rules that define a correctly structured JavaScript program.

A class in C++ is a user-defined type or data structure declared with any of the keywords class, struct or union that has data and functions as its members whose access is governed by the three access specifiers private, protected or public. By default access to members of a C++ class declared with the keyword class is private. The private members are not accessible outside the class; they can be accessed only through member functions of the class. The public members form an interface to the class and are accessible outside the class.

C++11 is a version of the ISO/IEC 14882 standard for the C++ programming language. C++11 replaced the prior version of the C++ standard, called C++03, and was later replaced by C++14. The name follows the tradition of naming language versions by the publication year of the specification, though it was formerly named C++0x because it was expected to be published before 2010.

In computer science, a value object is a small object that represents a simple entity whose equality is not based on identity: i.e. two value objects are equal when they have the same value, not necessarily being the same object.

Generics are a facility of generic programming that were added to the Java programming language in 2004 within version J2SE 5.0. They were designed to extend Java's type system to allow "a type or method to operate on objects of various types while providing compile-time type safety". The aspect compile-time type safety was not fully achieved, since it was shown in 2016 that it is not guaranteed in all cases.

In object-oriented computer programming, a null object is an object with no referenced value or with defined neutral (null) behavior. The null object design pattern, which describes the uses of such objects and their behavior, was first published as "Void Value" and later in the Pattern Languages of Program Design book series as "Null Object".

This article describes the syntax of the C# programming language. The features described are compatible with .NET Framework and Mono.

In computer programming, a constant is a value that is not altered by the program during normal execution. When associated with an identifier, a constant is said to be "named," although the terms "constant" and "named constant" are often used interchangeably. This is contrasted with a variable, which is an identifier with a value that can be changed during normal execution. To simplify, constants' values remains, while the values of variables varies, both hence their names. where as the constant variable of variation is the number that results two variables.

In the C, C++, and D programming languages, a type qualifier is a keyword that is applied to a type, resulting in a qualified type. For example, const int is a qualified type representing a constant integer, while int is the corresponding unqualified type, simply an integer. In D these are known as type constructors, by analogy with constructors in object-oriented programming.

<span class="mw-page-title-main">Strongly typed identifier</span>

A strongly typed identifier is user-defined data type which serves as an identifier or key that is strongly typed. This is a solution to the "primitive obsession" code smell as mentioned by Martin Fowler. The data type should preferably be immutable if possible. It is common for implementations to handle equality testing, serialization and model binding.

References

  1. Coblenz, Michael; Sunshine, Joshua; Aldrich, Jonathan; Myers, Brad; Weber, Sam; Shull, Forrest (14–22 May 2016). "Exploring Language Support for Immutability". The 38th International Conference on Software Engineering.
  2. Java Language Specification #4.12.4
  3. "Chapter 8. Classes". docs.oracle.com. Retrieved 2024-04-25.
  4. "Writing Final Classes and Methods". docs.oracle.com. Retrieved 2024-04-25.
  5. "Java theory and practice: Is that your final answer?". developer.ibm.com. Archived from the original on 2009-02-08. Retrieved 2024-04-25.
  6. Java Language Specification #8.3.1.2.
  7. "Java Programming Style Guidelines". petroware.no. Retrieved 2024-04-25.
  8. Pattis, Richard E. "More Java". Advanced Programming/Practicum 15–200. School of Computer Science Carnegie Mellon University . Retrieved 23 July 2010.
  9. Flanagan, David (May 1997). "Chapter 5 Inner Classes and Other New Language Features:5.6 Other New Features of Java 1.1". Java in a Nutshell (2nd ed.). O'Reilly. ISBN   1-56592-262-X.
  10. "Chapter 4. Types, Values, and Variables". The Java® Language Specification (Java SE 8 Edition). Oracle America, Inc. 2015. Retrieved 23 Feb 2015.
  11. 1 2 3 "Definite Assignment". The Java® Language Specification (Java SE 8 Edition). Oracle America, Inc. 2015. Retrieved 29 Oct 2016.
  12. What is the equivalent of Java's final in C#?