Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Зачем вводят слово super?


Автор: bogomol 18.3.2007, 12:13
  И для чего оно нужно? И к чему прикладывается?

Автор: powerOn 18.3.2007, 12:28
Цитата(bogomol @  18.3.2007,  12:13 Найти цитируемый пост)
И для чего оно нужно? И к чему прикладывается? 

для обращения к полю/методу суперкласса (класса родителя).

Код

public class A extends B
{
    public A()
    {
    }
    
    public void meth()
    {
        super.meth();
        System.out.println("A::meth()");
    }
    
    public static void main(String[] args)
    {
        A a = new A();
        a.meth();
    }
}

class B
{
    public void meth()
    {
        System.out.println("B::meth()");
    }
}

Автор: JUncle 18.3.2007, 14:49
Цитата(powerOn @  18.3.2007,  12:28 Найти цитируемый пост)
для обращения к полю/методу суперкласса (класса родител

И к конструкторам.

Код

public class Base {

  public Base() {
     ...
  }

  public Base(String parameter) {
     ...
  }
}


public class Derived extends Base {

  public Derived() {
     super(); //  вызов суперконструктора - строго до остальных действий в этом конструкторе
     ... //  остальные действия
  }

  public Derived(String parameter) {
     super(parameter);  // аналогично
     ... //  остальные действия
  }
}

Автор: JVM 19.3.2007, 10:53
Цитата(powerOn @  18.3.2007,  12:28 Найти цитируемый пост)
для обращения к полю/методу суперкласса (класса родителя).

Цитата(JUncle @  18.3.2007,  14:49 Найти цитируемый пост)
И к конструкторам.


Мне кажется это очевидно, но не дает полного ответа на вопрос bogomol. Ну обратились мы к методы супер класса, ну и что? Зачем это надо? Не рискну отвечать на этот вопрос - не тот уровень знаний - но думаю ответ лежит в основах ООП: наследование, полиморфизм, переопределение и т.д. и понимание, и уж тем более правильное применение придет не сразу.

Уж коль начали обсуждать эту тему задам и свой вопрос, на который ответ пока не нашел(может плохо искал ...)
Есть два класса - один супер класс, другой дочерний:
Код

package p1;

class A1{
    
    A1(){
    testSuper();
  }

  void testSuper(){
    System.out.println("Method testSuper() class A1");
  }

Код

package p1;

class A2 extends A1{

  A2(){
    super();//Вот здесь не понятно. Вызываю конструктор супер класса, но вызывается метод testSuper() не супер класса А1,
 а дочернего класса А2. Почему?
    testSuper();
  }

  void testSuper(){
    System.out.println("Method testSuper() class A2");
  }

  public static void main(String[] args){
    new A2();
  }
}


Не могу понять почему, при вызове конструктора супер класса А1 вызывается метод дочернего класса А2? Подскажите или где можно найти ответ?

Автор: y3u 19.3.2007, 11:12
все же очевидно. Во-первых, ты забыл перечислить еще один из главных принципов ООП - это инкапсуляция, собственно, этот термин и отвечает на твой вопрос. Мы часть логики скрываем (инкапсулируем, прячем в капсулу) в одних классах, чтобы потом эту логику ненароком не поломать в наследниках или еще где (ну и чтобы часть логики была доступна в определенных местах кода), для этого есть, в частности, приватные методы. А еще есть такая штука, как протектед методы, которые доступны в наследниках, которые мы можем перекрывать (ну и пэкедж локал методы тоже). Если нам надо при перекрытии метода сохранить логику метода предка, то надо обязательно дернуть внутри него super.thisOwerwrittenMethod(), иначе произойдет то, что произошло в этом "непонятном" примере выше - метод будет переопределен в потомке "полностью". А в примере выше, мы вызываем конструктор предка, в данном случае, чтобы отработал функционал по его созданию, но, реально, мы создаем инстанс объекта A2, где метод у нас уже переопределен, поэтому все правильно.

Автор: JVM 19.3.2007, 13:00
Т.е. к тому, что переопределено из дочерних классов нельзя обратиться?
 smile наверно это логично, а то зачем тогда переопределял

Автор: y3u 19.3.2007, 13:08
Цитата(JVM @  19.3.2007,  13:00 Найти цитируемый пост)
Т.е. к тому, что переопределено из дочерних классов нельзя обратиться?
  наверно это логично, а то зачем тогда переопределял 


почему это нельзя, как раз, таки, можно - используя super smile

Автор: JVM 19.3.2007, 16:11
y3u, еще раз посмотрел свой пример и твой ответ. Мне все же не понятно, почему вызывается метод дочернего класса из конструктора. Ведь когда создается объект А2
Код

new A2();

вызывается конструктор класса А2, который сначала должен вызвать конструктор супер класса, т.е. объект класса А2 еще не создан, а его метод уже вызывается. Почему? Что не понимаю?

Результат рабты программы
Код

Method testSuper() class A2
Method testSuper() class A2

Автор: y3u 19.3.2007, 17:02
а почему ты решил, что он еще не создан? smile Он-то как раз создан, но не доинициализирован. Если б это был конструктор с параметрами мы бы тут как раз сетили бы поля объекта, читай - инициализировали. Так что объект уже есть, и метод у него переопределен...

Автор: JVM 19.3.2007, 18:03
Цитата(y3u @  19.3.2007,  17:02 Найти цитируемый пост)
Если б это был конструктор с параметрами мы бы тут как раз сетили бы поля объекта, читай - инициализировали.

Не понял ...

Автор: y3u 19.3.2007, 18:44
Код

public class MyClass {
    private Integer f1;
    private Integer f2;

    public MyClass (Integer f1, Integer f2) {
        this.f1 = f1;
        this.f2 = f2;
    }
}

public class MyClass2 extends MyClass {
   private String f3;

   public MyClass2(Integer f1, Integer f2, String f3) {
       super(f1, f2);
       this.f3 = f3;
   }
}

Автор: JVM 20.3.2007, 09:51
y3u, я тебя не понял. Что ты этим примером хочешь сказать? Ведь из супер класса не вызывается никакой дочерний объект ...

Цитата(y3u @  19.3.2007,  17:02 Найти цитируемый пост)
Если б это был конструктор с параметрами мы бы тут как раз сетили бы поля объекта, читай - инициализировали. Так что объект уже есть, и метод у него переопределен...

Что такое 'сетили'?
Может есть статья, в которой объясняется мой вопрос?

Автор: y3u 20.3.2007, 12:18
Цитата(JVM @  20.3.2007,  09:51 Найти цитируемый пост)
y3u, я тебя не понял. Что ты этим примером хочешь сказать? Ведь из супер класса не вызывается никакой дочерний объект ...


во-первых, из супер класса, как ты его назвал, никакие дочерние объекты не вызываются... наследование - это отношение is as, т.е. это тот же самый объект, но несколько иной, никогда не проектируют код, чтобы предок вызывал наследников, для работы с объектом нужного типа из множества однотипных существует класс паттернов проектирования Factory.
Во-вторых, я отвечаю на конкретный вопрос. Задай подробно вопрос, постараюсь ответить конкретно, я отвечал на 
Цитата(JVM @  19.3.2007,  18:03 Найти цитируемый пост)
Если б это был конструктор с параметрами мы бы тут как раз сетили бы поля объекта


Цитата(JVM @  20.3.2007,  09:51 Найти цитируемый пост)
Что такое 'сетили'?

от слова Set/Setup - есть такое понятие, как дерево объектов, все объекты в Java наследуются от Object, когда отрабатывает конструктор, то объект конструируется снизу вверх, сначала создаются объеты по иерархии, начиная с Object, таким образом, к моменту создания твоего A2, объект A1 уже создан, но не до конца, так сказать... это я к слову о 
Цитата(JVM @  19.3.2007,  16:11 Найти цитируемый пост)
вызывается конструктор класса А2, который сначала должен вызвать конструктор супер класса, т.е. объект класса А2 еще не создан, а его метод уже вызывается.

А вызывается метод класса A2, потому что ты пишешь 
Цитата(JVM @  19.3.2007,  10:53 Найти цитируемый пост)
 public static void main(String[] args){
    new A2();
  }

ты создаешь инстанс объекта A2, где метод УЖЕ переопределен, поэтому он и дергается из конструктора A1 уже переопределенный

Автор: JVM 20.3.2007, 13:59
Цитата(y3u @  20.3.2007,  12:18 Найти цитируемый пост)
А вызывается метод класса A2, потому что ты пишешь 

Цитата(JVM @  19.3.2007,  10:53 )
 public static void main(String[] args){
    new A2();
  }


ты создаешь инстанс объекта A2, где метод УЖЕ переопределен, поэтому он и дергается из конструктора A1 уже переопределенный

Вот это объяснение мне и не понятно. Как может быть переопределен метод в объекте который еще не создан(объект)?

Мои рассуждения следующие. Когда я создаю объект А2
Код

new A2();
вызывается конструктор
Код

  A2(){
    super();
    testSuper();
  }

в котором вызывается конструктор родительского класса
Код

A1(){
    testSuper();
  }
т.к. объект класса А2 еще не создан, то вызывается метод не А2.testSuper(), а А1. testSuper().

Но судя по результату работы программы в этой логике есть ошибка. Мне как раз и хочется понять где она?

Автор: sergejzr 20.3.2007, 14:04
Цитата(JVM @  20.3.2007,  12:59 Найти цитируемый пост)
Но судя по результату работы программы в этой логике есть ошибка. Мне как раз и хочется понять где она? 

Методы как таковые в обьектах не существуют. Есть только указатели на них. Эти указатели расставлены естественно ещё до вызова конструктора в зависимости от имени класса. Поэтому все они указывают на методы от A2.

Добавлено @ 14:05 
если хочешь метод родителя, то ссылайся super.testSuper();

Автор: Omut 23.3.2007, 11:58
Цитата

Может есть статья, в которой объясняется мой вопрос?

Может это поможет
http://bruceeckel.by.ru/tij/Chapter07.html#Heading246
Вот оттуда
Цитата

В качестве результата, хорошие руководящие принципы для конструктора "Делайте в конструкторе настолько меньше, насколько можете и если это возможно, то не вызывайте никаких методов". Существует только один тип методов, которые безопасно вызывать из конструктора, это final методы из базового класса. (Это так же применимо и к private методам, которые так же являются final.) Они не могут быть переопределены и поэтому не могут преподнести своего рода сюрприз

Автор: pompei 18.10.2007, 13:00
Цитата(JVM @ 20.3.2007,  13:59)
Мои рассуждения следующие. Когда я создаю объект А2
Код

new A2();
вызывается конструктор
Код

  A2(){
    super();
    testSuper();
  }

в котором вызывается конструктор родительского класса
Код

A1(){
    testSuper();
  }
т.к. объект класса А2 еще не создан, то вызывается метод не А2.testSuper(), а А1. testSuper().

Но судя по результату работы программы в этой логике есть ошибка. Мне как раз и хочется понять где она?

Объясняю популярно: конструктор - это не метод который сам создаёт объект. Конструктор - это почти обычный (не статический) метод, который отличается от обычного метода тем, что:
1) вызывается особым образом (через оператор new);
2) не наследуется (т.е. конструктор делать обязательно нужно, а если Вы не указали ни одного конструктора, то компилятор создаёт конструктор по умолчанию);
3) между оператором new и вызовом конструктора происходят какие-то действия.

