Ответ 1
Короткий ответ
Нет, нет никакого преимущества в производительности. Оба private def
и private[this] def
переводятся в методы private
или public
в байт-коде в зависимости от того, вызывается ли их из другого класса, не зависит от того, какова их видимость в Scala.
Теория
Начнем с того, что Scala спецификация языка говорит о private[this]
:
к нему можно получить доступ только из объекта, в котором он определен. То есть выбор p.M является только законным, если префикс - это или O.это, для некоторого класса O, охватывающего ссылку. Кроме того, применяются ограничения для неквалифицированных частных лиц.
Вы можете видеть, что в спецификации просто сказано, что является синтаксически приемлемым или нет. Оба private
и private[this]
могут вызываться только из экземпляров одного класса или внутренних классов. В байт-коде вы можете дифференцировать доступ только на уровне класса, а не на уровне экземпляра. Поэтому оба варианта должны быть одинаковыми в байт-коде, а Scala устанавливает разницу только во время компиляции.
Основной случай
Сначала рассмотрим простой пример:
class MyClass {
private def privateDef(x: Int) = x
private[this] def privateThisDef(x: Int) = x
}
Это переводится в байт-код как
public class MyClass {
private int privateDef(int);
private int privateThisDef(int);
public MyClass();
}
Как вы можете видеть, оба метода заканчиваются как private
, поэтому нет никакой разницы с точкой зрения JVM (например, в отношении inlining, статической/динамической привязки и т.д.).
Внутренние классы
Как это изменяется при добавлении внутренних классов?
class MyClass {
private def privateDef(x: Int) = x
private[this] def privateThisDef(x: Int) = x
class MyInnerClass{
MyClass.this.privateDef(1)
MyClass.this.privateThisDef(2)
}
}
Это переводится на
public class MyClass {
public int MyClass$$privateDef(int);
public int MyClass$$privateThisDef(int);
public MyClass();
}
public class MyClass$MyInnerClass {
public final MyClass $outer;
public MyClass MyClass$MyInnerClass$$$outer();
public MyClass$MyInnerClass(MyClass);
}
Вы можете видеть, что на этот раз оба метода в MyClass
являются общедоступными, поэтому внутренний класс может их вызвать. Опять же, нет разницы между private
и private[this]
.
Спутники
Scala добавляет еще один частный случай, когда частный метод может быть вызван из другого класса - когда вы вызываете частный метод из сопутствующего объекта в соответствующем классе. Сопутствующим объектом для MyClass
будет отдельный класс с именем MyClass$
в байт-коде. Вызов метода private
в компаньоне пересекает границы классов, и поэтому такой метод будет общедоступным в байт-коде.
Вы не можете вызвать метод private[this]
вне компаньона, но это просто синтаксическое ограничение. Где бы вы ни выбрали между private
и private[this]
, результат будет таким же в байте-коде.
Варс
Поведение для варов кажется несколько иным, чем для defs. Этот класс
class MyClass {
private var privateVar = 0
private[this] var privateThisVar = 0
private var privateVarForInner = 0
private[this] var privateThisForInner = 0
class MyInnerClass{
privateVarForInner = 1
privateThisForInner = 1
}
}
скомпилирован в
public class MyClass {
private int privateVar;
private int privateThisVar;
private int MyClass$$privateVarForInner;
public int MyClass$$privateThisForInner;
// ...
}
Затем внутренний класс использует setter для privateVar
и доступ к полю для privateThisVar
. Я не знаю, почему именно так выглядит скайлак, я не нашел ничего в спецификации. Возможно, это что-то конкретное для реализации.
Изменить: по запросу я создал небольшой тест JMH сравнивающий производительность получения и установки private var
и private[this] var
. Результат? Все операции ≈ 10⁻⁸
соответствуют JMH. Разница незначительна, и случай с внутренними классами и var
редок в любом случае.