Java LanguageNon-Access Modifiers

Introduction

Non-Access Modifiers do not change the accessibility of variables and methods, but they do provide them special properties.

final

final in Java can refer to variables, methods and classes. There are three simple rules:

  • final variable cannot be reassigned
  • final method cannot be overriden
  • final class cannot be extended

Usages

Good Programming Practice

Some developer consider it good practice to mark a variable final when you can. If you have a variable that should not be changed, you should mark it final.

An important use of final keyword if for method parameters. If you want to emphasize that a method doesn't change its input parameters, mark the properties as final.

public int sumup(final List<Integer> ints);

This emphasizes that the sumup method is not going to change the ints.

Inner class Access

If your anonymous inner class wants to access a variable, the variable should be marked final

  public IPrintName printName(){
    String name;
    return new IPrintName(){
        @Override
        public void printName(){
            System.out.println(name);
        }
    };
}

This class doesn't compile, as the variable name, is not final.

Java SE 8

Effectively final variables are an exception. These are local variables that are written to only once and could therefore be made final. Effectively final variables can be accessed from anonymus classes too.

final static variable

Even though the code below is completely legal when final variable foo is not static, in case of static it will not compile:

class TestFinal {
    private final static List foo;

    public Test() {
        foo = new ArrayList();
    }
}

The reason is, let's repeat again, final variable cannot be reassigned. Since foo is static, it is shared among all instances of class TestFinal. When a new instance of a class TestFinal is created, its constructor is invoked and therefore foo gets reassigned which compiler does not allow. A correct way to initialize variable foo in this case is either:

class TestFinal {
    private static final List foo = new ArrayList();
    //..
}

or by using a static initializer:

class TestFinal {
    private static final List foo;
    static {
        foo = new ArrayList();
    }
    //..
}

final methods are useful when base class implements some important functionality that derived class is not supposed to change it. They are also faster than non-final methods, because there is no concept of virtual table involved.

All wrapper classes in Java are final, such as Integer, Long etc. Creators of these classes didn't want that anyone can e.g. extend Integer into his own class and change the basic behavior of Integer class. One of the requirements to make a class immutable is that subclasses may not override methods. The simplest way to do this is to declare the class as final.

volatile

The volatile modifier is used in multi threaded programming. If you declare a field as volatile it is a signal to threads that they must read the most recent value, not a locally cached one. Furthermore, volatile reads and writes are guaranteed to be atomic (access to a non-volatile long or double is not atomic), thus avoiding certain read/write errors between multiple threads.

public class MyRunnable implements Runnable
{
    private volatile boolean active;
 
    public void run(){ // run is called in one thread 
        active = true;
        while (active){
            // some code here
        }
    }
    
    public void stop(){ // stop() is called from another thread
        active = false;
    }
}

static

The static keyword is used on a class, method, or field to make them work independently of any instance of the class.

  • Static fields are common to all instances of a class. They do not need an instance to access them.
  • Static methods can be run without an instance of the class they are in. However, they can only access static fields of that class.
  • Static classes can be declared inside of other classes. They do not need an instance of the class they are in to be instantiated.
public class TestStatic
{
    static int staticVariable;

    static {
        // This block of code is run when the class first loads
        staticVariable = 11;
    }

    int nonStaticVariable = 5;

    static void doSomething() {
        // We can access static variables from static methods
        staticVariable = 10;
    }

    void add() {
        // We can access both static and non-static variables from non-static methods
        nonStaticVariable += staticVariable;
    }

    static class StaticInnerClass {
        int number;
        public StaticInnerClass(int _number) {
            number = _number;
        }

        void doSomething() {
            // We can access number and staticVariable, but not nonStaticVariable
            number += staticVariable;
        }

        int getNumber() {
            return number;
        }
    }
}


// Static fields and methods
TestStatic object1 = new TestStatic();

System.out.println(object1.staticVariable); // 11
System.out.println(TestStatic.staticVariable); // 11

TestStatic.doSomething();

TestStatic object2 = new TestStatic();

System.out.println(object1.staticVariable); // 10
System.out.println(object2.staticVariable); // 10
System.out.println(TestStatic.staticVariable); // 10

object1.add();

System.out.println(object1.nonStaticVariable); // 15
System.out.println(object2.nonStaticVariable); // 10

// Static inner classes
StaticInnerClass object3 = new TestStatic.StaticInnerClass(100);
StaticInnerClass object4 = new TestStatic.StaticInnerClass(200);

System.out.println(object3.getNumber()); // 100
System.out.println(object4.getNumber()); // 200

object3.doSomething();

System.out.println(object3.getNumber()); // 110
System.out.println(object4.getNumber()); // 200

abstract

Abstraction is a process of hiding the implementation details and showing only functionality to the user. An abstract class can never be instantiated. If a class is declared as abstract then the sole purpose is for the class to be extended.

abstract class Car
{
    abstract void tagLine();
}
 
class Honda extends Car
{
    void tagLine()
    {
        System.out.println("Start Something Special");
    }
}
 
class Toyota extends Car
{
    void tagLine()
    {
        System.out.println("Drive Your Dreams");
    }
}

synchronized

Synchronized modifier is used to control the access of a particular method or a block by multiple threads. Only one thread can enter into a method or a block which is declared as synchronized. synchronized keyword works on intrinsic lock of an object, in case of a synchronized method current objects lock and static method uses class object. Any thread trying to execute a synchronized block must acquire the object lock first.

class Shared
{
    int i;
 
    synchronized void SharedMethod()
    {
        Thread t = Thread.currentThread();
 
        for(int i = 0; i <= 1000; i++)
        {
            System.out.println(t.getName()+" : "+i);
        }
    }

    void SharedMethod2()
    {
        synchronized (this)
        {
            System.out.println("Thais access to currect object is synchronize "+this);
        }
    }
}
 
public class ThreadsInJava
{
    public static void main(String[] args)
    {
        final Shared s1 = new Shared();
 
        Thread t1 = new Thread("Thread - 1")
        {
            @Override
            public void run()
            {
                s1.SharedMethod();
            }
        };
 
        Thread t2 = new Thread("Thread - 2")
        {
            @Override
            public void run()
            {
                s1.SharedMethod();
            }
        };
 
        t1.start();
 
        t2.start();
    }
}

transient

A variable which is declared as transient will not be serialized during object serialization.

public transient int limit = 55;   // will not persist
public int b; // will persist

strictfp

Java SE 1.2

strictfp modifier is used for floating-point calculations. This modifier makes floating point variable more consistent across multiple platforms and ensure all the floating point calculations are done according to IEEE 754 standards to avoid errors of calculation (round-off errors), overflows and underflows on both 32bit and 64bit architecture. This cannot be applied on abstract methods, variables or constructors.

// strictfp keyword can be applied on methods, classes and interfaces.

strictfp class A{}

strictfp interface M{}

class A{  
    strictfp void m(){}
}