Теперь давайте посмотрим что детально происходит в строчке: new A2();

1) создаётся инстанция объекта класса A2 с пустыми полями (т.е. = null);
2) вызываются инициализаторы этих полей, если они есть;
3) вызывается метод-конструктор (как видите объект уже давно существует, а конструктор его только вызвался);
4) возвращается ссылка на объект, если небыло необработанных исключений.

Важно знать, что если первой строкой не стоит оператор super( ... ) в конструкторе, то там по умолчанию ставиться оператор super(); т.е. вызывается родительский конструктор по умолчанию. Если у родителя нет конструктора по умолчанию (или он не доступен), то генерируется исключение уровня компиляции.

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

Важно знать, что если Вы определили какой-нибудь конструктор, отличный от конструктора по умолчанию, то конструктор по умолчанию НЕ создаётся.

Если Вы знаете C++, то знайте, что в яве все методы виртуальные - это значит, что когда вызывается метод, то компилятор смотрит на класс самого объекта, а не на класс переменной.
Например:
A a = new B();
a.f() - f вызывается у B.
А если у класса объекта нет такого метода, то этот метод ищется у его родителей в последовательности: отец, дедушка, прадедушка и т.д. (на самом деле там ни какого поиска нет, всё работает быстро, но пока можно думать что там все методы при их вызове ищуться описанным образом)

Теперь посмотрим что же происходить в нашем случае:
1) Создаётся инстанция объекта класса А2
2) Вызывается конструктор А2
3) вызывается конструктор А1 (потому что есть super)
4) вызывается родительский к А1 конструктор по умолчанию
5) этот конструктор отрабатывает и управление возвращается к конструктору А1
6) в конструкторе А1 вызывается у объекта this метод с именем testSuper
7) т.к. this - это ссылка на объект класса А2, то поиск метода начинается с А2 - сразу находиться и вызывается метод А2.testSuper и в качестве аргумента this передается ему наш объект.
8) дорабатывает конструктор А1
9) управление возвращается в конструктор А2
10) у объекта this вызывается метод с именем testSuper
11) т.к. this - это ссылка на объект класса А2, то поиск метода начинается с А2 - сразу находиться и вызывается метод А2.testSuper и в качестве аргумента this передается ему наш объект.
12) дорабатывает конструктор А2
13) возвращается наш объект.

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

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)