undefined

Przeciążanie metod | część 2

Podstawy Java
Poziom 5 , Lekcja 3
Dostępny

– 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?

Kod
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:

Kod
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
 class Cat
{
 public static void print(Object o)
 {
  System.out.println(o);
 }
 public static void print(String s)
 {
  System.out.println(s);
 }

 public static void main(String[] args)
 {
  Cat.print(1);
  Cat.print(null);
 }
}
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.

Komentarze (2)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
Pighost Poziom 16 Warszawa
23 października 2020
I have question to Cat.print(null); In first example you saying that there is an error in compilation and we will need to cast (String)null or (Integer)null or any type to make it works... but on the other hand in last example you say that there are no compilation errors in Cat.print(null); and the default choice will be --> void print(String s) <-- method. How is that correct?