9

userIdここで匿名の内部サブクラスでこのメソッドに渡された値を取得するにはどうすればよいですか?

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

このエラーが発生します:

別のメソッドで定義された内部クラス内の非最終変数userIDを参照することはできません

値が不明な変数であるため、finalとして割り当てることはできないと確信しています。この構文は何らかの形でスコープを保持していると聞いていたので、まだよくわからない構文のトリックがあるに違いないと思います。

4

5 に答える 5

10

ここにいる他の誰もが言っているように、ローカル変数は、内部クラスによってアクセスされるために final でなければなりません。

これが(基本的に)その理由です...次のコードを書くと(長い答えですが、最後に短いバージョンを取得できます:-):

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 を出力します。ローカル変数を final にする必要があるため、この混乱する状況は発生しません。

于 2010-07-14T22:46:30.323 に答える
7

確かに最終として割り当てることができます-そのキーワードをパラメーターの宣言に入れるだけです:

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

値が不明な変数であるということについて、あなたが何を意味しているのかわかりません。最終的な意味は、変数に値が割り当てられると、割り当てできないということだけです。メソッド内で userID の値を変更していないため、この場合は final にしても問題ありません。

于 2010-07-14T22:25:12.137 に答える
2

Java 8 では、これが少し変更されました。実質的に finalである変数にアクセスできるようになりました。Oracleドキュメントからの関連するスニペットと例(強調鉱山):

ただし、Java SE 8 以降では、ローカル クラスは、 final または実質的に finalである囲んでいるブロックのローカル変数およびパラメーターにアクセスできます 。

実質的に最終: 初期化後に値が変更されない非最終変数またはパラメーターは、実質的に最終です。

たとえば、変数numberLengthが final として宣言されておらず、強調表示された割り当てステートメントをPhoneNumber コンストラクターに追加するとします。

PhoneNumber(String phoneNumber) {
    numberLength = 7; // From Kobit: this would be the highlighted line
    String currentNumber = phoneNumber.replaceAll(
        regularExpression, "");
    if (currentNumber.length() == numberLength)
        formattedPhoneNumber = currentNumber;
    else
        formattedPhoneNumber = null;
}

この代入ステートメントにより、変数numberLengthは実質的に final ではなくなります。その結果、Java コンパイラは、内部クラスが変数PhoneNumberにアクセスしようとする場所で、「内部クラスから参照されたローカル変数は最終または実質的に最終でなければなりません」のようなエラー メッセージを生成し ます。numberLength

if (currentNumber.length() == numberLength)

Java SE 8 以降では、メソッドでローカル クラスを宣言すると、メソッドのパラメーターにアクセスできます。たとえば、PhoneNumber ローカル クラスで次のメソッドを定義できます。

public void printOriginalNumbers() {
    System.out.println("Original numbers are " + phoneNumber1 +
        " and " + phoneNumber2);
}

メソッドはパラメータにprintOriginalNumbersアクセスし 、メソッドのphoneNumber1phoneNumber2validatePhoneNumber

于 2015-01-19T01:03:11.847 に答える
1

のようにすることの何が問題なのですfinal

public void doStuff (final String userID)
于 2010-07-14T22:26:00.870 に答える
1

メソッドを宣言する

public void doStuff(final String userID)

コンパイラが値が変更されていないことを確認できるように、値は final である必要があります。これは、コンパイラが更新を気にすることなく、いつでも内部クラスに値をバインドできることを意味します。

コード内の値は変更されないため、これは安全な変更です。

于 2010-07-14T22:26:16.097 に答える