Почему должен делегация другого конструктора происходить сначала в конструкторе Java?

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

  1. Вместо использования DriverManagerDataSource определите пул соединений с фиксированным числом соединений. Для упрощения используйте SingleConnectionDataSource, который не будет выполнять какую-либо проверку соединения по займу. Это не заводская настройка, но в вашем тесте будет меньше движущихся частей.
  2. Вместо SELECT * укажите только те столбцы, которые вам нужны. Разрешение * может отличаться для JDBC и клиента командной строки, лучше всего удалить это неизвестное.
  3. Используйте подготовленные операторы с client_no = ? вместо client_no=" + clientNo конкатенации. Это приведет к улучшению кэширования плана запросов при проверке различных номеров клиентов.

Обратите внимание, что JVM требует более 10 000 вызовов метода для запуска JIT-компиляции и оптимизации. Если у вас есть простой main(), который не нагревает JVM, код будет медленнее. Клиент командной строки уже скомпилирован в собственный код.

35
задан Community 23 May 2017 в 12:10
поделиться

8 ответов

я нахожу это довольно ужасным, но это помогает мне постараться не копировать код. Следующее - то, что я хотел бы сделать, но это недопустимо в Java...

Вы могли также работать вокруг этого ограничения при помощи статического метода фабрики, который возвращает новый объект:

public static BigFraction valueOf(BigDecimal d)
{
    // computate numerator and denominator from d

    return new BigFraction(numerator, denominator);
}

, С другой стороны, Вы могли обмануть путем вызова частного статического метода сделать вычисления для конструктора:

public BigFraction(BigDecimal d)
{
    this(computeNumerator(d), computeDenominator(d));
}

private static BigInteger computeNumerator(BigDecimal d) { ... }
private static BigInteger computeDenominator(BigDecimal d) { ... }        
14
ответ дан Zach Scrivena 27 November 2019 в 07:12
поделиться

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

Редактирование: Подводя итоги, когда конструктор производного класса "выполняется" перед этим () вызов, применяются следующие моменты.

  1. членские переменные не могут быть затронуты, потому что они недопустимы, прежде чем базовые классы будут созданы.
  2. Аргументы только для чтения, потому что стековый фрейм не был выделен.
  3. к Локальным переменным нельзя получить доступ, потому что стековый фрейм не был выделен.

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

10
ответ дан Tmdean 27 November 2019 в 07:12
поделиться

"Мое предположение - то, что, пока конструктора не вызвали для каждого уровня heierarchy, объект находится в недопустимом состоянии. Небезопасно для JVM выполнить что-либо на нем, пока это не было полностью создано".

На самом деле, возможно создать объекты в Java, не звоня каждый конструктор в иерархии, хотя не с new ключевое слово.

, Например, когда сериализация Java создает объект во время десериализации, она вызывает конструктора первого несериализуемого класса в иерархии. Таким образом, когда java.util. HashMap десериализовывается, сначала java.util. Экземпляр HashMap выделяется и затем конструктор его первого несериализуемого суперкласса java.util. AbstractMap называют (который в свою очередь называет java.lang. Конструктор Object).

можно также использовать библиотека Objenesis для инстанцирования объектов, не вызывая конструктора.

Или если Вы так склонны, можно генерировать байт-код сами (с ASM или подобный). На уровне байт-кода, new Foo() компиляции к двум инструкциям:

NEW Foo
INVOKESPECIAL Foo.<init> ()V

, Если Вы не хотите вызывать конструктора Foo, можно изменить вторую команду, например:

NEW Foo
INVOKESPECIAL java/lang/Object.<init> ()V

, Но даже затем, конструктор Foo должен содержать вызов к его суперклассу. Иначе загрузчик класса JVM выдаст исключение при загрузке класса, жалобе, что нет никакого вызова к super().

7
ответ дан Esko Luontola 27 November 2019 в 07:12
поделиться

