1

So I was playing with java.lang.reflect stuff and tried to make something like this. And here is my problem (maybe a bug):

The code for my method to set the field to true:

private static void setFinalStatic(Field field, Object newValue) throws Exception
{
    field.setAccessible(true);
    Field modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
    field.set(null, newValue);
}

The code where I print it:

setFinalStatic(Boolean.class.getField("FALSE"), true);
System.out.format("%s\n", false);                  //prints true
System.out.println(false);                         //prints false
System.out.format("%s\n", Boolean.FALSE);          //prints true
System.out.println(Boolean.FALSE);                 //prints true
System.out.println(Boolean.FALSE == false);        //prints false
System.out.format("%s\n", Boolean.FALSE == false); //prints true

When you use System.out.format("%s", false) it return "true", as expected but when you use System.out.println(false) it prints "false". And when I tried this System.out.println(Boolean.FALSE == false) it printed "false".

You you please explain this?

Tom
  • 16,842
  • 17
  • 45
  • 54
32byTe
  • 23
  • 1
  • 4
  • 3
    Please consider the types involved, `format` takes an `Object...` parameter, so `false` is boxed to a `java.lang.Boolean` (ie `Boolean.FALSE`), while `println` takes a `boolean` parameter and is used as is. A `boolean` is a different type than a `Boolean`. – Mark Rotteveel Feb 04 '19 at 13:33

2 Answers2

0

when you use System.out.println(false) it prints "false".

This boolean value is never autoboxed, so the change you make via reflection is not relevant.

Here is the call stack:

PrintStream::println(boolean x)
PrintStream::print(boolean b)
String::valueOf(boolean b)

String.valueOf(boolean) is implemented like this:

public static String valueOf(boolean b) {
    return b ? "true" : "false";
}

So the fact that you've changed the constant used by the wrapper class makes no difference. We never use the wrapper class.

And when I tried this System.out.println(Boolean.FALSE == false) it printed "false".

Boolean.FALSE is automatically unboxed to a primitive true. true == false is false.

Michael
  • 41,989
  • 11
  • 82
  • 128
0

There is no bug, Boolean.FALSE that you overridden is used for autoboxing because boolean autoboxing is implemented by compiler silently calling Boolean.valueOf() method with following body:

public static Boolean valueOf(boolean b) {
    return (b ? TRUE : FALSE);
}

In your example boolean parameters passed to methods using Object type e.g. System.out.format(String, Object...) will be subject to autoboxing. They will be affected by your reflective change and false will become true.

Otherwise methods using boolean primitive won't be affected e.g. System.out.println(boolean) and false will stay false.

The two most interesting lines in your example are:

  • System.out.println(Boolean.FALSE == false)

    The compiler is unboxing Boolean.FALSE by calling Boolean.FALSE.booleanValue() which due to your reflection override returns true. Since true == false you get false. This can be confirming by placing a breakpoint in Boolean.booleanValue().

  • System.out.format("%s\n", Boolean.FALSE == false)

    Although you do get false from comparison as per point above, it will be autoboxed into a Boolean to match the System.out.format(String, Object...) method signature. This will output true due to your reflection override.

Karol Dowbecki
  • 43,645
  • 9
  • 78
  • 111