Java: Анонимный внутренний класс с помощью локальной переменной

Как я могу получить значение userId переданный этому методу в моем анонимном внутреннем подклассе здесь?

public void doStuff(String userID) {
    doOtherStuff(userID, new SuccessDelegate() {
        @Override
        public void onSuccess() {
            Log.e(TAG, "Called delegate!!!! "+ userID);
        }
    });
}

Я получаю эту ошибку:

Не может относиться к идентификатору пользователя непоследней переменной во внутреннем классе, определенном в другом методе

Я вполне уверен, я не могу назначить его финалом, так как это - переменная с неизвестным значением. Я услышал, что этот синтаксис действительно сохраняет объем в некотором роде, таким образом, я думаю, что должен быть прием синтаксиса, который я еще не вполне знаю.

9
задан Alex Wayne 14 July 2010 в 22:21
поделиться

4 ответа

Конечно, вы можете присвоить ему значение final - просто поместите это ключевое слово в объявление параметра:

public void doStuff(final String userID) {
   ...

Я не уверен, что вы имели в виду, что это переменная с неизвестным значением; все, что означает final, это то, что после присвоения переменной значения она не может быть повторно присвоена. Поскольку вы не меняете значение userID в своем методе, нет никаких проблем сделать его конечным в этом случае.

7
ответ дан 4 December 2019 в 10:03
поделиться

Как все здесь уже сказали, локальные переменные должны быть окончательными, чтобы к ним мог получить доступ внутренний класс.

Вот (в основном) почему ... если вы напишете следующий код (длинный ответ, но внизу вы можете получить короткую версию: -):

class Main
{
    private static interface Foo
    {
        void bar();
    }

    public static void main(String[] args)
    {
        final int x;
        Foo foo;

        x = 42;
        foo = new Foo()
        {
            public void bar()
            {
                System.out.println(x);
            }
        };

        foo.bar();
    }
}

компилятор переводит это примерно так :

class Main
{
    private static interface Foo
    {
        void bar();
    }

    public static void main(String[] args)
    {
        final int x;
        Foo foo;

        x = 42;

        class $1
            implements Foo
        {
            public void bar()
            {
                System.out.println(x);
            }
        }

        foo = new $1();
        foo.bar();
    }
}

и затем это:

class Main
{
    private static interface Foo
    {
        void bar();
    }

    public static void main(String[] args)
    {
        final int x;
        Foo foo;

        x = 42;
        foo = new $1(x);
        foo.bar();
    }

    private static class $1
        implements Foo
    {
        private final int x;

        $1(int val)
        {
           x = val;
        }

        public void bar()
        {
            System.out.println(x);
        }
    }
}

и, наконец, это:

class Main
{
    public static void main(String[] args) 
    {
        final int x;
        Main$Foo foo;

        x = 42;
        foo = new Main$1(x);
        foo.bar();
    }
}

interface Main$Foo
{
    void bar();
}

class Main$1
    implements Main$Foo
{
    private final int x;

    Main$1(int val)
    {
       x = val;
    }

    public void bar()
    {
        System.out.println(x);
    }
}

Важным является то, где он добавляет конструктор к $ 1. Представьте, если бы вы могли сделать это:

class Main
{
    private static interface Foo
    {
        void bar();
    }

    public static void main(String[] args)
    {
        int x;
        Foo foo;

        x = 42;
        foo = new Foo()
        {
            public void bar()
            {
                System.out.println(x);
            }
        };

        x = 1;

        foo.bar();
    }
}

Можно было бы ожидать, что foo.bar () распечатает 1, но на самом деле он распечатает 42. Требуя, чтобы локальные переменные были окончательными, такой запутанной ситуации не может возникнуть.

11
ответ дан 4 December 2019 в 10:03
поделиться

объявить метод

public void doStuff(final String userID)

Значение должно быть окончательным, чтобы компилятор мог быть уверен это не меняется. Это означает, что компилятор может привязать значение к внутреннему классу в любое время, не беспокоясь об обновлениях.

Значение в вашем коде не меняется, так что это безопасное изменение.

1
ответ дан 4 December 2019 в 10:03
поделиться

В чем проблема с тем, чтобы сделать его final как в

public void doStuff (final String userID)
1
ответ дан 4 December 2019 в 10:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: