2_6 Доброхотова Л.А. .ppt
- Количество слайдов: 20
IT ШКОЛА SAMSUNG Модуль 2. Объектно-ориентированное программирование Тема 2. 6. Перегрузка методов. Инициализация данных класса
1. Перегрузка методов Java позволяет создавать несколько методов с одинаковыми именами, но разными сигнатурами. Создание метода с тем же именем, но с другим набором параметров называется перегрузкой. Какой из перегруженных методов должен выполняться при вызове, Java определяет на основе фактических параметров. void pr( double a) { Пример использования метода. System. out. println(a); int a = 5; } int [] m = {1, 2, 8, 3} void pr (String a) { String s = "Мир"; System. out. println(a); pr (a) //работает исходный метод } pr (a+s); // 5 мир, работает первая перегрузка void pr(int[] a) { pr (m); // 1 2 8 3 for (int i=0; i<a. length; i++) { pr (m+a); // ошибка System. out. print(a[i]+" ") } System. out. println(); Переменная а не относится к типу double, но её обрабатывает исходный метод, поскольку возможно автоприведение из int в double. В обратном направлении оно невозможно. Если бы } метод имел аргумент типа int, то с его помощью вещественные числа выводить не получилось бы. 2
Метод называется перегруженным, если существует несколько его версий с одним и тем же именем, но с различным списком параметров. Перегрузка реализует «раннее связывние» . Перегрузка может ограничиваться одним классом. Методы с одинаковыми именами, но с различающимися списком параметров и возвращаемыми значениями могут находиться в разных классах одной цепочки наследования и также будут являться перегруженными. Если в последнем случае списки параметров совпадают, то имеет место другой механизм – переопределение метода. Статические методы могут перегружаться нестатическими и наоборот – без ограничений. При вызове перегруженных методов следует избегать ситуаций, когда компилятор будет не в состоянии выбрать тот или иной метод. 3
Например # 1 : вызов перегруженных методов package chapt 04; public class Number. Info { public static void view. Num(Integer i) {//1 System. out. printf("Integer=%d%n", i); } public static void view. Num(int i) {//2 System. out. printf("int=%d%n", i); } public static void view. Num(Float f) {//3 System. out. printf("Float=%. 4 f%n", f); } public static void view. Num(Number n) {//4 System. out. println("Number=" + n); } public static void main(String[] args) { Number[] num = {new Integer(7), 71, 3. 14 f, 7. 2 }; for (Number n : num) view. Num(n); view. Num(new Integer(8)); view. Num(81); view. Num(4. 14 f); view. Num(8. 2); } } Может показаться, что в результате компиляции и выполнения данного кода будут последовательно вызваны все четыре метода, однако в консоль будет выведено: Number=71 Number=3. 14 Number=7. 2 Integer=8 int=81 Float=4, 1400 Number=8. 2 То есть во всех случаях при передаче в метод элементов массива был вызван четвертый метод. Это произошло вследствие того, что выбор варианта перегруженного метода происходит на этапе компиляции и зависит от типа массива num. То, что на этапе выполнения в метод передается другой тип (для первых трех элементов массива), не имеет никакого значения, так как выбор уже был осуществлен заранее. 4
При перегрузке всегда следует придерживаться следующих правил: не использовать сложных вариантов перегрузки; не использовать перегрузку с одинаковым числом параметров; заменять при возможности перегруженные методы на несколько разных методов. 5
2. Конструктор по умолчанию является единственным конструктором без аргументов, который используется для создания объекта”. Если вы создаете класс, который не имеет конструкторов, компилятор автоматически создаст конструктор по умолчанию вместо вас. Например: class Bird { int i; } public class Default. Constructor { public static void main(String[] args) { Bird nc = new Bird(); // по умолчанию! } } ///: ~ Строка new Bird(); создает новый объект и вызывает конструктор по умолчанию, даже не смотря на то, что он не был явно определен. Без этого мы не имели бы метода построения нашего объекта. Однако если вы определили любой конструктор (с аргументами или без них) компилятор не будет синтезировать его за вас: class Bush { Bush(int i) {} Bush(double d) {} 6 }
Теперь, если вы скажете: new Bush(); компилятор заявит, что он не может найти соответствующий конструктор. Это похоже на то, что когда вы не определяете ни одного конструктора, компилятор говорит: “Вы обязаны иметь какой-то конструктор, так что позвольте мне создать его за вас”. Но если вы написали конструктор, компилятор говорит: “Вы написали конструктор, так что вы знаете, что вы делаете; если вы не создали конструктор по умолчанию, это значит, что он вам не нужен”. 7
3. Ключевое слово this Если вы имеете два объекта одного и того же типа, с именами a и b, вы можете задуматься, как вы можете вызвать метод f( ) для этих обоих объектов: class Banana { void f(int i) { /*. . . */ } } Banana a = new Banana(), b = new Banana(); a. f(1); b. f(2); Если есть только один метод с именем f( ), как этот метод узнает, был ли он вызван объектом a или b? Чтобы позволить вам писать код в последовательном объектно-ориентированном синтаксисе, в котором вы “посылаете сообщения объекту”, компилятор выполняет некоторую скрытую от вас работу. Секрет в первом аргументе, передаваемом методу f( ), и который отражает ссылку на объект, с которым происходит манипуляция. Так что эти два вызова метода, приведенные выше, становятся похожи на следующие вызовы: Banana. f(a, 1); Banana. f(b, 2); Это внутренний формат и вы не можете записать эти выражения и дать компилятору доступ к ним, но это дает вам представление об идеи происходящего. 8
Предположим, вы находитесь внутри метода и хотите получить ссылку на текущий объект. Так как эта ссылка передается компилятором в тайне, здесь нет идентификатора для нее. Однако для этих целей существует ключевое слово: this. Ключевое слово this, которое может использоваться только внутри метода, производит ссылку на объект, который вызвал метод. Вы можете трактовать эту ссылку, как и любой другой объект. Примите во внимание, что если вы вызываете метод вашего класса из другого метода вашего класса, вам не нужен this; вы просто вызываете метод. Текущая ссылка this используется автоматически для другого метода. Таким образом, вы можете сказать: class Apricot { void pick() { /*. . . */ } void pit() { pick(); /*. . . */ } } Внутри pit( ), вы могли сказать this. pick( ), но в этом нет необходимости. Компилятор делает это за вас автоматически. Ключевое слово this используется только в тех особых случаях, в которых вам нужно явное использование ссылки на текущий объект. 9
// Простое использование ключевого слова "this". public class Leaf { int i = 0; Leaf increment() { i++; return this; } void print() { System. out. println("i = " + i); } public static void main(String[] args) { Leaf x = new Leaf(); x. increment(). print(); } } ///: ~ Поскольку increment( ) возвращает ссылку на текущий объект через ключевое слово this, множественные операции могут быть легко выполнены над тем же объектом. 10
4. Инициализация различных типов данных Java гарантирует правильную инициализацию переменных перед использованием. Если примитивный тип является членом данного класса, происходящее немного отличается. Так как любой метод может инициализировать или использовать данные, становится не практично заставлять пользователя инициализировать их соответствующим значением перед использованием. Однако также не безопасно оставлять их, заполненными всяким мусором, так каждая переменная - член класса примитивного типа гарантированно получает инициализирующее значение. 11
class Measurement { boolean t; char c; byte b; short s; int i; long l; float f; double d; void print() { System. out. println( "Data type Initial valuen" + "boolean " + t + "n" + "char [" + c + "] "+ (int)c +"n"+ "byte " + b + "n" + "short " + s + "n" + "int " + i + "n" + "long " + l + "n" + "float " + f + "n" + "double " + d); } } public class Initial. Values { public static void main(String[] args) { Measurement d = new Measurement(); d. print(); } } Вот что программа печатает на выходе: Data type Initial value boolean false char [ ] 0 //Значение char - это ноль, который печатается как пробел. byte 0 short 0 int 0 long 0 float 0. 0 double 0. 0 12
Что произойдет, если присвоить переменной начальное значение? Один прямой способ сделать это - это просто присвоить значение в точке определения переменной в классе. Вот определение полей в классе Measurement, который изменен для обеспечения начальных значений: class Measurement { boolean b = true; char c = 'x'; byte B = 47; short s = 0 xff; int i = 999; long l = 1; float f = 3. 14 f; double d = 3. 14159; //. . . 13
Можно инициализировать не примитивные объекты таким же способом. Если Depth - это класс, то можно вставить переменную и инициализировать её следующим образом: class Measurement { Depth o = new Depth(); boolean b = true; //. . . 14
Для обеспечения начального значения можно вызвать метод: class CInit { int i = f(); //. . . } Конечно, этот метод может иметь аргументы, но эти аргументы не могут быть другими членами класса, которые еще не инициализированы. Таким образом, это можно сделать так: class CInit { int i = f(); int j = g(i); } 15
В языке Java массивы являются объектами, поэтому для создания массива как и для создания любого другого объекта используется оператор new. Тип массива может быть либо примитивным (int, double и т. д. ) либо ссылочным (объекты). Объявление массива в Java имеет следующий синтаксис, рассмотренный на примере типа Integer: Integer[] array = new Integer[10]; Либо можно воспользоваться альтернативным синтаксисом: Integer array[] = new Integer[10]; Пока элементы массива не проинициализивароны они содержат ссылку null. Поэтому при попытке обращения к элементу массива содержащему null произойдет ошибка Null. Pointer. Exception. Таким образом перед обращением к элементам массива они должны быть проинициализированы. 16
Инициализация массива можно проводить отдельно после объявления Integer[] arr = new Integer[3]; 1 2 arr[0] = new Integer(1); 3 arr[1] = new Integer(5); 4 arr[2] = new Integer(-5); Так же возможна явная инициализация массива при объявлении 1 Integer[] arr = new Integer[]{new Integer(1), new Integer(5), new Integer(-5)}; Или даже без использования оператора new: 1 Integer[] arr = {new Integer(1), new Integer(5), new Integer(-5)}; Например, для числового массива явная инициализация записывается следующим образом: int i[]={1, 3, 5}; int j[]={}; // эквивалентно new int[0] Следует отметить, инициализируются 0. что элементы массивов примитивных типов по умолчанию 17
Для создания многомерных массивов можно использовать инициализаторы. В этом случае применяется столько вложенных фигурных скобок, сколько требуется: int i[][] = {{1, 2}, null, {3}, {}}; В этом примере порождается четыре объекта. Это, во-первых, массивов длиной 4, а во-вторых, три массива чисел с длинами 2, 1, 0, соответственно. 18
Задачи • Создать статический метод, который будет иметь два целочисленных параметра a и b, и в качестве своего значения возвращать случайное целое число из отрезка [a; b]. C помощью данного метода заполнить массив из 20 целых чисел и вывести его на экран. • Создать метод, который будет сортировать указанный массив по возрастанию любым известным вам способом. • Создать и инициализировать двумерный массив 19
Спасибо!
2_6 Доброхотова Л.А. .ppt