Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing static variable works Primitive Wrapper but not with Primitive type

I have a situation where I have to change java constant.

I have below code working

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class Main {
    public static final Integer FLAG = 44;

    static void setFinalStatic(Class<?> clazz, String fieldName, Object newValue) throws NoSuchFieldException, IllegalAccessException {
        Field field = clazz.getDeclaredField(fieldName);
        field.setAccessible(true);
        Field modifiers = field.getClass().getDeclaredField("modifiers");
        modifiers.setAccessible(true);
        modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        field.set(null, newValue);
    }

    public static void main(String... args) throws Exception {
        System.out.printf("Everything is %s%n", FLAG);
        setFinalStatic(Main.class, "FLAG", 33);
        System.out.printf("Everything is %s%n", FLAG);
    }
}

If I run above , I get following output:

Everything is 44
Everything is 33

But if I change FLAG variable to int i.e.

public static final int FLAG = 44;

It does not work. The output is :

Everything is 44
Everything is 44

Is there any other way to make it work with Primitive Type int.

like image 818
Makky Avatar asked Apr 24 '14 15:04

Makky


People also ask

Does wrapper class exists for each primitive type?

Each Java primitive has a corresponding wrapper: boolean, byte, short, char, int, long, float, double. Boolean, Byte, Short, Character, Integer, Long, Float, Double.

Which do wrapper object types allow primitive variables to be used in?

The eight primitive data types byte, short, int, long, float, double, char and boolean are not objects, Wrapper classes are used for converting primitive data types into objects, like int to Integer etc.

Which is better primitive or wrapper class in Java?

Generally, choose primitive types over wrapper classes unless using a wrapper class is necessary. Primitive Types will never be slower than Wrapper Objects, however Wrapper Objects have the advantage of being able to be null.

What is the difference between primitive type and wrapper type?

A primitive type is a predefined data type provided by Java. A Wrapper class is used to create an object; therefore, it has a corresponding class. A Primitive type is not an object so it does not belong to a class. The wrapper class objects allow null values.

How to convert primitive types to objects in Java?

Here, we have used the valueOf () method of the Wrapper class ( Integer, Double, and Boolean) to convert the primitive types to the objects. To learn about wrapper classes in Java, visit Java Wrapper Class.

Which of the following wrapper classes are immutable in Java?

Explanation: All primitive wrapper classes (Integer, Byte, Long, Float, Double, Character, Boolean and Short) are immutable in Java, so operations like addition and subtraction create a new object and not modify the old. The below line of code in the modify method is operating on wrapper class Integer, not an int.

What is wrapper class in Java?

Wrapper classes can be used to achieve that task. The difference between wrapper class and primitive type in Java is that wrapper class is used to convert a primitive type to an object and object back to a primitive type while a primitive type is a predefined data type provided by the Java programming language.


2 Answers

From jls-4.12.4

A variable of primitive type or type String, that is final and initialized with a compile-time constant expression (§15.28), is called a constant variable.

Also section 13.1 says (emphasis mine)

3..References to fields that are constant variables (§4.12.4) are resolved at compile time to the constant value that is denoted. No reference to such a field should be present in the code in a binary file (except in the class or interface containing the field, which will have code to initialize it). Such a field must always appear to have been initialized (§12.4.2); the default initial value for the type of such a field must never be observed.

It means that compile-time constant expression from constant variables will be put directly in code by compiler (it will be inlined) not read from final reference at runtime.

For instance if you execute main method from Bar class

class Foo{
    static{
        System.out.println("test if class will be loaded");
    }
    public static final int x = 42;
}

class Bar{
    public static void main(String [] args){
        System.out.println(Foo.x);
    }
}

you will see no output from static block of Foo class which means Foo class hasn't been loaded, which means that value of Foo.x didn't come from this class. In fact Bar was compiled this way

class Bar{
    public static void main(String [] args){
        System.out.println(42); // reference Foo.x will be removed by compiler 
                                // and replaced with actual value because
                                // compiler assumes that value can't/shouldn't
                                // change at runtime
    }
}

So even changing value of Foo.x at runtime will not affect value printed in main method in Bar class.

You can't change that mechanism.


Possible way around would be initializing your final fields with values created at runtime time (they wouldn't exist at compile time, which will prevent them from being compile-time constant expressions). So instead of

public static final String x = "foo";

try

public static final String x = new String("foo");

or in case of primitive types use Unboxing like instead of

public static final int x = 42;

use

public static final int x = new Integer(42);
like image 172
Pshemo Avatar answered Oct 12 '22 23:10

Pshemo


  1. Primitive types get inlined.

  2. In fact even non-primitive constants, when imported into other classes, will be copied, and the import forgotten. So there it will not work either. Only for constant caches, like the string pool, and Integer (Integer.valueOf(13)) caches you may overwrite their values.

like image 27
Joop Eggen Avatar answered Oct 13 '22 00:10

Joop Eggen