Мой предположение - то, что, пока конструктора не вызвали для каждого уровня heierarchy, объект находится в недопустимом состоянии. Небезопасно для JVM выполнить что-либо на нем, пока это не было полностью создано.

0
ответ дан 27 November 2019 в 07:12
поделиться

Разрешение кода не вызвать супер конструктора сначала повреждает инкапсуляцию - идея, что можно написать код и смочь к , доказывают , что независимо от того, что кто-то еще делает - расширяют его, вызовите его, instansiate он - это всегда будет в допустимом состоянии.

IOW: это не требование JVM как таковое, а требование Науки Аккомпанемента. И важный.

Для решения проблемы, несущественно, Вы используете частные статические методы - они не зависят ни от какого экземпляра:

public BigFraction(BigDecimal d)
{
  this(appropriateInitializationNumeratorFor(d),
       appropriateInitializationDenominatorFor(d));
}

private static appropriateInitializationNumeratorFor(BigDecimal d)
{
  if(d.scale() < 0)
  {
    return d.unscaledValue().multiply(BigInteger.TEN.pow(-d.scale()));
  }
  else
  {
    return d.unscaledValue();
  }
}

, Если Вам не нравится иметь отдельные методы (большая общая логика Вы только хотите выполниться однажды, например), имейте один метод, который возвращает частный небольшой статический внутренний класс, который используется для вызова частного конструктора.

1
ответ дан 27 November 2019 в 07:12
поделиться

Посмотрите он этот путь.

Скажем, что объект состоит из 10 частей.

1,2,3,4,5,6,7,8,9,10

хорошо?

От 1 до 9 находятся в суперклассе, часть № 10 является Вашим дополнением.

Простой не может добавить 10-ю часть, пока предыдущие 9 не завершаются.

Вот именно.

, Если от 1-6 от другого суперкласса, настолько прекрасного, вещью является один отдельный объект, создается в определенной последовательности, это - путь, был разработан .

, Конечно, настоящая причина намного более сложна, чем это, но я думаю, что это было бы в значительной степени отвечать на вопрос.

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

-3
ответ дан OscarRyz 27 November 2019 в 07:12
поделиться

Ну, проблемой является Java, не может обнаружить, какие 'операторы' Вы собираетесь поместить перед вызовом super. Например, Вы могли обратиться к членским переменным, которые еще не инициализируются. Таким образом, я не думаю, что Java будет когда-либо поддерживать это. Теперь, существует много способов работать вокруг этой проблемы такой как при помощи шаблонных методов или фабрики.

0
ответ дан Samuel Edwin Ward 27 November 2019 в 07:12
поделиться

I think several of the answers here are wrong because they assume encapsulation is somehow broken when calling super() after invoking some code. The fact is that the super can actually break encapsulation itself, because Java allows overriding methods in the constructor.

Consider these classes:

class A {
  protected int i;
  public void print() { System.out.println("Hello"); }
  public A() { i = 13; print(); }
}

class B extends A {
  private String msg;
  public void print() { System.out.println(msg); }
  public B(String msg) { super(); this.msg = msg; }
}

If you do

new B("Wubba lubba dub dub");

the message printed out is "null". That's because the constructor from A is accessing the uninitialized field from B. So frankly it seems that if someone wanted to do this:

class C extends A {
  public C() { 
    System.out.println(i); // i not yet initialized
    super();
  }
} 

Then that's just as much their problem as if they make class B above. In both cases the programmer has to know how the variables are accessed during construction. And given that you can call super() or this() with all kinds of expressions in the parameter list, it seems like an artificial restriction that you can't compute any expressions before calling the other constructor. Not to mention that the restriction applies to both super() and this() when presumably you know how to not break your own encapsulation when calling this().

My verdict: This feature is a bug in the compiler, perhaps originally motivated by a good reason, but in its current form it is an artifical limitation with no purpose.

26
ответ дан 27 November 2019 в 07:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: