Java: руководство для начинающих (ЛП)
Java: руководство для начинающих (ЛП) читать книгу онлайн
"Java: руководство для начинающих"составлено Гербертом Шилдтом, автором популярных во всем мире книг по языкам программирования, таким образом, чтобы читатель смог быстро овладеть основными навыками программирования на Java. Полностью обновленное по версии Java Platform, Standard Edition 7, пятое издание этого учебного пособия начинается с рассмотрения самых основ, включая компилирование и выполнение простых программ на Java. Затем в нем описываются ключевые слова и синтаксические конструкции, составляющие основу Java как языка программирования. Далее следует изложение самых передовых языковых средств Java, включая обобщения и многопоточное программирование. И завершается книга введением в библиотеку Swing. Представленный в книге учебный и справочный материал позволяет легко и быстро научиться программировать на Java. Для облегчения процесса изучения Java книга построена следующим образом: - Основные навыки и понятия. Каждая глава начинается с перечня основных навыков и понятий, которые предстоит усвоить читателю. - Обращение к знатоку. Во врезках под этим заголовком даются полезные рекомендации в форме вопросов и ответов. - Примеры для опробования. Это примеры небольших проектов, наглядно показывающие, как применять приобретенные знания и навыки на практике. - Упражнения для самопроверки. В конце каждой главы приводятся контрольные вопросы и задания для проверки прочности усвоенного материала. - Подробные комментарии к примерам программ. Все примеры программ в этой книге снабжены подробными комментариями, описывающими демонстрируемые языковые средства и приемы программирования на Java. В этом учебном пособии для начинающих программировать на Java подробно рассмотрены все основные средства данного языка программирования: типы данных, операторы, циклы, классы, интерфейсы, методы, исключения, обобщения, пакеты, основные библиотеки классов, средства многопоточного программирования, потоки ввода-вывода, перечисления, апплеты и документирующие комментарии. Применение всех этих языковых средств Java на практике наглядно демонстрируется в небольших проектах для самостоятельного опробования. Книга снабжена массой полезных советов авторитетного автора и множеством примеров программ с подробными комментариями, благодаря которым они становятся понятными любому читателю независимо от уровня его подготовки. А для проверки прочности приобретенных знаний и навыков в конце каждой главы приводятся контрольные вопросы и задания.
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
В приведенном выше примере программы объект t2 конструируется на основании объекта tl, и поэтому они идентичны. Результат выполнения данной программы выглядит следующим образом:Info for tl:Triangle is rightWidth and height are 8.0 and 12.0Area is 48.0Info for t2:Triangle is rightWidth and height are 8.0 and 12.0Area is 48.0
Обратите внимание на конструктор класса Triangle, код которого приведен ниже.// построить один объект на основании другого объектаTriangle(Triangle ob) { // Передача ссылки на объект Triangle конструктору класса TwoDShape. super(ob); style = ob.style;}
В качестве параметра данному конструктору передается объект Triangle, который затем с помощью вызова super () передается конструктору TwoDShape, как показано ниже.// Построение одного объекта на основании другого объекта.TwoDShape(TwoDShape ob) { width = ob.width; height = ob.height;}
Следует заметить, что конструктор TwoDshape () должен получить объект типа TwoDShape, но конструктор Triangle () передает ему объект типа Triangle. Тем не менее никаких недоразумений не возникает. Ведь, как пояснялось ранее, переменная ссылки на суперкласс может ссылаться на объект производного от него подкласса. Следовательно, конструктору TwoDShape () можно передать ссылку на экземпляр подкласса, производного от класса TwoDShape. Конструктор TwoDShape () инициализирует лишь те части передаваемого ему объекта подкласса, которые являются членами класса TwoDShape, и поэтому не имеет значения, содержит ли этот объект дополнительные члены, добавленные в производных подклассах.Переопределение методов
В иерархии классов часто присутствуют методы с одинаковой сигнатурой и одинаковым возвращаемым значением как в суперклассе, так и в подклассе. В этом случае говорят, что метод суперкласса переопределяется в подклассе. Если переопределяемый метод вызывается из подкласса, то всегда выбирается тот вариант метода, который определен в подклассе. А вариант метода, определенный в суперклассе, скрывается. Рассмотрим в качестве примера следующий фрагмент кода:// Переопределение метода,class А { int i, j; A(int a, int b) { i = a; j = b; } // отобразить переменные i и j void show() { System.out.println("i and j: " + i + " " + j) ; }}class В extends A { int k; В(int a, int b, int c) { super(a, b); k = c; } // Отображение переменной к. Данный метод переопределяет // метод show() из класса А. void show() { System.out.println("k: " + к); }}class Override { public static void main(String args[]) { В subOb = new B(l, 2, 3) ; subOb.show(); // вызвать метод show() из класса В }}
Выполнение этого фрагмента кода дает следующий результат:к: 3
Когда метод show () вызывается для объекта типа В, выбирается вариант этого метода, определенный в классе В. Таким образом, вариант метода show () в классе В переопределяет вариант одноименного метода, объявленный в классе А.
Если требуется обратиться к исходному варианту переопределяемого метода, т.е. тому, который определен в суперклассе, следует воспользоваться ключевым словом super. Например, в приведенном ниже варианте класса В из метода show () вызывается вариант того же метода, определенный в суперклассе. При этом отображаются все переменные экземпляра.class В extends А { int к; В(int a, int b, int с) { super (а, Ь); к = с; } void show() { // Использование ключевого слова super для // вызова метода show(), определенного в классе А. super.show(); System.out.println("k: " + k); }}
Если подставить новый вариант метода show () в предыдущую версию рассматриваемого здесь фрагмента кода, результат его выполнения изменится и будет иметь следующий вид:i and j: 1 2k: 3
В данном случае super. show () — это вызов метода show (), определенного в суперклассе.
Переопределение метода происходит только в том случае, если сигнатуры переопределяемого и переопределяющего методов совпадают. В противном случае происходит обычная перегрузка методов. Рассмотрим следующую видоизмененную версию предыдущего примера:/* Методы с разными сигнатурами не переопределяются,а перегружаются. */class А { int i, j; A(int a, int b) { i = a; j = b; } // отобразить переменные i и j void show() { System.out.println("i and j: " + i + " " + j) ; }}// создать подкласс путем расширения класса Лclass В extends А { int к; В (int a, int b, int с) { super(а, Ь); к = с; } // Сигнатуры данного метода и метода show() из класса А отличаются, // поэтому вместо переопределения происходит перегрузка метода. void show(String msg) { System.out.println(msg + k); }}class Overload { public static void main(String args[]) { В subOb = new В(1, 2, 3); subOb.show("This is k: "); // вызывается метод show() из класса В subOb.show(); // вызывается метод show() из класса А }}
Выполнение этого фрагмента кода дает следующий результат:This is k: 3i and j: 1 2
На этот раз в варианте метода show () из класса В предусмотрен строковый параметр. И благодаря этому сигнатура данного метода отличается от сигнатуры метода show () из класса А, для которого параметры не предусмотрены. В результате переопределение метода не происходит.Поддержка полиморфизма
в переопределяемых методахПримеры из предыдущего раздела демонстрируют переопределение методов, но по ним трудно судить, насколько богатые возможности предоставляет этот механизм. В самом деле, если переопределение методов используется только для соблюдения соглашений о пространствах имен, то его можно рассматривать как любопытную, но почти бесполезную особенность языка программирования. Но это совсем не так. Переопределение методов лежит в основе одного из наиболее эффективных языковых средств Java: динамической диспетчеризации методов, представляющей собой механизм вызова переопределяемых методов, когда выбор конкретного метода осуществляется не на этапе компиляции, а в процессе выполнения программы. Динамическая диспетчеризация методов имеет очень большое значение, поскольку именно с ее помощью принцип полиморфизма реализуется на стадии выполнения программ на Java.
Прежде всего напомним один очень важный принцип: переменная ссылки на суперкласс может ссылаться на объект подкласса. В Java этот принцип используется для вызова переопределяемых методов во время выполнения. Если переопределяемый метод вызывается по ссылке на суперкласс, то исполняющая система Java определяет по типу объекта, какой именно вариант метода следует вызвать, причем делает это во время выполнения программы. Если ссылки указывают на разные типы объектов, то и вызываться будут разные версии переопределенных методов. Иными словами, вариант переопределенного метода для вызова определяет не тип переменной, а тип объекта, на который она ссылается. Так, если суперкласс содержит метод, переопределяемый в подклассе, то вызывается метод, соответствующий тому типу объекта, на который указывает переменная ссылки на суперкласс.
Ниже приведен простой пример, демонстрирующий динамическую диспетчеризацию методов в действии.// Демонстрация динамической диспетчеризации методов.class Sup { void who() { System.out.println("who() in Sup"); }}class Subl extends Sup { void who() { System.out.println("who() in Subl"); }}class Sub2 extends Sup { void who() { System.out.println("who() in Sub2"); }}class DynDispDemo { public static void main(String args[]) { Sup superOb = new Sup(); Subl subObl = new Subl(); Sub2 sub0b2 = new Sub2(); Sup supRef; // В каждом из приведенных ниже вызовов конкретный вариант // метода who () выбирается во время выполнения по типу // объекта, на который делается ссылка. supRef = superOb; supRef.who(); supRef = subObl; supRef.who(); supRef = sub0b2; supRef.who(); }}
Результат выполнения данной программы выглядит следующим образом:who() in Supwho () in Sublwho() in Sub2
В данном примере программы определяются суперкласс Sup и два его подкласса Subl и Sub2. В классе Sup объявляется метод who (), переопределяемый в его подклассах. В методе main () создаются объекты типа Sup, Subl и Sub2. Там же объявляется переменная supRef ссылки на объект типа Sup. Затем переменной supRef в методе main () поочередно присваиваются ссылки на объекты разного типа, и далее эти ссылки используются для вызова метода who (). Как следует из результата выполнения данной программы, вызываемый вариант метода who () определяется типом объекта, на который ссылается переменная supRef в момент вызова, а не типом самой этой переменной.Причины для переопределения методов
