Подтвердить что ты не робот

Val и объект внутри класса scala?

В чем разница между объявлением поля как val, lazy val и object внутри класса scala, как в следующем фрагменте:

class A

class B {
  val a1 = new A      { def foo = 1 }
  object a2 extends A { def foo = 1 }
  lazy val a3 = new A { def foo = 1 }
}
4b9b3361

Ответ 1

В первом, любой введенный код выполняется, как только будет создан класс B. В последнем, однако, пока вы фактически не используете объект, он не будет создан.

Здесь вы можете увидеть разницу:

class A { println("Creating a new A") }
class B {
  val a1 = new A { println("a1"); def foo = 1 }
  object a2 extends A { println("a2"); def foo = 1 }
}

scala> val b = new B
Creating a new A
a1
b: B = [email protected]

scala> b.a2.foo
Creating a new A
a2
res0: Int = 1

Есть также скрытые различия в том, какие имена созданных файлов .class и так; и, конечно, у них разные типы.

Ответ 2

Одно существенное отличие состоит в том, что val может быть переопределен, а объекты не могут.

class C extends B {                           
  override val a1 = new A { def foo = 2 }     
  override object a2 extends A { def foo = 2 }
}

приводит к:

<console>:9: error: overriding object a2 in class B of type object C.this.a2;
object a2 cannot be used here - classes and objects cannot be overridden
override object a2 extends A { def foo = 2 }

Ответ 3

Я не уверен, что aioobe признал значение своего ответа, но разные типы на самом деле представляют собой критическую разницу между vals и objects. В частности, val и lazy val имеют структурный тип (например, A{def foo: Int}), а object имеет одноэлементный тип. В результате вызовы метода foo на val включают отражение, а вызовы метода foo на object не выполняют:

class A

class B {
  val a1 = new A      { def foo = printStack }
  object a2 extends A { def foo = printStack }
  lazy val a3 = new A { def foo = printStack }

  def printStack() = 
     new Exception().getStackTrace take 3 foreach println
}

scala> val b = new B
b: B = [email protected]

scala> b.a1.foo   // the val
line124$object$$iw$$iw$B.printStack(<console>:12)
line124$object$$iw$$iw$B$$anon$1.foo(<console>:7)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

scala> b.a2.foo   // the object
line124$object$$iw$$iw$B.printStack(<console>:12)
line124$object$$iw$$iw$B$a2$.foo(<console>:8)
line128$object$$iw$$iw$.<init>(<console>:9)

scala> b.a3.foo   // the lazy val
line124$object$$iw$$iw$B.printStack(<console>:12)
line124$object$$iw$$iw$B$$anon$2.foo(<console>:9)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

Ответ 4

Я полагаю, что одно отличие состоит в том, что a1 будет иметь один подтип A, а a2 будет другого подтипа A, а именно a2.type.

scala> class A
defined class A

scala> val a1 = new A {def foo = 1}
a1: A{def foo: Int} = [email protected]

scala> object a2 extends A {def foo = 1}
defined module a2

scala> a1
res0: A{def foo: Int} = [email protected]

scala> a2
res1: a2.type = [email protected]

scala> 

Ответ 5

Другим важным отличием является то, что объекты знают свое имя, а val - нет.

Ответ 6

Первое практическое отличие состоит в том, что ленивые vals и объекты ленивы, тогда как vals стремятся.

Основное различие между объектами и ленивыми vals заключается в том, что объект с точки зрения языков считается "одноэлементным", который с точки зрения jvm обычно рассматривается как статический член. Определение объекта в данном примере не может быть переоценено, как показали другие, по той же причине, что статические члены не могут быть переопределены: без привязки к экземпляру нет мыслимого способа поиска виртуальной функции.

object Foo { object Bar extends A; }

не похож на следующий код java:

class Foo { 
  private static class Bar extends A{}
  public static Bar Bar = new Bar;
}

Если в приведенном выше примере, если был определен подкласс C extends Foo, он не сможет переопределить определение Bar. Статический массив экземпляров в Java будет доступен как Foo.Bar. C.Bar не означает то же самое, что (новый C).Bar. Я мог бы быть немного отсюда, я на самом деле не пытался декомпилировать scala код, это просто пример, иллюстрирующий общую концепцию объектов как статических членов.

lazy vals могут быть немного менее эффективными. В прошлый раз, когда я проверил, они были реализованы путем сохранения скрытого поля в классе, который отслеживал, какие ленивые валы были инициализированы. Поддержание этого поля требует блокировки, что может вызвать проблемы с производительностью.

Одним из основных практических различий между ленивым val и объектом является обработка отказа:

Если у меня есть:

class Foo() { throw new Exception("blah!"); }
object Stuff { object Bar extends Foo { val x = "hi" } }
Stuff.Bar
//exception "blah!" thrown.
Stuff.Bar.x
//NoClassDefFoundError: Could not initialize Stuff$Bar$

тогда как если:

object Stuff2 { lazy val Bar = new Foo() { val x = "hi" } }
Stuff2.Bar
// "blah!"
Stuff2.Bar.x
// "blah!"

"NoClassDefFoundError" может быть действительно запутанным, и поскольку он не является исключением, он может разбить код обработки ошибок, который (соответственно) ловит/регистрирует "Исключение", но позволяет распространять ошибки. Я мог бы даже рассмотреть такую ​​ошибку на языке scala, так как этот прецедент на самом деле указывает на исключительное условие, а не на ошибку JVM. Я видел NoClassDefFoundErrors при доступе к объектам, зависящим от внешних ресурсов (например, подключений к базе данных или файлов на диске). Только первый доступ регистрирует основную причину, поэтому для правильной отладки такой проблемы обычно требуется перезапуск сервера приложений.

Ответ 7

Это не структурный тип: val a = new A {def foo = 1}

Создает уникальный анонимный подкласс; a.foo вызывает foo в этом классе.

x здесь структурный тип: def bar (x: {def bass: Int})

x.bass будет интроспекции x (неизвестного типа), чтобы найти метод с именем "бас". Он будет работать с рыбой или музыкальными инструментами.;)

Одно из различий между ленивым val и объектом заключается в следующем:

var someA = (new B).a3
someA = (new B).a3 // ok

var anotherA = (new B).a2
anotherA =  = (new B).a2 // compile error