You will build a small application to demonstrate the usage and usefulness of the keyword final for variable, parameters, method or class
The final keyword is very useful when the developper of the code want to be insured that a value cannot be modified in the future. Every entity in Java can be defined as final.
A final variable is a constant. Once its value has been set, it cannot be changed.
To declare a variable final, the keyword final will be between the access modifier and the type of the variable.
It is a convention to write the name of a constante all in upper case.
We declare in general constant for variable that are always true and we want the developper using our class not to be able to change, some example:
private final int YEAR = 2021;
We will implement a very small class to test this variable.
public class Tea {
private final int YEAR = 2021;
private String name;
public Tea (String name) {
this.name = name;
}
public int getYear (){
return this.YEAR;
}
}
as always a small class to test this class
public class Main {
public static void main(String[] args) {
Tea tea = new Tea("english");
System.out.println(tea.getYear());
}
}
If you try to implement a setter, like in this following code we will have a compile time error:
public class Tea {
public final int YEAR = 2021;
private String name;
public Tea (String name) {
this.name = name;
}
public void setYEAR (int year){
this.YEAR=year;
}
public int getYear (){
return this.YEAR;
}
}
For a final reference variable (for an object), the final will not affect the state of the object, but we cannot change what object it refer to. In other words, we can change the value of the different instance variables of the object. The Tea class instance variable name can be change and we added a setter and getter from the previous example.
public class Tea {
private final int YEAR = 2021;
private String name;
public Tea (String name) {
this.name = name;
}
public int getYear (){
return this.YEAR;
}
public void setName (String name){
this.name=name;
}
public String getName (){
return name;
}
}
In the following example, we are declaring that the Tea variable tea is final (in the main), in the first line of the main. We instantiate the object Tea with the value "english" to the variable name. The state of the object after the first line in the main will be:
name = english YEAR = 2021
We are changing the value of the variable name from english to Darjeeling using the setter.
public class Main {
public static void main(String[] args) {
final Tea tea = new Tea("english");
System.out.println(tea.getName());
tea.setName("Darjeeling");
System.out.println(tea.getName());
}
}
If you run this code, you will see that the value of the name have been effectively changed.
However, if now we are trying to change the object (in a whole) tea refer to, it will create a compile time error.
You can run the following code to test it out:
public class Main {
public static void main(String[] args) {
final Tea tea = new Tea("english");
System.out.println(tea.getName());
tea.setName("Darjeeling");
System.out.println(tea.getName());
Tea tea2 = new Tea("Darjeeling");
tea = tea2;
}
}
The error you will see is this one:
You can declare a final parameter for a method. With declaring that a parameter is final, we are stating that the value of this parameter cannot be changed anywhere in the function.
Let's try it with the name of the tea in the class Tea. We will have first to modify the writing of the parameter in the setTea method. Now to test what is happening, we will try to change the value of the String in the setName method by writing it in Upper case.
public class Tea {
private final int YEAR = 2021;
private String name;
public Tea (String name) {
this.name = name;
}
public int getYear(){
return this.YEAR;
}
public void setName(final String name){
name = name.toUpperCase();
this.name=name;
}
public String getName(){
return name;
}
}
Now to test what is happening, by running the following code:
public class Main {
public static void main(String[] args) {
final Tea tea = new Tea("english");
System.out.println(tea.getName());
tea.setName("Darjeeling");
System.out.println(tea.getName());
}
}
The compile time error this time will be this one:
To set the parameter as final will insure that the variable that is passed as an arguments will not be changed.
A method that is declared as final cannot be overridden by a subclass. Let's implement a class Darjeeling that will be a child of the class Tea.
public class Darjeeling extends Tea{
public Darjeeling(){
super("Darjeeling");
}
}
We will refactor the method setName to make it final:
public class Tea {
private final int YEAR = 2021;
private String name;
public Tea (String name) {
this.name = name;
}
public int getYear(){
return this.YEAR;
}
public final void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
}
Let's test this new class.
public class Main {
public static void main(String[] args) {
final Tea tea = new Tea("english");
System.out.println(tea.getName());
tea.setName("Darjeeling");
System.out.println(tea.getName());
Darjeeling d = new Darjeeling();
System.out.println(d.getName());
}
}
It will compile and run, however, let's try to override the method setName in the class Darjeeling:
public class Darjeeling extends Tea{
public Darjeeling(){
super("Darjeeling");
}
public void setName(String name){
this.name = name;
}
}
An compile time error will be raised:
We can also declare a class final, in this case, the developper using this class will not be able to extends any classes with this final class. In other words, a final class cannot be a parent of another class.
Let's make Tea a final class.
public final class Tea {
private final int YEAR = 2021;
private String name;
public Tea (String name) {
this.name = name;
}
public int getYear(){
return this.YEAR;
}
public final void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
}
The class Darjeeling cannot extends the class Tea anymore, it will raise this compile time error:
You can find the code for this example in https://git.cardiff.ac.uk/ASE_GROUP_2020/code_for_codelabs.git