5

外部クラスからiにアクセスする方法は?

  HashSet<Integer> hs=new HashSet<Integer>(){
        int i=30;
    };

私はこのようにそれを行うことができます

int k=new HashSet<Integer>(){
    int i=30;
}.i;

しかし、「i」を取得すると、ハッシュセットのインスタンスを取得できません。両方を取得する方法はありますか?好奇心からの質問です。実用的なアプリケーションはあまりありません。実行できるかどうかを知りたいだけです。 。

4

6 に答える 6

7

解決策 1: オブジェクト登録システム

提示された 2 つのスニペットは、基本的に、作成したばかりの匿名クラス インスタンスへの参照を格納するか、そのカスタム フィールドにすぐにアクセスするかの選択を行いました。一方を行うと、他方を行う能力が失われるように思われます。

妥協を実現する 1 つの方法は、オブジェクト登録システムを用意し、匿名クラスでインスタンス初期化子( JLS 8.6 ) を使用してこのシステムに自己登録することです。

Object[]以下は、単純な登録システムを使用した単純な概念実証です。

    final Object[] registrar = { null };
    int k = new HashSet<Integer>(){
        { registrar[0] = this; }
        int i= 666;
    }.i;
    Set<Integer> set = (Set<Integer>) registrar[0];

    System.out.println(k); // 666
    System.out.println(set.getClass().isAnonymousClass()); // true

基本的に 1-element を使用し、匿名クラスのインスタンス初期化子で、この配列Object[]に「登録」します。thisこれは単なる概念実証であることに注意してください。本番コードでは、これよりも堅牢で型安全なオブジェクト登録システムを使用します。


解決策 2: タプル

このアプローチは、匿名クラスに複数の「フィールド」がある場合にうまく機能します。それらをすべてtupleにパックするだけthisで、匿名クラスにへの参照が含まれていることを確認してください。

Object[]タプルを使用した簡単な概念実証は次のとおりです。

    Object[] tuple = new HashSet<Integer>(){
        Object[] tuple = { this, 666, 13, "XXX", "OMG ABUZE" };
    }.tuple;
    Set<Integer> set = (Set<Integer>) tuple[0];
    set.add(null);
    System.out.println(set.getClass().isAnonymousClass()); // true
    System.out.println(Arrays.toString(tuple));
    // [[null], 666, 13, XXX, OMG ABUZE]

本番コードでCustomTupleは、よりオブジェクト指向でタイプセーフなクラスを使用します。これは、「メソッドが 2 つの値を返すにはどうすればよいか」という問題に対する類似の解決策であることに注意してください。これらの情報をすべて取得する 1 つの値を返すだけです。

于 2010-08-18T07:43:24.917 に答える
5

救助への反省、私は推測します:

HashSet<Integer> hs = new HashSet<Integer>() {
    int i = 30;
};
int i = hs.getClass().getDeclaredField("i").getInt(hs);
System.out.println(i);

PSそれを書いた後、私はちょっと汚い感じがします。

于 2010-08-18T07:31:14.383 に答える
2

あなたがそれについて考えるとき、それは理にかなっています。

表現

new HashSet<Integer>(){
    int i=30;
}

は 型java.util.HashSetで、java.util.HashSetというフィールドがないiため、

new HashSet<Integer>(){
   int i=30;
}.i

コンパイルされません。別の言い方をすれば、複合式を分割して、 の結果がnew変数に代入されるようにしてから、xを呼び出しますx.i。コンパイルxできるようにするには、どの型を指定できますか? x.iそのような型名はありません。匿名クラスです。

これは、無名クラスの「欠点」です。無名クラスは、拡張される型に存在するメンバーのみを有意にオーバーライドできます。新しいメンバーを追加すると、リフレクション経由でのみアクセスできます。

于 2010-08-18T07:29:10.347 に答える
1

私はあなたができるとは思わない。変数の型を匿名型として宣言することはできません1。ただし、メソッド内に名前付きクラスを導入できます。

import java.util.*;

public class Test
{
    public static void main(String[] args)
    {
        class Foo extends Hashtable
        {
            int i = 30;
        }

        Foo f = new Foo();
        System.out.println(f.i);
    }
}

これは恐ろしい (本当に、本当に恐ろしい)もので、プロダクション コードで使用されているのを見たことはないと思いますが、動作します


1 C# はこれを回避しvarます。コンパイラは初期化式を使用して変数の型を決定します。Java の匿名型は C# の匿名型とは多少異なりますが、Java に のようなものがある場合var、コードは機能すると思います。

于 2010-08-18T07:27:19.600 に答える
0

ええと、私の考えでは、反省の方法は常にありますが、それは少しやり過ぎのように思えます。

クラスを匿名の方法に設定すると、あなた以外の方法はわかりません。

于 2010-08-18T07:26:45.000 に答える
0

匿名の内部クラスはその目的のために設計されていないため、私が覚えていることから、それを行う方法はありません。必要に応じて、「通常の」内部クラスを作成できます。

于 2010-08-18T07:28:46.207 に答える