Search code examples
javastaticfinal

Why aren't all final variables static by default?


Why would you ever need a final variable in a non-static context? Does the compiler automatically assign static to all final variables?

Edit: I know the difference between static and final, what I am asking is whether there is any case when you would need final int x instead of static final int x. Why would you need a copy of x in each instance when you cannot modify it?


Solution

  • Keyword final is used when you want to allow to assign value only once at construction time.

    public class Person {
        public final String name;
    
        public Person(String name) {
            this.name = name;
        }
    }
    
    Person p = new Person("a");
    p.name = "newName"; // COMPILE ERROR name is marked as "final" thus can not be changed.
    

    when you would need final int x instead of static final int x?

    Consider these classes:

    public class OriginConstants {
          // static final fields allows to access constants via class accessor i. e. OriginConstants.x (no need to create instance)
          public static final int x = 0;
          public static final int y = 0;
    }
    
    public class ImmutablePoint {
        public final int x;
        public final int y;
    
        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
    
    public class MutablePoint {
        public int x;
        public int y;
    
        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
    

    Examples of usage

    // create immutable point shifted from coordinate system origin by 5
    ImmutablePoint ip = new ImmutablePoint(OriginConstants.x + 5, OriginConstants.y + 5);
    
    // updating point coordinate by 10
    ip.x += 10; // COMPILE ERROR 
    ip.y += 10; // COMPILE ERROR
    
    // we cannot modify final fields, but we can create new instance with shifted coordinates
    ImmutablePoint shiftedIp = new ImmutablePoint(ip.x + 10, ip.y + 10);
    
    // create mutable point shifted from coordinate system origin by 5
    MutablePoint mp = new MutablePoint(OriginConstants.x + 5, OriginConstants.y + 5);
    
    // updating point coordinate by 10
    ip.x += 10; // OK
    ip.y += 10; // OK
    

    I would use immutable points for some coordinates that can not be changed in time. Suppose, we have canvas with height = 100, width = 100. We can create helper constant points as follows:

    public class Canvas {
        public static final int HEIGHT = 100;
        public static final int WIDTH = 100;
    
        // anchor points
        public static final ImmutablePoint topLeft = new ImmutablePoint(0,0);
        public static final ImmutablePoint topRight = new ImmutablePoint(Canvas.WIDTH, 0);
        public static final ImmutablePoint bottomLeft = new ImmutablePoint(0, Canvas.HEIGHT);
        public static final ImmutablePoint bottomRight = new ImmutablePoint(Canvas.WIDTH, Canavas.HEIGHT);
    }
    

    This way we can be sure, that topLeft is always 0,0 and can not be changed by some mistake.