Как ответили и здесь : sup>
Самый простой способ ответить на этот вопрос - взглянуть на исходный код java.util.Date
.
Он имеет только 2 нестатических поля (Java 1.7.0_55):
private transient long fastTime;
private transient BaseCalendar.Date cdate;
long
имеет объем памяти 8 байтов, а cdate
является ссылкой на объект, который имеет размер 4 байта. Таким образом, в общей сложности 12 байтов .
Если бы был создан экземпляр cdate
, это могло бы потребовать дополнительных байтов в памяти, но если вы посмотрите и на конструкторы, иногда это даже не будет затронуто, а в других оно будет null
-обработано в конец конструктора, поэтому конечный результат также составляет 12 байт .
Это только для создания Date
. Если вы вызываете методы для Date
(например, Date.toString()
), то будет создавать и сохранять объект в поле cdate
, которое не будет очищено. Поэтому, если вы вызовете определенные методы для Date
, его использование памяти увеличится.
Примечание: Ссылки на объекты могут иметь длину 64 бита на 64-битных JVM, в этом случае использование памяти будет составлять 16 байтов.
Примечание № 2: Также обратите внимание, что это только использование памяти самого объекта Date
. Скорее всего, вы будете хранить его ссылку где-нибудь, например. в массиве или списке или поле в каком-либо другом классе, для которого потребуются дополнительные 4 байта (или, может быть, 8 байтов на 64-битных JVM).
You could do this:
val numer = numerator / gcd(numerator.abs, denominator.abs)
val denom = denominator / gcd(numerator.abs, denominator.abs)
Of course you'd have to do the calculation twice. But then optimizations are often a trade-off between memory/space and execution time.
Maybe there are other ways too, but then the program might get overly complex, and if there's one place where optimization is rarely premature, it's brain power optimization :). For instance, you could probably do this:
val numer = numerator / gcd(numerator.abs, denominator.abs)
val denom = denominator / (numerator / numer)
But it doesn't necessarily make the code more understandable.
(Note: I didn't actually try this, so use at your own risk.)
Сопутствующий объект может обеспечить необходимую гибкость. Он может определять «статические» фабричные методы, заменяющие конструктор.
object Rational{
def apply(numerator: Int, denominator: Int) = {
def gcd(a: Int, b: Int): Int = if(b == 0) a else gcd(b, a % b)
val g = gcd(numerator, denominator)
new Rational(numerator / g, denominator / g)
}
}
class Rational(numerator: Int, denominator: Int) {
require(denominator != 0)
override def toString = numerator + "/" + denominator
// other methods go here, neither access g
}
val r = Rational(10,200)
В рамках фабричного метода можно вычислять и использовать g для получения двух значений конструктора.
В примере Томаса Юнга есть небольшая проблема; он по-прежнему позволяет вам создавать объект Rational с общим термином в числителе и знаменателе - если вы создаете объект Rational с помощью 'new' самостоятельно, а не через сопутствующий объект:
val r = new Rational(10, 200) // Oops! Creating a Rational with a common term
Этого можно избежать, потребовав от клиентского кода всегда используйте сопутствующий объект для создания объекта Rational, сделав неявный конструктор закрытым:
class Rational private (numerator: Int, denominator: Int) {
// ...
}
Вы можете сделать это:
object Rational {
def gcd(a: Int, b: Int): Int =
if(b == 0) a else gcd(b, a % b)
}
class Rational private (n: Int, d: Int, g: Int) {
require(d != 0)
def this(n: Int, d: Int) = this(n, d, Rational.gcd(n.abs, d.abs))
val numer = n / g
val denom = d / g
override def toString = numer + "/" + denom
}
... на самом деле, я не понимаю, как это представляет собой "утечку памяти".
Вы объявляете последнее поле в рамках экземпляра класса, а затем явно удивляетесь что он «торчит». Какого поведения вы ожидали?
Я что-то упустил?
Я наткнулся на эту статью, которая может быть вам полезна: http://daily-scala.blogspot.com/2010/02/temporary-variables-during-object.html
Кажется, вы могли бы написать это:
class Rational(numerator: Int, denominator: Int) {
require(denominator != 0)
val (numer,denom) = {
val g = gcd(numerator.abs, denominator.abs)
(numerator/g, denominator/g)
}
override def toString = numer + "/" + denom
private def gcd(a: Int, b: Int): Int =
if(b == 0) a else gcd(b, a % b)
// other methods go here, neither access g
}