Передача конечных переменных анонимным классам

В конечная переменная передается анонимному классу через конструктор, Джон Скит упомянул, что переменные передаются в экземпляр анонимного класса через автогенерированный конструктор. Почему бы мне не увидеть конструктора, использующего отражение в этом случае:

public static void main(String... args) throws InterruptedException {
final int x = 100;
new Thread() {
    public void run() {
        System.out.println(x);      
        for (Constructor<?> cons : this.getClass()
                .getDeclaredConstructors()) {
            StringBuilder str = new StringBuilder();
            str.append("constructor : ").append(cons.getName())
                    .append("(");
            for (Class<?> param : cons.getParameterTypes()) {
                str.append(param.getSimpleName()).append(", ");
            }
            if (str.charAt(str.length() - 1) == ' ') {
                str.replace(str.length() - 2, str.length(), ")");
            } else
                str.append(')');
            System.out.println(str);
        }
    }

}.start();
Thread.sleep(2000);

}

Вывод:

100
constructor : A$1()

Ответ 1

Вот что ваша программа выводит в мою систему:

100
constructor : A$1()

Итак, существует конструктор. Однако он без параметров. От взгляда на разборку происходит то, что компилятор выясняет, что ему не нужно передавать x в run(), поскольку его значение известно во время компиляции.

Если я изменил код так:

public class A {

    public static void test(final int x) throws InterruptedException {
        new Thread() {
            public void run() {
                System.out.println(x);
                for (Constructor<?> cons : this.getClass()
                        .getDeclaredConstructors()) {
                    StringBuilder str = new StringBuilder();
                    str.append("constructor : ").append(cons.getName())
                            .append("(");
                    for (Class<?> param : cons.getParameterTypes()) {
                        str.append(param.getSimpleName()).append(", ");
                    }
                    if (str.charAt(str.length() - 1) == ' ') {
                        str.replace(str.length() - 2, str.length(), ")");
                    } else
                        str.append(')');
                    System.out.println(str);
                }
            }

        }.start();
        Thread.sleep(2000);
        }

    public static void main(String[] args) throws InterruptedException {
        test(100);
    }

}

Созданный конструктор теперь:

constructor : A$1(int)

Единственным аргументом является значение x.

Ответ 2

В этом случае это потому, что 100 является константой. Это запекается в ваш класс.

Если вы измените x следующим образом:

final int x = args.length;

... тогда вы увидите Test$1(int) на выходе. (Это несмотря на то, что он явно не объявлен. И да, захват большего количества переменных добавляет параметры конструктору.)