Final Classes and Methods – Java

Ebook: Core Java 2 Volums 1

Occasionally, you want to prevent someone from forming a subclass from one of your classes. Classes that cannot be extended are called final classes, and you use the final modifier in the definition of the class to indicate this. For example, let us suppose we want to prevent others from subclassing the Executive class. Then, we simply declare the class by using the final modifier as follows:

final class Executive extends Manager
{
   . . .
}

 

You can also make a specific method in a class final. If you do this, then no subclass can override that method. (All methods in a final class are automatically final.) For example,

class Employee
{
   . . .
   public final String getName()
   {
      return name;
   }
   . . .
}

NOTE

Recall that fields can also be declared as final. A final field cannot be changed after the object has been constructed. However, if a class is declared as final, only the methods, not the fields, are automatically final.

 

There is only one good reason to make a method or class final: to make sure that the semantics cannot be changed in a subclass. For example, the getTime and setTime methods of the Calendar class are final. This indicates that the designers of the Calendar class have taken over responsibility for the conversion between the Date class and the calendar state. No subclass should be allowed to mess up this arrangement. Similarly, the String class is a final class. That means nobody can define a subclass of String. In other words, if you have a String reference, then you know it refers to a String and nothing but a String.

Some programmers believe that you should declare all methods as final unless you have a good reason that you want polymorphism. In fact, in C++ and C#, methods do not use polymorphism unless you specifically request it. That may be a bit extreme, but we agree that it is a good idea to think carefully about final methods and classes when you design a class hierarchy.

In the early days of Java, some programmers used the final keyword in the hope of avoiding the overhead of dynamic binding. If a method is not overridden, and it is short, then a compiler can optimize the method call away—a process called inlining. For example, inlining the call e.getName() replaces it with the field access e.name. This is a worthwhile improvement—CPUs hate branching because it interferes with their strategy of prefetching instructions while processing the current one. However, if getName can be overridden in another class, then the compiler cannot inline it because it has no way of knowing what the overriding code may do.

Fortunately, the just-in-time compiler in the virtual machine can do a better job than a traditional compiler. It knows exactly which classes extend a given class, and it can check whether any class actually overrides a given method. If a method is short, frequently called, and not actually overridden, the just-in-time compiler can inline the method. What happens if the virtual machine loads another subclass that overrides an inlined method? Then the optimizer must undo the inlining. That’s slow, but it happens rarely

Abstract – Java

Ebook: Core Java 2 Volumn 1

Abstract methods are an important concept in the Java programming language. You will encounter them most commonly inside interfaces.

Example 5-2. PersonTest.java
 1. import java.text.*;
 2. import java.util.*;
 3.
 4. public class PersonTest
 5. {
 6.    public static void main(String[] args)
 7.    {
 8.       Person[] people = new Person[2];
 9.
10.       // fill the people array with Student and Employee objects
11.       people[0] = new Employee("Harry Hacker", 50000, 1989, 10, 1);
12.       people[1] = new Student("Maria Morris", "computer science");
13.
14.       // print out names and descriptions of all Person objects
15.       for (Person p : people)
16.          System.out.println(p.getName() + ", " + p.getDescription());
17.    }
18. }
19.
20. abstract class Person
21. {
22.    public Person(String n)
23.    {
24.       name = n;
25.    }
26.
27.    public abstract String getDescription();
28.
29.    public String getName()
30.    {
31.       return name;
32.    }
33.
34.    private String name;
35. }
36.
37. class Employee extends Person
38. {
39.    public Employee(String n, double s,
40.       int year, int month, int day)
41.    {
42.       super(n);
43.       salary = s;
44.       GregorianCalendar calendar = new GregorianCalendar(year, month - 1, day);
45.       hireDay = calendar.getTime();
46.    }
47.
48.    public double getSalary()
49.    {
50.       return salary;
51.    }
52.
53.    public Date getHireDay()
54.    {
55.       return hireDay;
56.    }
57.
58.    public String getDescription()
59.    {
60.       return String.format("an employee with a salary of $%.2f", salary);
61.    }
62.
63.    public void raiseSalary(double byPercent)
64.    {
65.       double raise = salary * byPercent / 100;
66.       salary += raise;
67.    }
68.
69.    private double salary;
70.    private Date hireDay;
71. }
72.
73.
74. class Student extends Person
75. {
76.    /**
77.       @param n the student's name
78.       @param m the student's major
79.    */
80.    public Student(String n, String m)
81.    {
82.       // pass n to superclass constructor
83.       super(n);
84.       major = m;
85.    }
86.
87.    public String getDescription()
88.    {
89.       return "a student majoring in " + major;
90.    }
91.
92.    private String major;
93. }