– Cześć, Amigo! Kilka dni temu mówiłem Ci o przeciążaniu metod. Wszystko zrozumiałeś?
– Tak. Pamiętam. Każda klasa musi być unikalna. Metoda składowa jest unikalna, jeśli klasa nie ma innej metody o tej samej nazwie i tych samych typach parametrów (kolejność parametrów również ma znaczenie).
– Bardzo dobrze. Widzę, że dobrze nauczyłeś się tej lekcji. Dzisiaj chcę tylko odrobinę poszerzyć Twoją wiedzę na ten temat. Jak myślisz, jaka metoda będzie wywoływana w każdym przypadku?
class Cat
{
public static void print(int n)
{
System.out.println(n);
}
public static void print(short n)
{
System.out.println(n);
}
public static void print(Integer n)
{
System.out.println(n);
}
public static void print(String s)
{
System.out.println(s);
}
public static void main(String[] args)
{
Cat.print(1);
Cat.print((byte)1);
Cat.print("1");
Cat.print(null);
}
}
– Trudno powiedzieć.
– W pierwszym przypadku 1 to typ int. Mamy 100% dopasowanie do metody, która przyjmuje typ int. Zostanie wywołana pierwsza metoda void print(int n).
W drugim przypadku nie mamy metody, która przyjmuje typ byte. Ale są dwie metody, które przyjmują typ short i int. W oparciu o zasady rozszerzania typu, byte zostanie najpierw rozszerzony do typu short, a następnie do typu int. W rezultacie wywołana zostanie metoda void print(short n).
W trzecim przypadku mamy 100% dopasowanie do metody, która przyjmuje typ String. Zostanie wywołana metoda void print(String s).
Czwarty przypadek jest niejednoznaczny. Null nie ma określonego typu. Kompilator odmówi kompilacji tego kodu. W tym przypadku musimy napisać Cat.print((Integer)null), aby wywołać trzecią metodę i Cat.print((String)null), aby wywołać metodę czwartą.
– To bardzo przydatne informacje. Dziękuję.
– Chciałbym zwrócić Twoją uwagę na to, że przy określaniu właściwej metody do wywołania typy mogą się tylko rozszerzać. Nie mogą się zawężać. Przeanalizuj ten przykład:
class Cat
{
public static void print(short n)
{
System.out.println(n);
}
public static void print(Integer n)
{
System.out.println(n);
}
public static void main(String[] args)
{
Cat.print((byte)1);
Cat.print(1);
}
}
W pierwszym przypadku typ byte zostanie rozszerzony do typu short i zostanie wywołana pierwsza metoda: void print(short n).
W drugim przypadku nastąpi domyślne rozszerzenie konwersji z int na Integer, a następnie zostanie wywołana druga metoda: void print(Integer n).
– Tego się nie spodziewałem.
– Teraz to dopiero się zdziwisz:
Kod Java | Opis |
---|---|
|
W pierwszym przypadku typ int zostanie rozszerzony do typu Integer. Ponieważ nie ma żadnej metody dla typu Integer, najbardziej odpowiednią metodą (i właśnie ona zostanie wywołana) jest metoda void print(Object o)
W drugim przypadku nie będzie żadnych błędów w kompilacji i, co nie jest do końca oczywiste, zostanie wywołana metoda void print(String s). |
– Amigo, mam nadzieję, że rozumiesz to, że w takich przypadkach najlepiej jest określić operator rzutowania typów (jak to zrobiliśmy z «(byte)»), aby wiedzieć dokładnie, która metoda zostanie wywołana.
– Nigdy nie przypuszczałem, że z przeciążania metod mogą wyniknąć jakieś problemy. I zjawiłeś się Ty. Dziękuję, Raszi! Będę miał to na uwadze.
GO TO FULL VERSION