Брюс Эккель - Философия Java3
- Название:Философия Java3
- Автор:
- Жанр:
- Издательство:неизвестно
- Год:неизвестен
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Брюс Эккель - Философия Java3 краткое содержание
Философия Java3 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Создание нового дерева высотой 3 м.
Дерево высотой 3 м.
Перегруженный метод: Дерево высотой 3 м.
Создание нового дерева высотой 4 м.
Дерево высотой 4 м.
Перегруженный метод: Дерево высотой 4 м.
Сажаем росток
*///:-
Объект Tree (дерево) может быть создан или в форме ростка (без аргументов), или в виде «взрослого растения» с некоторой высотой. Для этого в классе определяются два конструктора; один используется по умолчанию, а другой получает аргумент с высотой дерева.
Возможно, вы захотите вызывать метод info() несколькими способами. Например, вызов с аргументом-строкой info(String) используется при необходимости вывода дополнительной информации, а вызов без аргументов info() — когда дополнений к сообщению метода не требуется. Было бы странно давать два разных имени методам, когда их схожесть столь очевидна. К счастью, перегрузка методов позволяет использовать одно и то же имя для обоих методов.
Различение перегруженных методов
Если у методов одинаковые имена, как Java узнает, какой именно из них вызывается? Ответ прост: каждый перегруженный метод должен иметь уникальный список типов аргументов.
Если немного подумать, такой подход оказывается вполне логичным. Как еще различить два одноименных метода, если не по типу аргументов?
Даже разного порядка аргументов достаточно для того, чтобы методы считались разными (хотя описанный далее подход почти не используется, так как он усложняет сопровождение программного кода):
// initialization/OverloadingOrder.java // Перегрузка, основанная на порядке // следования аргументов import static net.mindview util Print.*;
public class OverloadingOrder {
static void f(String s, int i) {
print("String- " + s + ". int: " + i).
}
static void f(int i. String s) {
printCint. " + i + String: " + s):
}
public static void main(String[] args) { f("Сначала строка", 11); f(99. "Сначала число").
}
} /* Output
String Сначала строка, int: 11 int 99. String. Сначала число *///.-
Два метода f() имеют одинаковые аргументы с разным порядком следования, и это различие позволяет идентифицировать метод.
Перегрузка с примитивами
Простейший тип может быть автоматически приведен от меньшего типа к большему, и это в состоянии привнести немалую путаницу в перегрузку. Следующий пример показывает, что происходит при передаче примитивного типа перегруженному методу:
//: ini ti alizati on/Pri mi ti veOverloadi ng.java // Повышение примитивных типов и перегрузка, import static net mindview.util.Print.*;
public class PrimitiveOverloading {
void fl(char x) { printnb("fl(char)"); }'
void fKbyte x) { printnbCf l(byte)"). }
void fKshort x) { printnb("fl(short)"); }
void fl(int x) { printnbCfKint)"): }
void fKlong x) { printnD("fl(long)"); }
void fl(float x) { printnb("fl(float)"); }
void f1(double x) { printnb("fl(double)"); }
void f2(byte x) { printnb("f2(byte)"); }
void f2(short x) { printnb("f2(short)"'); }
void f2(int x) { printnb("f2(int)"); }
void f2(long x) { printnb("f2(long)"); }
void f2(float x) { printnb("f2(float)"); }
void f2(double x) { printnb("f2(double)"); }
void f3(short x) { printnb("f3(short)"); }
void f3(int x) { printnb("f3(int)")} void f3(long x) { printnb("f3(long) M); } void f3(float x) { printnb("f3(float)"); } void f3(double x) { printnb("f3(double)"); }
void f4(int x) { printnb("f4(int)"); } void f4(long x) { printnb("f4(long)"); } void f4(float x) { printnb("f4(float)"); } void f4(double x) { printnb("f4(double)"); }
void f5(long x) { printnb("f5(long)"); } void f5(float x) { printnb("f5(float)"); } void f5(double x) { printnb("f5(double)"); }
void f6(float x) { printnb("f6(float)"); } void f6(double x) { printnb("f6(double)"); }
void f7(double x) { printnb("f7(double)"); }
void testConstValО {
printnb("5: ");
fl(5);f2(5);f3(5);f4(5);f5(5).f6(5);f7(5);print();
}
void testCharO {
char x = 'x'; printnbC'char: ");
fl(x) ;f2(x) ;f3(x) ;f4(x) ;f5(x) ;f6(x) ;f7(x); print ();
}
void testByteO {
byte x = 0;
System.out.println("параметр типа byte:"); fl(x):f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
}
void testShortO {
short x = 0; printnb("short: ");
fl(x):f2(x):f3(x):f4(x);f5(x):f6(x);f7(x);print():
}
void testlntO {
int x = 0: printnbC'int: "):
fl(x) ;f2(x) ;f3(x) :f4(x) :f5(x) ;f6(x) ;f7(x); print ():
}
void testLongO {
long x = 0; printnbC'long:");
fl(x):f2(x):f3(x):f4(x):f5(x):f6(x):f7(x);print();
}
void testFloatO {
float x = 0:
System.out.pri nt1n("f1 oat:");
fl(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);print();
}
void testDoubleO {
double x = 0: printnb("double:"):
fl(x) ;f2(x) ;f3(x) ;f4(x) ;f5(x) ;f6(x) ;f7(x) ;print();
}
public static void main(String[] args) { PrimitiveOverloading p =
/new PrimitiveOverloadingO; p.testConstValО. p.testCharO; p.testByteО; p testShortO; p.testlntO; p.testLongO; p testFloatO; p.testDoubleO;
}
} /* Output:
5: fl(int) f2(int) f3(int) f4(int) f5(long) f6(float) f7(double) char: fl(char) f2(int) f3(int) f4(int) f5(long) f6(float) f7(double) byte: fl(byte) f2(byte) f3(short) f4(int) f5(long) f6(float) f7(double) short: fl(short) f2(short) f3(short) f4(int) f5(long) f6(float) f7(double) int: fl(int) f2(int) f3(int) f4(int) f5(long) f6(float) f7(double) long: fl(long) f2(long) f3(long) f4(long) f5(long) f6(float) f7(double) float: fl(float) f2(float) f3(float) f4(float) f5(float) f6(float) f7(double) double- fl(double) f2(double) f3(double) f4(double) f5(double) f6(double) f7(double) *///:-
Если вы рассмотрите результат работы программы, то увидите, что константа 5 трактуется как int, поэтому если есть перегруженный метод, принимающий аргумент типа int, то он и используется. Во всех остальных случаях, если имеется тип данных, «меньший», чем требуется для существующего метода, то этот тип данных повышается соответственным образом. Только тип char ведет себя несколько иначе по той причине, что, если метода с параметром char нет, этот тип приводится сразу к типу int, а не к промежуточным типам byte или short.
Что же произойдет, если ваш аргумент «больше», чем аргумент, требующийся в перегруженном методе? Ответ можно найти в модификации рассмотренной программы:
//: с04:Demotion.java
// Понижение примитивов и перегрузка.
import com.bruceeckel.simpletest.*;
public class Demotion {
static Test monitor = new TestO;
void fl(char x) { System.out.println("fl(char)"); }
void fKbyte x) { System out.println("fl(byte)"), }
void f 1(short x) { System.out.printlnC'fKshort)"); }
void fl(int x) { System.out.printlnC'fKint)"); }
void fKlong x) { System.out.printlnC'f 1(long)"); }
void fKfloat x) { System.out.println("fl(float)"); }
void f 1(double x) { System.out printlnC'fKdouble)"); }
void f2(char x) { System.out.println("f2(char)"); } void f2(byte x) { System.out.println("f2(byte)"); } void f2(short x) { System.out.println("f2(short)"). } void f2(int x) { System.out println("f2(int)"): } void f2(long x) ♦{ System.out.println("f2( 1 ong)"); }
void f2(float x) { System.out.println("f2(float)"); } продолжение &
124Глава 5 • Инициализация и завершение
System out println("f3(char)"), System out.pri nt1n("f3(byte)"); { System.out.pri ntln("f3(short)") System out.println("f3(int)"), } System.out.pri nt1n("f3(1ong)");
System.out.println("f4(char)"); System.out.println("f4(byte) M). { System.out println("f4(short)") System.out.println("f4(int)"); }
System.out println("f5(char)"); System out println("f5(byte)"); { System.out.pri ntln("f5(short)")
System out.pri nt1n("f6(char)"). System.out.pri ntln("f6(byte)"),
void f3(char х) void f3(byte х) void f3(short x) void f3(int x) { void f3(long x)
void f4(char x) void f4(byte x) void f4(short x) void f4(int x) {
void f5(char x) void f5(byte x) void f5(short x)
void f6(char x) void f6(byte x)
void f7(char x)
void testDouble(
System.out.println("f7(char)"), }
{
double x = 0;
System.out printlnC'napaMeip типа double:"); fl(x);f2((float)x);f3((long)x).f4((int)x), f5((short)x);f6((byte)x);f7((char)x);
}
public static void main(String[] args) { Demotion p = new DemotionO; p.testDoubleO; monitor.expect(new StringC] {
"параметр типа double: "fl(double)", "f2(float)", "f3(long)", "f4(int)\ "f5(short)", "f6(byte)", "f7(char) M
} ///:-
Здесь методы требуют сужения типов данных. Если ваш аргумент «шире», необходимо явно привести его к нужному типу. В противном случае компилятор выведет сообщение об ошибке.
Перегрузка по возвращаемым значениям
Вполне логично спросить, почему при перегрузке используются только имена классов и списки аргументов? Почему не идентифицировать методы по их возвращаемым значениям? Следующие два метода имеют одинаковые имена и аргументы, но их легко отличить друг от друга:
void f() {} int f() {}
Такой подход прекрасно сработает в ситуации, в которой компилятор может однозначно выбрать нужную версию метода, например: int х = f(). Однако возвращаемое значение при вызове метода может быть проигнорировано; это часто называется вызовом метода для получения побочного эффекта , так как метод вызывается не для естественного результата, а для каких-то других целей. Допустим, метод вызывается следующим способом:
Читать дальшеИнтервал:
Закладка: