The final Keyword in Java - Quiz

Total: 6 questions

1. 

What is the final keyword in Java and where can it be applied?

final is a Java modifier that blocks any further change to whatever it is applied to. It has exactly three uses:

on a variable (local variable, method parameter, instance field, static field) — the value is assigned exactly once, and a second assignment is a compile-time error;
on a method — the method cannot be overridden in a subclass;
on a class — the class cannot be extended.

final is not an access modifier: it combines freely with public, private and static, and it goes before the type.

final int x = 5;                              // local variable
void print(final double d) { }                // method parameter
private final String name;                    // blank final instance field
public static final int MAX_WEIGHT = 100;     // constant
public final void print() { }                 // final method
public final class Money { }                  // final class

A field declared final but left without a value at the declaration is called a blank final: it must be assigned exactly once in every constructor of the class (or in an instance initializer block). A static final field is initialized at the declaration or in a static initializer block. Break these rules and the compiler answers with variable might not have been initialized or cannot assign a value to final variable.

2. 

Why can elements still be added to a collection that is declared final?

final List<String> names = new ArrayList<>();
names.add("Anna");
names.add("Boris");
System.out.println(names); // [Anna, Boris]

Because for reference types final freezes the reference, not the state of the object. The variable keeps pointing at the same object forever, yet that object is free to change if it is mutable.

final List<String> names = new ArrayList<>();
names.add("Anna");            // OK: we mutate the object, not the reference
names.clear();                // OK
// names = new ArrayList<>();  // error: cannot assign a value to final variable names

final int[] numbers = {1, 2, 3};
numbers[0] = 42;              // OK: array elements are not protected
// numbers = new int[5];      // compile-time error

String rarely causes confusion here, because String is immutable already: every method returns a brand-new string and leaves the original untouched.

So final on its own does not make an object immutable. A genuinely immutable class needs final fields, no setters, defensive copies of mutable state and no subclasses (a final class or a record). For a truly unmodifiable collection use List.of(), Set.of(), Map.of() (Java 9 and later) or Collections.unmodifiableList().

3. 

What is a constant in Java and why is it declared public static final?

A constant in Java is a class field declared public static final. Each word does its own job:

public — the value is reachable from anywhere;
static — one value shared by the whole class, no object needed;
final — the value is set once and can never be reassigned.

Constant names are written in upper case with underscores between words: MAX_WEIGHT, DEFAULT_TIMEOUT. Their main benefit is getting rid of magic numbers — literals whose meaning is impossible to guess without a comment.

public class Physics {
    public static final double ACCELERATION = 9.81;

    public static double potentialEnergy(double mass, double height) {
        return mass * height * ACCELERATION;
    }

    public static double getVelocity(double time) {
        return time * ACCELERATION;
    }
}

The name explains what the number means, and the value lives in a single place, so changing it is a one-line edit. One subtlety: constants of primitive types and String initialized with a literal are compile-time constants, and the compiler copies their value straight into the bytecode of every calling class. After changing such a constant in a library, every dependent class has to be recompiled.

4. 

What does final forbid on a method, and what does it forbid on a class?

A final method cannot be overridden in a subclass. Subclasses still inherit and call it; what they cannot do is swap in their own implementation — the attempt fails with overridden method is final.

public class Report {
    public final void print() {
        System.out.println("This method is final");
    }
}

public class SalesReport extends Report {
    /* @Override
    public void print() { }   // compile-time error */
}

A final class cannot be extended: class Cash extends Money does not compile if Money is final. Every method of a final class is implicitly final as well, because there is no subclass left to override anything in. The standard library is full of final classes: String, the wrappers Integer and Double, LocalDate, Math — final protects their immutability and their equals()/hashCode() contract. A record is implicitly final too.

Other rules worth remembering:

private final on a method is redundant — a private method is invisible to subclasses anyway;
• static methods are hidden rather than overridden, so final on a static method forbids hiding it;
• a constructor can never be final, since constructors are not inherited;
abstract final is illegal for both methods and classes: abstract demands a subclass, final forbids one;
final blocks overriding, not overloading.

5. 

What is an effectively final variable, and why does a lambda stop compiling when the variable is reassigned?

Effectively final is a local variable or a method parameter that is never reassigned after initialization, even though the word final is not written. The notion was introduced in Java 8.

Lambdas and anonymous classes can capture only final or effectively final variables, because what gets captured is a copy of the value rather than the variable itself: if reassignment were allowed, the lambda and the enclosing method would see different values.

public void printTotal(List<String> items) {
    int total = items.size();  // effectively final: never reassigned

    Runnable task = () -> System.out.println("Total: " + total); // OK
    task.run();

    // total++; // uncomment this and the lambda stops compiling:
    //          // local variables referenced from a lambda expression
    //          // must be final or effectively final
}

This is one of the first walls developers hit when they move to lambdas: a counter cannot be incremented from inside the lambda. The usual workarounds are a one-element array, an AtomicInteger, or — almost always the better answer — a Stream API operation such as count() or reduce() that returns a result instead of mutating a variable.

As for parameters: final on a parameter or a local variable changes nothing for the caller. It is a guard against accidental reassignment inside the method and a signal to the reader that the value stays put.

6. 

What is the difference between final, finally and finalize()?

Three lookalike words that belong to three unrelated parts of the language:

final is a modifier. It blocks reassignment of a variable, overriding of a method and inheritance of a class.
finally is a block of the try-catch-finally statement. It runs either way, whether an exception was thrown or not, and is used to release resources.
finalize() is a legacy method of Object. It was an obsolete hook called before garbage collection: deprecated in Java 9, deprecated for removal in Java 18, and already switchable off with --finalization=disabled.

final int x = 5;            // modifier: x can never be reassigned

try {
    readFile();
} finally {
    closeFile();            // block: runs in any case
}

Modern replacements for finalize() are try-with-resources and java.lang.ref.Cleaner. Telling these three words apart is a classic Java interview opener.

Page 1 of 1