Использование отражения для доступа к внешнему классу в Scala - PullRequest
4 голосов
/ 06 сентября 2011

В Scala возможно ли использовать отражение для доступа к внешнему классу внутреннего класса?Например:

class A { 
   val inner = new { 
      println(getClass.getConstructors.toList)  
      println(getClass.getDeclaredFields.toList)
   }
}

scala> val a = new A
List(public $line11.$read$$iw$$iw$A$$anon$1($line11.$read$$iw$$iw$A))
List()
a: A = A@45f76fc7

Я думаю, что компилятор Scala где-то сохраняет ссылку на внешний класс, но вы можете видеть здесь, что список полей, напечатанных в конструкторе, пуст.Кроме того, похоже, что конструктор берет ссылку на экземпляр внешнего класса (но сложно сказать наверняка - я не совсем уверен, что здесь происходит).Я также заметил, что в некоторых случаях есть поле $outer, которое, кажется, мне нужно, но оно не всегда там, и я не понимаю этого.

ПОЧЕМУ ???!!! У меня есть внутренний класс, который мне нужен, чтобы создать новый экземпляр использования отражения.Новый экземпляр копируется из существующего экземпляра и должен иметь ту же внешнюю ссылку.

Ответы [ 3 ]

5 голосов
/ 07 сентября 2011

Я не думаю, что вы можете надежно получить родителя, если вы не используете родителя вне конструктора внутреннего класса.Дано:

class X  {
    val str = "xxyy"
    val self = this

    val inner = new {
        override def toString():String = {
            "inner " + self.toString
        }

    }

    override def toString():String = {
        "ima x" + this.str
    }

}

Если вы делаете javap, вы получаете приватное поле $ outer

, но дается:

class X  {
    val str = "xxyy"
    val self = this

    val inner = new {
        println(self)

    }

    override def toString():String = {
        "ima x" + this.str
    }

}

В javap не указано внешнее поле $.

5 голосов
/ 07 сентября 2011

Если вы знаете, что вам это понадобится, то лучше (на данный момент) сделать ссылку явной и полностью избежать отражения:

class A { 
  outerA =>
  val inner = new { 
    val outer = outerA
    println(getClass.getConstructors.toList)  
    println(getClass.getDeclaredFields.toList)
  }
}

Волшебный соус здесь - это собственный тип outerA =>, позволяющийдать уникальное имя для ссылки this.

4 голосов
/ 07 сентября 2011

Внутренние классы ДОЛЖНЫ иметь ссылку на их внешний класс. Это делается неявно JVM. В следующем примере вызов new InnerClass() переводится как new InnerClass(this). Экземпляр OuterClass хранится в поле $outer во внутреннем классе, к которому можно получить доступ с использованием этого синтаксиса OuterClass.this.

class OuterClass {

   val str = "abcde";
   val inner = new InnerClass();

   class InnerClass {
      def printStr() {
          println(OuterClass.this.str);
      }
   }
}

Чтобы создать новый экземпляр InnerClass с помощью отражений, у вас должна быть ссылка на экземпляр OuterClass. Чтобы создать новый экземпляр, сделайте следующее.

val outer = new OuterClass;

val newInner = outer.inner.getClass.getDeclaredConstructor(classOf[OuterClass])
        .newInstance(outer);

В качестве дополнения я бы сказал, что необходимость создания нового внутреннего класса с помощью отражений звучит как довольно плохая практика кодирования. Только OuterClass должен когда-либо видеть экземпляры InnerClass и поэтому должен быть готов к любой ситуации, когда ему может понадобиться создать новый экземпляр InnerClass. Если другие классы имеют видимость InnerClass, то он должен быть преобразован в свой собственный класс.

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