{"id":28528,"date":"2024-08-05T05:00:00","date_gmt":"2024-08-05T03:00:00","guid":{"rendered":"https:\/\/sii.pl\/blog\/?p=28528"},"modified":"2024-12-04T13:48:51","modified_gmt":"2024-12-04T12:48:51","slug":"python-vs-java-podstawowe-roznice-w-podejsciu-do-programowania-obiektowego","status":"publish","type":"post","link":"https:\/\/sii.pl\/blog\/python-vs-java-podstawowe-roznice-w-podejsciu-do-programowania-obiektowego\/","title":{"rendered":"Python vs. Java \u2013 podstawowe r\u00f3\u017cnice w podej\u015bciu do programowania obiektowego"},"content":{"rendered":"\n<p>Zar\u00f3wno Python, jak i Java, to j\u0119zyki programowania ciesz\u0105ce si\u0119 w ostatnich latach nies\u0142abn\u0105c\u0105 popularno\u015bci\u0105. Nie dziwi zatem fakt, i\u017c du\u017ce grono os\u00f3b uto\u017csamia programowanie ze znajomo\u015bci\u0105 w\u0142a\u015bnie jednego z nich. Dotyczy to szczeg\u00f3lnie os\u00f3b znajduj\u0105cych si\u0119 na pocz\u0105tku swojej drogi w bran\u017cy IT i kt\u00f3rym przysz\u0142o zmierzy\u0107 si\u0119 z pytaniem: <em>\u201eOd czego zacz\u0105\u0107 i <strong>jaki j\u0119zyk programowania b\u0119dzie najlepszy na start?<\/strong>\u201d<\/em> Nie ma tutaj prostej odpowiedzi i jedyn\u0105 s\u0142uszn\u0105 wydaje si\u0119 by\u0107 \u2013 a jak\u017ce \u2013 <em>\u201eto zale\u017cy\u201d<\/em> \ud83d\ude09<\/p>\n\n\n\n<p>Oba j\u0119zyki maj\u0105 swoje zalety i wady oraz dziedziny, w kt\u00f3rych sprawdzaj\u0105 si\u0119 lepiej lub gorzej, dlatego w tym wpisie chcia\u0142bym przybli\u017cy\u0107 <strong>kilka cech, kt\u00f3re odr\u00f3\u017cniaj\u0105 Pythona od Javy (i na odwr\u00f3t)<\/strong> i kt\u00f3re szczeg\u00f3lnie zwr\u00f3ci\u0142y moj\u0105 uwag\u0119 podczas nauki. Nie b\u0119d\u0119 tutaj jednak skupia\u0142 si\u0119 na r\u00f3\u017cnicach, kt\u00f3re s\u0105 widoczne go\u0142ym okiem (jak np.: sk\u0142adnia czy szerokie om\u00f3wienie dost\u0119pnych typ\u00f3w danych), a przede wszystkim na <strong>koncepcjach charakteryzuj\u0105cych oba j\u0119zyki<\/strong> w kontek\u015bcie programowania zorientowanego obiektowo.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Przetwarzanie kodu \u017ar\u00f3d\u0142owego<\/strong><\/h2>\n\n\n\n<p>Wykonanie napisanego przez nas programu w obu j\u0119zykach odbywa si\u0119 na innych zasadach.<\/p>\n\n\n\n<p>W <strong>Pythonie<\/strong> mamy do czynienia z tzw. interpreterem, przez co j\u0119zyk ten jest okre\u015blany mianem j\u0119zyka interpretowanego. Uruchomienie programu wi\u0105\u017ce si\u0119 z tym, \u017ce kod \u017ar\u00f3d\u0142owy jest czytany linijka po linijce w czasie rzeczywistym. Mo\u017ce wi\u0119c doj\u015b\u0107 do sytuacji, i\u017c fragment programu wykona si\u0119 poprawnie, a dopiero, gdy interpreter napotka b\u0142\u0105d, dalsza egzekucja zostanie przerwana.<\/p>\n\n\n\n<p>W <strong>Javie<\/strong> taka sytuacja jest niemo\u017cliwa i aby uzyska\u0107 dzia\u0142aj\u0105cy program, kod \u017ar\u00f3d\u0142owy musi zosta\u0107 najpierw w ca\u0142o\u015bci poddany procesowi kompilacji, czyli zamianie na tzw. kod bajtowy (ang. <em>bytecode<\/em>). Dopiero je\u015bli kompilacja si\u0119 powiedzie (tj. nie zostan\u0105 zidentyfikowane \u017cadne b\u0142\u0119dy, np. dotycz\u0105ce niepoprawnie zadeklarowanych typ\u00f3w), program jest gotowy do uruchomienia przez maszyn\u0119 wirtualn\u0105 Javy (ang. <em>Java Virtual Machine, JVM<\/em>).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Zalety i wady<\/strong> j\u0119zyk\u00f3w<\/h3>\n\n\n\n<p>Atutem program\u00f3w napisanych w j\u0119zykach interpretowanych jest to, \u017ce s\u0105 \u0142atwiej przenoszalne, gdy\u017c w przeciwie\u0144stwie do program\u00f3w wymagaj\u0105cych kompilacji, nie zale\u017c\u0105 od specyficznej platformy, na kt\u00f3rej chcemy je uruchamia\u0107. Umo\u017cliwiaj\u0105 one r\u00f3wnie\u017c szybsze prototypowanie oraz niemal natychmiastowe uruchamianie i testowanie aplikacji, co nie pozostaje bez znaczenia w przypadku konieczno\u015bci wprowadzenia zmian w kodzie.<\/p>\n\n\n\n<p>Niestety, brak kompilacji oraz specyfika Pythona jako j\u0119zyka \u0142atwego do zrozumienia i modyfikacji znacznie u\u0142atwia, zazwyczaj niepo\u017c\u0105dany, <em>reverse engineering<\/em>. Fakt posiadania niemal pe\u0142nego dost\u0119pu do kodu \u017ar\u00f3d\u0142owego programu wymusza wi\u0119c konieczno\u015b\u0107 stosowania dodatkowych zabezpiecze\u0144, np. w formie tzw. zaciemniania kodu (ang. <em>obfuscating<\/em>).<\/p>\n\n\n\n<p>Kod bajtowy Javy ma w tym aspekcie wyra\u017an\u0105 przewag\u0119. Trudno\u015b\u0107 wynikaj\u0105ca z potrzeby jego dekompilacji oraz p\u00f3\u017aniejszej czasoch\u0142onnej analizy znacznie wp\u0142ywa na bezpiecze\u0144stwo ko\u0144cowego produktu.<\/p>\n\n\n\n<p>Programy wykonywane przez interpreter, pomimo szeregu swoich zalet, s\u0105 z regu\u0142y tak\u017ce wolniejsze od tych dzia\u0142aj\u0105cych bezpo\u015brednio na poziomie kodu maszynowego. J\u0119zyki kompilowane lepiej sprawdzaj\u0105 si\u0119 ponadto, gdy musimy mierzy\u0107 si\u0119 z aplikacjami o wysokim poziomie skomplikowania. Jest to zwi\u0105zane z faktem, i\u017c oferuj\u0105 one zaawansowane mechanizmy zarz\u0105dzania pami\u0119ci\u0105, silne wsparcie dla wielow\u0105tkowo\u015bci oraz tzw. kompilacj\u0119 <em>Just-In-Time<\/em>, kt\u00f3ra pozwala optymalizowa\u0107 kod \u201ew locie\u201d, a co za tym idzie \u2013 <strong>lepiej wykorzystywa\u0107 dost\u0119pne zasoby<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Komentarz<\/strong><\/h3>\n\n\n\n<p><em>W rzeczywisto\u015bci zar\u00f3wno Java jak i Python \u0142\u0105cz\u0105 w sobie cechy j\u0119zyk\u00f3w interpretowanych i kompilowanych. Zag\u0142\u0119biaj\u0105c si\u0119 w spos\u00f3b dzia\u0142ania pythonowego interpretera, kod \u017ar\u00f3d\u0142owy w pierwszej kolejno\u015bci jest zamieniany w\u0142a\u015bnie na kod bajtowy (tzw. kod po\u015bredni), a nast\u0119pnie analizowany i wykonywany kawa\u0142ek po kawa\u0142ku. Do uruchomienia skompilowanego kodu Javy wykorzystywana jest z kolei maszyna wirtualna, kt\u00f3rej spos\u00f3b dzia\u0142ania jest zbli\u017cony do interpretera.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Typowanie<\/strong><\/h2>\n\n\n\n<p>R\u00f3\u017cnic\u0105, kt\u00f3rej nie spos\u00f3b nie zauwa\u017cy\u0107 podczas tworzenia kodu, jest typowanie. Python jest j\u0119zykiem dynamicznie typowanym, za\u015b Java \u2013 statycznie. <strong>Co to oznacza w praktyce?<\/strong><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Typowanie w Pythonie<\/strong><\/h3>\n\n\n\n<p>Deklaruj\u0105c zmienne, argumenty, czy zwracane warto\u015bci, w Pythonie nie musimy jawnie okre\u015bla\u0107 typ\u00f3w danych, jakie elementy te b\u0119d\u0105 przechowywa\u0107. Ma to miejsce automatycznie, tj. po przypisaniu do elementu konkretnej warto\u015bci i \u2013 co bardzo istotne \u2013 typ ten nie jest sta\u0142y, a wi\u0119c mo\u017ce ulega\u0107 zmianie w trakcie wykonywania programu.<\/p>\n\n\n\n<p>Takie zachowanie zdecydowanie <strong>zwi\u0119ksza szybko\u015b\u0107 i elastyczno\u015b\u0107 kodowania<\/strong> poprzez uproszczenie sk\u0142adni. Jednak\u017ce dla wielu programist\u00f3w jest to niew\u0105tpliwie wada, poniewa\u017c dynamicznie zmieniaj\u0105ce si\u0119 typy mog\u0105 powodowa\u0107 <strong>sporo problem\u00f3w<\/strong> np. przy wykrywaniu b\u0142\u0119d\u00f3w.<\/p>\n\n\n\n<p>W zwi\u0105zku z tym od wersji 3.5 Python daje nam mo\u017cliwo\u015b\u0107 deklaracji typ\u00f3w za pomoc\u0105 mechanizmu zwanego <em>type hinting<\/em>. Zadeklarowane w ten spos\u00f3b typy nadal nie s\u0105 jednak sta\u0142e i mog\u0105 zosta\u0107 zignorowane przez programist\u0119. Nie jest to zatem spos\u00f3b na wprowadzenie statycznego typowania, a jedynie podpowied\u017a s\u0142u\u017c\u0105ca \u0142atwiejszej analizie kodu pod k\u0105tem pierwotnych za\u0142o\u017ce\u0144.&nbsp;<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# Type hinting in Python\ndef calculate_bmi(person: str, weight: float, height: int) -&gt; str:\n   return f&quot;BMI of {person}: {weight\/((height * 0.01) ** 2)}&quot;\n\n\nif __name__ == &#039;__main__&#039;:\n   name: str = &quot;John&quot;\n   w: float = 78.8\n   h: int = 182\n   print(calculate_bmi(name, w, h))\n\n   # change the variable types to be different from the type hints\n   name: list = &#x5B;&quot;John&quot;, &quot;Smith&quot;]\n   w: int = 120\n   h: float = 182.5\n   print(calculate_bmi(name, w, h))\n\n# Output:\n# BMI of John: 23.789397415771038\n# BMI of 123456: 36.02927378495027\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\"><strong>Typowanie w Javie<\/strong><\/h3>\n\n\n\n<p>Java, jako j\u0119zyk statycznie typowany, w wi\u0119kszo\u015bci przypadk\u00f3w wymaga od programisty jasnej deklaracji typu ju\u017c w momencie inicjalizacji elementu. Raz okre\u015blony typ jest niezmienny i weryfikowany przez kompilator, kt\u00f3ry sprawdza czy operacje, kt\u00f3re chcemy wykona\u0107 s\u0105 zgodne z typem, kt\u00f3ry zadeklarowali\u015bmy. Dzi\u0119ki temu mo\u017cliwe jest wychwycenie wszelkich niesp\u00f3jno\u015bci jeszcze przed wykonaniem programu.<\/p>\n\n\n\n<p>Nale\u017cy podkre\u015bli\u0107, \u017ce wyr\u00f3\u017cnia si\u0119 dwa rodzaje typ\u00f3w w Javie:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>typy prymitywne (ang. <em>primitive types<\/em>),<\/li>\n\n\n\n<li>typy referencyjne (ang. <em>reference types<\/em>).<\/li>\n<\/ul>\n\n\n\n<p>Podstawow\u0105 r\u00f3\u017cnic\u0105 jest <strong>spos\u00f3b alokacji pami\u0119ci<\/strong>. Typy prymitywne z uwagi na swoj\u0105 prostot\u0119 i lekko\u015b\u0107 cechuj\u0105 si\u0119 wysok\u0105 szybko\u015bci\u0105, ale maj\u0105 znacznie ograniczone mo\u017cliwo\u015bci pod wzgl\u0119dem operacji, jakie mo\u017cna na nich wykonywa\u0107 w por\u00f3wnaniu do typ\u00f3w referencyjnych, dlatego w zasadzie ka\u017cdy typ prymitywny posiada odpowiadaj\u0105cy mu typ \u201eobiektowy\u201d (ang. <em>wrapper class<\/em>).<\/p>\n\n\n\n<p>Statyczne typowanie niew\u0105tpliwie zwi\u0119ksza niezawodno\u015b\u0107 i bezpiecze\u0144stwo tworzonego programu, aczkolwiek mo\u017ce utrudnia\u0107 jego czytelno\u015b\u0107. W zwi\u0105zku z tym, od wersji 10 wprowadzono w Javie typ <em>var<\/em>, kt\u00f3ry pozwala na wi\u0119ksz\u0105 swobod\u0119 poprzez automatyczne okre\u015blenie typu zmiennej przez kompilator w oparciu o przypisan\u0105 do niej warto\u015b\u0107. Nie jest to mimo wszystko zmiana, kt\u00f3ra powoduje drastyczn\u0105 r\u00f3\u017cnic\u0119 w kwestii przejrzysto\u015bci czy \u0142atwo\u015bci tworzenia kodu, przez co <strong>Python jest j\u0119zykiem o zdecydowanie ni\u017cszym progu wej\u015bcia.<\/strong><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\n\/\/ File: BMI.java\npublic class BMI {\n\n   public static String calculateBMI(String person, double weight, int height) {\n       double meters = height * 0.01;\n       double squaredHeight = meters * meters;\n       return &quot;BMI of &quot; + person + &quot;: &quot; + weight\/squaredHeight;\n   }\n\n   public static void main(String&#x5B;] args) {\n       var name = &quot;John&quot;;\n       double w = 78.8;\n       int h = 182;\n\n       System.out.println(calculateBMI(name, w, h));\n   }\n}\n\n\/\/Output:\n\/\/BMI of John: 23.789397415771038\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\"><strong>Hermetyzacja<\/strong><\/h2>\n\n\n\n<p>Na czym polega hermetyzacja (enkapsulacja) wspomina\u0142em ju\u017c w artykule <a href=\"https:\/\/sii.pl\/blog\/programowanie-obiektowe-na-przykladzie-pythona\/\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\">Programowanie obiektowe na przyk\u0142adzie Pythona<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Enkapsulacja w Pythonie<\/strong><\/h3>\n\n\n\n<p>Python traktuje wszystkie atrybuty i metody domy\u015blnie jako publiczne, tj. nie ogranicza dost\u0119pu do nich w \u017caden spos\u00f3b. Istniej\u0105 jednak <strong>mechanizmy<\/strong>, kt\u00f3re to umo\u017cliwiaj\u0105 i s\u0105 to <em>name mangling<\/em> oraz <em>internal use<\/em>.<\/p>\n\n\n\n<p>Pierwszy z nich pozwala traktowa\u0107 metody i atrybuty jako prywatne (ang. <em>private<\/em>) poprzez poprzedzenie ich nazw podw\u00f3jnym znakiem podkre\u015blenia. Taki zabieg sprawia, i\u017c s\u0105 one bezpo\u015brednio dost\u0119pne jedynie w klasie, w kt\u00f3rej zosta\u0142y zdefiniowane. Drugi mechanizm natomiast jest swego rodzaju rozszerzeniem pierwszego, poniewa\u017c wprowadza poj\u0119cie atrybut\u00f3w i metod chronionych (ang. <em>protected<\/em>), kt\u00f3re s\u0105 osi\u0105galne r\u00f3wnie\u017c w klasach potomnych. W celu zdefiniowania element\u00f3w chronionych u\u017cywamy pojedynczego znaku podkre\u015blenia.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nclass BankAccount:\n\n   def __init__(self, account_name):\n       self.account_name = account_name  # public attribute\n       self._operations = 10  # protected attribute\n       self.__account_balance = 1500  # private attribute\n\n\nif __name__ == &#039;__main__&#039;:\n   my_account = BankAccount(&quot;My private account&quot;)\n   print(&quot;Account name:&quot;, my_account.account_name)\n   print(&quot;Number of operations:&quot;, my_account._operations)\n   print(&quot;Account balance:&quot;, my_account.__account_balance) # AttributeError\n\n\n# Output:\n# Account name: My private account\n# Number of operations: 10\n\n# Traceback (most recent call last):\n#   File &quot;C:\\Users\\sii_user\\PycharmProjects\\python_vs_Java\\encapsulation.py&quot;, line 13, in &lt;module&gt;\n#     print(my_account.__account_balance)  # AttributeError\n#           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n# AttributeError: &#039;BankAccount&#039; object has no attribute &#039;__account_balance&#039;\n<\/pre><\/div>\n\n\n<p>Jak mo\u017cna zauwa\u017cy\u0107 powy\u017cej, w przypadku atrybutu chronionego <em>self._operations<\/em> nie ma \u017cadnych ogranicze\u0144 dost\u0119pu z zewn\u0105trz. Z kolei pr\u00f3ba wywo\u0142ania atrybutu prywatnego <em>self.__account_balance<\/em> zwr\u00f3ci b\u0142\u0105d, aczkolwiek nie oznacza to, i\u017c dost\u0119p do niego jest ca\u0142kowicie zablokowany. Stosowanie powszechnie akceptowanych rozwi\u0105za\u0144 s\u0142u\u017c\u0105cych do operowania na elementach \u201ez ograniczeniami\u201d (np. poprzez definiowanie getter\u00f3w i setter\u00f3w), to nie jedyny spos\u00f3b na dostanie si\u0119 do nich i istniej\u0105 r\u00f3wnie\u017c pewne \u201eobej\u015bcia\u201d:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# Workaround #1:\nif __name__ == &#039;__main__&#039;:\n   my_account = BankAccount(&quot;My private account&quot;)\n   print(&quot;Account balance (using &#039;name mangling&#039;):&quot;, my_account._BankAccount__account_balance)\n\n# Output:\n# Account balance (using &#039;name mangling&#039;): 1500\n<\/pre><\/div>\n\n\n<p>Powy\u017csze rozwi\u0105zanie w postaci poprzedzenia atrybutu prywatnego dodatkowym podkre\u015bleniem i nazw\u0105 klasy jest z\u0142amaniem konwencji i nie powinno si\u0119 go stosowa\u0107. Edytor kodu prawdopodobnie wyr\u00f3\u017cni nam je jako b\u0142\u0105d, ale program wykona si\u0119 bez problemu, co jasno pokazuje, \u017ce Python nie jest w kwestii hermetyzacji bardzo restrykcyjny.<\/p>\n\n\n\n<p>Poni\u017csze przyk\u0142ady z u\u017cyciem <em>__dict__<\/em> oraz <em>inspect<\/em> r\u00f3wnie\u017c potwierdzaj\u0105, i\u017c u\u017cywanie \u201enazw zast\u0119pczych\u201d nie jest pe\u0142nym zabezpieczeniem. Ci\u0119\u017cko jednak nie zgodzi\u0107 si\u0119 ze stwierdzeniem, \u017ce <strong>dzia\u0142a ono jako warstwa ochrony<\/strong>, motywuj\u0105c niejako programist\u00f3w do przestrzegania dobrych praktyk.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# Workaround #2:\nif __name__ == &#039;__main__&#039;:\n   my_account = BankAccount(&quot;My private account&quot;)\n   print(&quot;Account balance (using &#039;__dict__):&quot;,\n         my_account.__dict__&#x5B;&#039;_BankAccount__account_balance&#039;])\n\n# Output:\n# Account balance (using __dict__): 1500\n\n\n# Workaround #3:\nif __name__ == &#039;__main__&#039;:\n   import inspect\n\n   my_account = BankAccount(&quot;My private account&quot;)\n\n   # get all members of my_account object as (name, value) pairs\n   # for name, value in inspect.getmembers(my_account):\n   #     print(f&quot;{name}: {value}&quot;)\n\n   # based on the returned object members\n   print(\n       &quot;Account balance (using &#039;inspect&#039;):&quot;,\n       getattr(my_account, &#039;_BankAccount__account_balance&#039;, None)\n   )\n\n# Output:\n# Account balance (using &#039;inspect&#039;): 1500\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\"><strong>Enkapsulacja w Javie<\/strong><\/h3>\n\n\n\n<p>Java podchodzi do tematu bardziej bezkompromisowo. Widoczno\u015b\u0107 klas, metod i atrybut\u00f3w okre\u015blamy tutaj za pomoc\u0105 modyfikator\u00f3w dost\u0119pu w postaci nast\u0119puj\u0105cych s\u0142\u00f3w kluczowych:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em>public<\/em> \u2013 element jest dost\u0119pny z dowolnego miejsca w obr\u0119bie pakietu i poza nim;<\/li>\n\n\n\n<li><em>protected<\/em> \u2013 element jest dost\u0119pny w obr\u0119bie klasy w kt\u00f3rej zosta\u0142 zdefiniowany, jak r\u00f3wnie\u017c w klasach dziedzicz\u0105cych niezale\u017cnie od pakietu, w kt\u00f3rym si\u0119 znajduj\u0105;<\/li>\n\n\n\n<li><em>private<\/em> \u2013 element jest dost\u0119pny jedynie w klasie, w kt\u00f3rej zosta\u0142 zdefiniowany;<\/li>\n\n\n\n<li><em>default<\/em> \u2013 brak modyfikatora; element, kt\u00f3ry nie zosta\u0142 poprzedzony \u017cadnym z powy\u017cszych modyfikator\u00f3w ma tzw. dost\u0119p pakietowy (domy\u015blny), czyli jest dost\u0119pny w obr\u0119bie pakietu, w kt\u00f3rym zosta\u0142 zdefiniowany.<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\n\/\/ File: BankAccount.java\npublic class BankAccount {\n   public String accountName; \/\/ Available everywhere\n   protected Integer operations = 0; \/\/ Available in the class, subclasses and package\n   private Integer accountBalance = 0; \/\/ Available only in the class\n   String generalInfo; \/\/ Available in the package (default)\n\n   \/\/ public constructor\n   public BankAccount(String accountName, Integer accountBalance, String generalInfo) {\n       this.accountName = accountName;\n       this.accountBalance = accountBalance;\n       this.generalInfo = generalInfo;\n   }\n\n   \/\/ Methods:\n   public String getAccountName() { return this.accountName; }\n\n   protected void getOperations() { System.out.println(&quot;Number of operations: &quot; + this.operations); }\n\n\/\/ File: Runner.java\npublic class Runner {\n\n   public static void main(String&#x5B;] args) {\n       BankAccount my_account = new BankAccount(\n               &quot;Savings account&quot;,\n               12000,\n               &quot;Savings for holidays&quot;\n       );\n\n       \/\/ Access to public attr:\n       System.out.println(&quot;Name: &quot; + my_account.accountName);\n       \/\/ Access to protected attr (in the same package):\n       System.out.println(&quot;Operations: &quot; + my_account.operations);\n       \/\/ Access to private attr (not possible - commented out):\n       \/\/ System.out.println(my_account.accountBalance);\n       \/\/ Access to default attr (in the same package):\n       System.out.println(&quot;Info: &quot; + my_account.generalInfo);\n       \/\/ Access to public mtd:\n       System.out.println(&quot;Name: &quot; + my_account.getAccountName());\n       \/\/ Access to protected mtd (in the same package):\n       my_account.getOperations();\n       \/\/ Access to private mtd (not possible - commented out)\n       \/\/ System.out.println(my_account.getAccountBalance());\n       \/\/ Access to default mtd (in the same package):\n       my_account.getInfo();\n   }\n}\n\n\/\/Output:\n\/\/Name: Savings account\n\/\/Operations: 0\n\/\/Info: Savings for holidays\n\/\/Name: Savings account\n\/\/Number of operations: 0\n\/\/Account name: Savings account\n\/\/Account balance: 12000\n\/\/Number of operations: 0\n\/\/Savings for holidays\n<\/pre><\/div>\n\n\n<p>Dzi\u0119ki modyfikatorom dost\u0119pu <strong>Java jest j\u0119zykiem bardziej rygorystycznym<\/strong> \u2013 ci\u0119\u017cej tutaj o doprowadzenie do braku sp\u00f3jno\u015bci danych, poniewa\u017c nie posiada ona analogicznych do Pythona rozwi\u0105za\u0144 pozwalaj\u0105cych na omijanie hermetyzacji.<\/p>\n\n\n\n<p>Nie jest jednak prawd\u0105, \u017ce podobny efekt jest niemo\u017cliwy do osi\u0105gni\u0119cia. Chc\u0105c uzyska\u0107 dost\u0119p do metod i atrybut\u00f3w okre\u015blonych jako <em>private,<\/em> mo\u017cna pos\u0142u\u017cy\u0107 si\u0119 <strong>mechanizmem zwanym refleksj\u0105<\/strong> (ang. <em>reflection<\/em>), kt\u00f3ry pozwala nam na dynamiczne badanie i modyfikowanie struktury programu w czasie jego dzia\u0142ania.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\n\/\/ File: Reflection.java\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\n\npublic class Reflection {\n\n   public static void main(String&#x5B;] args) {\n       BankAccount my_account = new BankAccount(\n               &quot;Savings account&quot;,\n               12000,\n               &quot;Savings for holidays&quot;\n       );\n\n       try {\n           Field privateField = BankAccount.class.getDeclaredField(&quot;accountBalance&quot;);\n           privateField.setAccessible(true);\n           System.out.println(&quot;Account balance (using privateField): &quot; + privateField.get(my_account));\n\n           Method privateMethod = BankAccount.class.getDeclaredMethod(&quot;getAccountBalance&quot;);\n           privateMethod.setAccessible(true);\n           System.out.println(&quot;Account balance (using privateMethod): &quot; + privateMethod.invoke(my_account));\n       } catch (Exception err) {\n           err.printStackTrace();\n       }\n   }\n}\n\n\/\/Output:\n\/\/Account balance (using privateField): 12000\n\/\/Account balance (using privateMethod): 12000\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\"><strong>Interfejsy<\/strong><\/h2>\n\n\n\n<p>Ka\u017cdy rodzaj obiekt\u00f3w, czy to w Pythonie, czy w Javie, udost\u0119pnia pewien zestaw operacji, kt\u00f3re mo\u017cna na nim wykona\u0107, a co za tym idzie \u2013 rozwi\u0105za\u0107 za jego pomoc\u0105 jaki\u015b problem. Przyk\u0142adowo, w Pythonie dla obiektu o typie <strong><em>str<\/em><\/strong> b\u0119dzie to metoda <strong><em>upper()<\/em><\/strong>, za\u015b w Javie \u2013 typ <strong><em>String<\/em><\/strong><em> <\/em>i metoda <strong><em>toUpperCase()<\/em><\/strong>.<\/p>\n\n\n\n<p>To, jakie zachowanie jest mo\u017cliwe do uzyskania na obiekcie danej klasy (jakie metody b\u0119dzie ten obiekt posiada\u0142 \u2013 co b\u0119dzie robi\u0142, czy inaczej \u2013 jaki interfejs b\u0119dzie udost\u0119pnia\u0142), okre\u015blaj\u0105 tzw. <strong>kontrakty<\/strong>. To w\u0142a\u015bnie one zawieraj\u0105 regu\u0142y, jakim powinna podlega\u0107 konkretna implementacja, tj. deklaracje jakich metod s\u0105 wymagane oraz jakie s\u0105 ich oczekiwane zachowania.<\/p>\n\n\n\n<p>Definiuj\u0105c nowy interfejs, za\u0142o\u017cenie jest wi\u0119c proste: <strong>definiujemy w nim tylko metody okre\u015blone w \u201ekontrakcie\u201d<\/strong>, a cia\u0142a tych metod pozostawiamy puste, tj. nie implementujemy ich zachowania \u2013 stanowi\u0105 one jedynie swego rodzaju <em>placeholdery<\/em> i dopiero klasy zbudowane w oparciu o dany interfejs dostarczaj\u0105 w\u0142asne implementacje owych metod. Takie podej\u015bcie sprawia, \u017ce tworzony przez nas <strong>kod jest sp\u00f3jny i spe\u0142nia okre\u015blone wymagania.<\/strong><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Interfejsy w Pythonie<\/strong><\/h3>\n\n\n\n<p>Jak \u0142atwo si\u0119 domy\u015bli\u0107, Python i Java w kwestii tworzenia interfejs\u00f3w preferuj\u0105 odmienne podej\u015bcia. Mo\u017cna nawet przyj\u0105\u0107, \u017ce w Pythonie poj\u0119cie interfejsu w og\u00f3le nie istnieje, gdy\u017c j\u0119zyk ten nie posiada osobnych struktur do ich opisywania. W celu utworzenia \u201ezbioru\u201d metod dla innych klas stosuje si\u0119 tutaj klasy i metody abstrakcyjne.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# Python abstract class\nfrom abc import ABC, abstractmethod\n\n\nclass Animal(ABC):\n\n   @abstractmethod\n   def move(self):\n       pass\n\n   @abstractmethod\n   def eat(self):\n       pass\n\n   @abstractmethod\n   def make_sound(self):\n       print(&quot;Making sound&quot;)\n\n   @staticmethod\n   def double_number(a: int):\n       return a * 2\n<\/pre><\/div>\n\n\n<p>Wykorzystanie abstrakcji do utworzenia struktury imituj\u0105cej interfejs powoduje, \u017ce dopuszczalne s\u0105 pewne odst\u0119pstwa od g\u0142\u00f3wnych za\u0142o\u017ce\u0144, jakie prawid\u0142owy interfejs powinien spe\u0142nia\u0107. Nie ma w tym przypadku problemu, aby metoda nale\u017c\u0105ca do klasy abstrakcyjnej (metoda abstrakcyjna) posiada\u0142a w\u0142asn\u0105 implementacj\u0119 (cia\u0142o). Mo\u017cliwe jest definiowanie metod w og\u00f3le niezwi\u0105zanych z okre\u015blon\u0105 funkcjonalno\u015bci\u0105, za\u015b konkretna implementacja (tworzenie klas na podstawie og\u00f3lnej klasy abstrakcyjnej) odbywa si\u0119 z wykorzystaniem standardowego dziedziczenia.<\/p>\n\n\n\n<p>Opr\u00f3cz tego, z definiowaniem interfejs\u00f3w w Pythonie \u0142\u0105czy si\u0119 poj\u0119cie <strong>protoko\u0142\u00f3w<\/strong> (ang. <em>protocols<\/em>). Pozwalaj\u0105 one r\u00f3wnie\u017c okre\u015bla\u0107 zbi\u00f3r metod i atrybut\u00f3w, kt\u00f3re dana klasa powinna zawiera\u0107, aby wspiera\u0107 konkretn\u0105 funkcjonalno\u015b\u0107, ale odbywa si\u0119 to bez konieczno\u015bci stosowania dziedziczenia. Jest to zatem mechanizm bardzo elastyczny, gdzie programista skupia si\u0119 g\u0142\u00f3wnie na implementacji po\u017c\u0105danych zachowa\u0144 bez potrzeby po\u015bwi\u0119cania swojej uwagi na z\u0142o\u017cone relacje pomi\u0119dzy klasami.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nfrom typing import Protocol\n\n\nclass Figure(Protocol):\n\n   def create(self, tool): ...\n\n\nclass Circle:\n\n   def create(self, radius):\n       print(f&quot;Creating a circle with a radius: {radius}&quot;)\n\n\nclass Cube:\n\n   def create(self, side):\n       print(f&quot;Creating a cube with a side: {side}&quot;)\n\n\nclass Triangle:\n\n   def draw(self, height):\n       print(f&quot;Creating a triangle with a height: {height}&quot;)\n\n\ndef create_item(item: Figure, *args):\n   item.create(*args)\n\n\nif __name__ == &#039;__main__&#039;:\n   circle = Circle()\n   cube = Cube()\n   triangle = Triangle()\n\n   create_item(circle, 5)\n   create_item(cube, 2)\n   create_item(triangle, 10)  # Expected type &#039;Figure&#039;, got &#039;Triangle&#039; instead\n\n# Output:\n# Creating a circle with a radius: 5\n# Creating a cube with a side: 2\n# Traceback (most recent call last):\n#   File &quot;C:\\Users\\sii_user\\PycharmProjects\\python_vs_Java\\protocol.py&quot;, line 39, in &lt;module&gt;\n#     create_item(triangle, 10)  # Expected type &#039;Figure&#039;, got &#039;Triangle&#039; instead\n#     ^^^^^^^^^^^^^^^^^^^^^^^^^\n#   File &quot;C:\\Users\\mwilk\\PycharmProjects\\python_vs_Java\\protocol.py&quot;, line 29, in create_item\n#     item.create(*args)\n#     ^^^^^^^^^^^\n# AttributeError: &#039;Triangle&#039; object has no attribute &#039;create&#039;\n<\/pre><\/div>\n\n\n<p>Przyk\u0142ad ilustruje tworzenie protoko\u0142u <em>Figure<\/em> oraz trzech klas, z kt\u00f3rych dwie (<em>Circle<\/em> i <em>Cube<\/em>) implementuj\u0105 go poprzez posiadanie metody <em>create<\/em> i jedna (<em>Triangle<\/em>) nieodnosz\u0105ca si\u0119 do niego w \u017caden spos\u00f3b. Wszystko odbywa si\u0119 bez dziedziczenia, przez co klasy s\u0105 niezale\u017cne, a tym co \u0142\u0105czy je ze sob\u0105 (lub nie) jest posiadanie wsp\u00f3lnej metody <em>create<\/em>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Interfejsy w Javie<\/strong><\/h3>\n\n\n\n<p>W Javie protoko\u0142y nie s\u0105 obecne, ale klasy abstrakcyjne ju\u017c tak i dzia\u0142aj\u0105 one na zasadach podobnych, jak w Pythonie \u2013 mog\u0105 zawiera\u0107 zar\u00f3wno deklaracje metod abstrakcyjnych, jak i ich implementacje. Nie s\u0105 one natomiast bezpo\u015brednio wykorzystywane do budowy interfejs\u00f3w. W tym celu s\u0142u\u017cy dedykowana struktura zwana po prostu <em>interface<\/em> pozwalaj\u0105ca tworzy\u0107 tzw. <em>sygnatury<\/em> metod tj. deklaracje sk\u0142adaj\u0105ce si\u0119 jedynie z nazwy, listy parametr\u00f3w wraz z typami oraz niekiedy obs\u0142ugiwanymi wyj\u0105tkami.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\n\/\/File: Interfaces.java\ninterface FirstInterface {\n   void methodA();\n\n   void methodB();\n}\n\ninterface SecondInterface {\n   void methodX();\n\n   default void defaultMethod() {\n       System.out.println(&quot;Default methods are allowed!&quot;);\n   }\n\n   static void staticMethod() {\n       System.out.println(&quot;Static methods are allowed!&quot;);\n   }\n}\n\n\n\/\/File: InterfaceImp.java\npublic class InterfaceImp implements FirstInterface, SecondInterface {\n   @Override\n   public void methodA() {\n       System.out.println(&quot;Implementation of methodA&quot;);\n   }\n\n   @Override\n   public void methodB() {\n       System.out.println(&quot;Implementation of methodB&quot;);\n   }\n\n   @Override\n   public void methodX() {\n       System.out.println(&quot;Implementation of methodX&quot;);\n   }\n}\n\n\n\/\/File: InterfaceMain.java\npublic class InterfaceMain {\n   public static void main(String&#x5B;] args) {\n       InterfaceImp object = new InterfaceImp();\n\n       object.methodA();\n       object.methodB();\n       object.methodX();\n       object.defaultMethod();\n       SecondInterface.staticMethod();\n   }\n}\n\n\/\/Output:\n\/\/Implementation of methodA\n\/\/Implementation of methodB\n\/\/Implementation of methodX\n\/\/Default methods are allowed!\n\/\/Static methods are allowed!\n<\/pre><\/div>\n\n\n<p>Warto odnotowa\u0107, \u017ce implementacja interfejs\u00f3w w Javie nie odbywa si\u0119 poprzez dziedziczenie (jak w Pythonie), a z wykorzystaniem s\u0142owa kluczowego <em>implements<\/em>. Pozwala to w pewnym sensie na osi\u0105gni\u0119cie wielodziedziczenia, kt\u00f3re domy\u015blnie nie jest w tym j\u0119zyku mo\u017cliwe \u2013 klasa w Javie mo\u017ce dziedziczy\u0107 (za pomoc\u0105 s\u0142owa kluczowego <em>extends<\/em>) tylko po jednej klasie, ale implementowa\u0107 (<em>implements<\/em>) wiele interfejs\u00f3w naraz.<\/p>\n\n\n\n<figure class=\"wp-block-table aligncenter\"><table><tbody><tr><td><strong>Klasa abstrakcyjna<\/strong><\/td><td><strong>Interfejs<\/strong><\/td><\/tr><tr><td>Mo\u017ce zawiera\u0107 zar\u00f3wno metody abstrakcyjne (bez cia\u0142a), jak i nieabstrakcyjne<\/td><td>Mo\u017ce zawiera\u0107 tylko metody abstrakcyjne (bez cia\u0142a) przewidziane dla danego interfejsu<\/td><\/tr><tr><td>Mo\u017ce implementowa\u0107 inny interfejs oraz rozszerza\u0107 inn\u0105 klas\u0119<\/td><td>Mo\u017ce implementowa\u0107 inny interfejs<\/td><\/tr><tr><td>Klasa pochodna mo\u017ce rozszerza\u0107 tylko jedn\u0105 klas\u0119 abstrakcyjn\u0105 (brak wielodziedziczenia w Javie)<\/td><td>Klasa pochodna mo\u017ce implementowa\u0107 wiele interfejs\u00f3w naraz (wielodziedziczenie)<\/td><\/tr><tr><td>Modyfikatory dost\u0119pu dla klasy abstrakcyjnej:<br>public, protected, private, default<\/td><td>Modyfikatory dost\u0119pu dla interfejsu: public, default<\/td><\/tr><\/tbody><\/table><figcaption class=\"wp-element-caption\">Tab. 1 Klasa abstrakcyjna a interfejs<\/figcaption><\/figure>\n\n\n\n<p>Osobna konstrukcja dedykowana interfejsom dost\u0119pna w Javie jest jej niew\u0105tpliw\u0105 zalet\u0105. Od razu nasuwa si\u0119 przez to na my\u015bl, \u017ce w przypadku tego j\u0119zyka nie ma mowy o \u017cadnych osobliwo\u015bciach i wszystkie restrykcje stawiane interfejsom z definicji musz\u0105 zosta\u0107 spe\u0142nione.<\/p>\n\n\n\n<p>Nie jest to do ko\u0144ca prawda, gdy\u017c \u2013 jak wykaza\u0142em powy\u017cej \u2013 od wersji 8+ <strong>dopuszcza si\u0119 deklarowanie w interfejsach metod domy\u015blnych<\/strong> (ang. <em>default methods<\/em>) <strong>i statycznych<\/strong>. Powodem takiej zmiany jest m.in.: ch\u0119\u0107 trzymania funkcjonalno\u015bci wsp\u00f3lnych dla klas implementuj\u0105cych dany interfejs w jednym miejscu, co zdecydowanie zmniejsza redundancj\u0119 i u\u0142atwia utrzymanie kodu.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Polimorfizm<\/strong><\/h2>\n\n\n\n<p>Polimorfizm ma szczeg\u00f3lne znaczenie w programowaniu obiektowym, poniewa\u017c wspiera tworzenie elastycznego i reu\u017cywalnego kodu. Pozwala on zdefiniowa\u0107 pojedynczy interfejs, kt\u00f3ry mo\u017ce by\u0107 wykorzystany dla r\u00f3\u017cnych implementacji. Oznacza to, \u017ce mimo, i\u017c posiadamy w naszym kodzie metody o identycznych nazwach, to ich zachowania r\u00f3\u017cni\u0105 si\u0119 od siebie zale\u017cnie od obiektu, na kt\u00f3rym s\u0105 wywo\u0142ywane.<\/p>\n\n\n\n<p>M\u00f3wi\u0105c o polimorfizmie nie spos\u00f3b nie wspomnie\u0107 o dw\u00f3ch jego odmianach, czyli o <em>method overriding <\/em>(nadpisywanie metod) oraz <em>method overloading <\/em>(przeci\u0105\u017canie metod)<em>.<\/em><\/p>\n\n\n\n<p><strong>Nadpisywanie metod<\/strong> dotyczy dziedziczenia, gdzie ka\u017cda z klas pochodnych mo\u017ce dostarcza\u0107 swoj\u0105 w\u0142asn\u0105 implementacj\u0119 metody odziedziczonej z klasy nadrz\u0119dnej. M\u00f3wi\u0105c wprost: nadpisujemy (lub rozszerzamy) odziedziczon\u0105 metod\u0119 przez co ka\u017cdy obiekty mo\u017ce zachowywa\u0107 si\u0119 w inny spos\u00f3b. Z punktu widzenia Pythona <em>method overriding<\/em> wydaje si\u0119 by\u0107 bardziej \u201enaturalny\u201d, aczkolwiek wyst\u0119puje on w obu j\u0119zykach.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# Method overriding in Python\nclass Mammal:\n   division = &quot;mammal&quot;\n\n   def __init__(self, name):\n       self.name = name\n\n   def make_sound(self):\n       print(f&quot;{self.name} is making a sound...&quot;)\n\n\nclass Dog(Mammal):\n\n   def __init__(self, name, breed):\n       super(Dog, self).__init__(name) # extending inherited method\n       self.breed = breed\n\n   def make_sound(self):\n       print(&quot;Woof woof!&quot;)         # overriding inherited method\n\n\nif __name__ == &#039;__main__&#039;:\n   animal = Mammal(&quot;Animal&quot;)\n   animal.make_sound()\n   doggie = Dog(&quot;Pluto&quot;, &quot;bulldog&quot;)\n   doggie.make_sound()\n\n\n# Output:\n# Animal is making a sound...\n# Woof woof!\n\n\n\/\/ Method overriding in Java\n\/\/ File: Mammal.java\npublic class Mammal {\n   protected final String division = &quot;mammal&quot;;\n   private String name;\n\n   public Mammal(String name) {\n       this.name = name;\n   }\n\n   public void makeSound() {\n       System.out.println(name + &quot; is making sound...&quot;);\n   }\n}\n\n\n\/\/ File: Dog.java\npublic class Dog extends Mammal {\n   private String breed;\n\n   public Dog(String name, String breed) {\n       super(name);            \/\/ extending inherited method\n       this.breed = breed;\n   }\n\n   @Override\n   public void makeSound() {\n       System.out.println(&quot;Woof woof!&quot;);   \/\/ overriding inherited method\n   }\n}\n\n\/\/ File: MainRunner.java\npublic class MainRunner {\n   public static void main(String&#x5B;] args) {\n       Mammal animal = new Mammal(&quot;Animal&quot;);\n       animal.makeSound();\n       Dog doggie = new Dog(&quot;Pluto&quot;, &quot;bulldog&quot;);\n       doggie.makeSound();\n   }\n}\n\n\/\/ Output:\n\/\/ Animal is making sound...\n\/\/ Woof woof!\n<\/pre><\/div>\n\n\n<p>Inaczej ma si\u0119 sprawa w przypadku <em>method overloading\u2019u<\/em>, kt\u00f3ry charakteryzuje bardziej j\u0119zyki statyczne (Jav\u0119, C++) i w samym Pythonie, jako j\u0119zyku dynamicznie typowanym, bezpo\u015brednio nie istnieje. <strong>Przeci\u0105\u017canie metod<\/strong> ma miejsce w sytuacji, gdy definiujemy kilka wersji tej samej metody, a tym co decyduje o jej zachowaniu w danej chwili jest liczba i typy przekazanych parametr\u00f3w. W momencie wywo\u0142ania kompilator sam decyduje, kt\u00f3rej implementacji u\u017cy\u0107.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\n\/\/ File: OverloadMethods.java\npublic class OverloadMethods {\n\n   public void combineItems(int itemOne, int itemTwo) {\n       int result = itemOne + itemTwo;\n       System.out.println(&quot;Result of combined items is: &quot; + result);\n   }\n\n   public void combineItems(int itemOne, int itemTwo, int itemThree) {\n       int result = itemOne + itemTwo + itemThree;\n       System.out.println(&quot;Result of combined items is: &quot; + result);\n   }\n\n   public void combineItems(String itemOne, String itemTwo) {\n       String result = itemOne + itemTwo;\n       System.out.println(&quot;Result of combined items is: &quot; + result);\n   }\n}\n\n\/\/ File: RunMethods.java\npublic class RunMethods {\n   public static void main(String&#x5B;] args) {\n       OverloadMethods object = new OverloadMethods();\n       object.combineItems(3, 5);\n       object.combineItems(3, 5, 7);\n       object.combineItems(&quot;One&quot;, &quot;Two&quot;);\n   }\n}\n\n\/\/ Output:\n\/\/ Result of combined items is: 8\n\/\/ Result of combined items is: 15\n\/\/ Result of combined items is: OneTwo\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\"><strong>Co z tym przeci\u0105\u017caniem w Pythonie?<\/strong><\/h2>\n\n\n\n<p>Domy\u015blnie Python nie umo\u017cliwia korzystania z <em>method overloading\u2019u<\/em> w spos\u00f3b, jaki robi to Java. Ka\u017cda pr\u00f3ba zdefiniowania metod o tej samej nazwie r\u00f3\u017cni\u0105cych si\u0119 od siebie liczb\u0105 i\/lub typem parametr\u00f3w spowoduje, \u017ce skorzysta\u0107 b\u0119dziemy mogli tylko z jednej (ostatniej) z nich. Istnieje jednak pewien wyj\u0105tek, czyli tzw. przeci\u0105\u017canie operator\u00f3w (kt\u00f3rego z kolei nie posiada Java ;). Charakteryzuje si\u0119 ono tym, \u017ce konkretny operator (arytmetyczny, logiczny, por\u00f3wnania etc.) r\u00f3wnie\u017c mo\u017ce posiada\u0107 r\u00f3\u017cne, zale\u017cne od kontekstu, implementacje.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nfrom typing import List, Union\n\n\nclass Box:\n\n   def __init__(self, elements: List = &#x5B;]):\n       self.elements = elements\n\n   def __add__(self, item: Union&#x5B;str, int, bool]):\n       return self.elements.append(item)\n\n   def __str__(self):\n       return f&quot;Elements in the box: {self.elements}&quot;\n\n\nclass IntNumbers:\n\n   def __init__(self, a: int, b: int):\n       self.a = a\n       self.b = b\n\n   def __add__(self, to_add: int):\n       return IntNumbers(self.a + to_add, self.b + to_add)\n\n\nif __name__ == &#039;__main__&#039;:\n   box = Box(&#x5B;1, &quot;abc&quot;, True])\n   print(box)\n   box + &quot;new_item&quot;\n   print(box)\n\n   nums = IntNumbers(5, 10)\n   print(f&quot;Numbers: {nums.a}, {nums.b}&quot;)\n   nums = nums + 5\n   print(f&quot;Numbers: {nums.a}, {nums.b}&quot;)\n\n\n# Output:\n# Elements in the box: &#x5B;1, &#039;abc&#039;, True]\n# Elements in the box: &#x5B;1, &#039;abc&#039;, True, &#039;new_item&#039;]\n# Numbers: 5, 10\n# Numbers: 10, 15\n<\/pre><\/div>\n\n\n<p><strong>Przeci\u0105\u017canie operator\u00f3w odbywa si\u0119 za pomoc\u0105 metod specjalnych<\/strong>. Przyk\u0142ad powy\u017cej ilustruje, jak mo\u017ce zmienia\u0107 si\u0119 zachowywanie operatora \u201c+\u201d w przypadku zastosowania go na r\u00f3\u017cnych obiektach. Ka\u017cda z klas zawiera tutaj w\u0142asn\u0105 definicj\u0119 metody specjalnej __add__, odpowiadaj\u0105cej w\u0142a\u015bnie za spos\u00f3b dzia\u0142ania operatora dodawania \u2013 w przypadku klasy <em>Box<\/em> u\u017cycie \u201c+\u201d spowoduje dorzucenie elementu do listy, za\u015b dla klasy <em>IntNumbers<\/em> dodanie konkretnej warto\u015bci do ka\u017cdego z dw\u00f3ch jej atrybut\u00f3w.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Inne metody<\/strong><\/h3>\n\n\n\n<p>Przeci\u0105\u017canie operator\u00f3w to nie jedyny przyk\u0142ad <em>method overloading\u2019u<\/em> w Pythonie. W pewnej uproszczonej formie mo\u017cemy go uzyska\u0107 tak\u017ce poprzez:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>u\u017cycie instrukcji warunkowych wraz z metod\u0105 wbudowan\u0105 <em>isinstance()<\/em>;<\/li>\n<\/ol>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\ndef ovrld_with_isinstance(param1, param2):\n   if isinstance(param1, int) and isinstance(param2, int):\n       print(&quot;Both parameters are compatible!&quot;)\n   else:\n       print(&quot;At least one parameter is incompatible!&quot;)\n\n\nif __name__ == &#039;__main__&#039;:\n   ovrld_with_isinstance(11, 15)\n   ovrld_with_isinstance(100, &#x5B;1, 2])\n\n# Output:\n# Both parameters are compatible!\n# At least one parameter is incompatible!\n<\/pre><\/div>\n\n\n<ol class=\"wp-block-list\" start=\"2\">\n<li>przekazywanie zmiennej liczby argument\u00f3w za pomoc\u0105 <em>*args <\/em>i\/lub <em>**kwargs<\/em>;<\/li>\n<\/ol>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\ndef ovrld_with_args_kwargs(*args, **kwargs):\n   if len(args) &gt;= 1 and kwargs.get(&quot;key&quot;):\n       print(&quot;*args and **kwargs have been passed!&quot;)\n   elif kwargs.get(&quot;key&quot;) is None:\n       print(&quot;**kwargs have not been passed...&quot;)\n\n\nif __name__ == &#039;__main__&#039;:\n   ovrld_with_args_kwargs(8, &quot;string&quot;, key=&quot;value&quot;)\n   ovrld_with_args_kwargs(8, &quot;string&quot;)\n\n# Output:\n# *args and **kwargs have been passed!\n# **kwargs have not been passed...\n<\/pre><\/div>\n\n\n<ol class=\"wp-block-list\" start=\"3\">\n<li>przypisywanie argumentom domy\u015blnej warto\u015bci <em>None<\/em><\/li>\n<\/ol>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\ndef ovrld_with_none(param1=None, param2=None):\n   if isinstance(param1, float) and param2 is None:\n       print(&quot;Proceed with param1...&quot;)\n   elif param1 is None and param2 is None:\n       print(&quot;Received invalid arguments&quot;)\n\n\nif __name__ == &#039;__main__&#039;:\n   ovrld_with_none()\n   ovrld_with_none(10.120)\n\n# Output:\n# Received invalid arguments\n# Proceed with param1...\n<\/pre><\/div>\n\n\n<ol class=\"wp-block-list\" start=\"4\">\n<li>zastosowanie <em>singledispatch <\/em>z modu\u0142u <em>functools<\/em><\/li>\n<\/ol>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nfrom functools import singledispatch\n\n\n@singledispatch\ndef method(item):\n   raise ValueError(&quot;Provided data type is not supported!&quot;)\n\n\n@method.register\ndef _(item: str):\n   print(&quot;Provided data type: string&quot;)\n\n\n@method.register\ndef _(item: list):\n   print(&quot;Provided data type: list&quot;)\n\n\nif __name__ == &#039;__main__&#039;:\n   method(&quot;text&quot;)\n   method(&#x5B;True, 150])\n   # method(150)  # ValueError: Provided data type is not supported!\n\n# Output:\n# Provided data type: string\n# Provided data type: list\n<\/pre><\/div>\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/sii.pl\/oferty-pracy\/?tt=PYTHON_2,JAVA_3&amp;pa=2\" target=\"_blank\" rel=\"noreferrer noopener\"><img decoding=\"async\" width=\"737\" height=\"170\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/12\/praca-m-3.jpg\" alt=\"oferty pracy\" class=\"wp-image-29683\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/12\/praca-m-3.jpg 737w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/12\/praca-m-3-300x69.jpg 300w\" sizes=\"(max-width: 737px) 100vw, 737px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Podsumowanie<\/strong><\/h2>\n\n\n\n<p>Oba j\u0119zyki znacznie r\u00f3\u017cni\u0105 si\u0119 od siebie i ka\u017cdy z nich ma swoje unikalne cechy, kt\u00f3re sprawiaj\u0105, \u017ce znajduj\u0105 one zastosowanie w innych, specyficznych dziedzinach.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Python<\/strong> znany ze swojej prostej i zwi\u0119z\u0142ej sk\u0142adni, dynamicznego podej\u015bcia i szerokiej gamy dost\u0119pnych bibliotek \u015bwietnie sprawdza si\u0119 w automatyzacji zada\u0144, analizie danych czy przy tworzeniu aplikacji webowych.<\/li>\n\n\n\n<li><strong>Java <\/strong>cechuj\u0105ca si\u0119 z kolei wysok\u0105 wydajno\u015bci\u0105 i skalowalno\u015bci\u0105, wspieraj\u0105ca silne typowanie i posiadaj\u0105ca bogaty ekosystem, idealnie pasuje do rozwijania system\u00f3w rozproszonych, aplikacji mobilnych czy korporacyjnych.<\/li>\n<\/ul>\n\n\n\n<p>Tak szerokie wykorzystanie ka\u017cdego z podej\u015b\u0107 powoduje, \u017ce zdecydowanie warto posi\u0105\u015b\u0107 przynajmniej og\u00f3ln\u0105 wiedz\u0119 na temat ka\u017cdego z nich.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>\u0179r\u00f3d\u0142a<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/sii.pl\/blog\/inzynieria-odwrotna-co-to-jest\/\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\">In\u017cynieria odwrotna \u2013 co to jest?<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/towardsdatascience.com\/rewiring-your-brain-from-python-to-java-383960580098\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >Rewiring Your Brain from Python to Java<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/runestone.academy\/ns\/books\/published\/java4python\/index.html\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >Welcome to Java for Python Programmers<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.geeksforgeeks.org\/python-method-overloading\/\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >Python | Method Overloading<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/pl.wikipedia.org\/wiki\/Przeci%C4%85%C5%BCanie_operator%C3%B3w\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >Przeci\u0105\u017canie operator\u00f3w<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/pl.wikipedia.org\/wiki\/Przeci%C4%85%C5%BCanie_funkcji\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >Przeci\u0105\u017canie funkcji<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/bulldogjob.pl\/readme\/nie-boj-sie-type-hints-w-pythonie\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >Nie b\u00f3j si\u0119 Type Hints w Pythonie<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/realpython.com\/python-type-hints-multiple-types\/\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >How to Use Type Hints for Multiple Return Types in Python<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/realpython.com\/operator-function-overloading\/\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >Operator and Function Overloading in Custom Python Classes<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/medium.com\/@knoldus\/accessing-private-fields-and-methods-using-reflection-27caf3e5bdd4\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >Accessing private fields and methods using reflection<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/realpython.com\/python-protocol\/#the-meaning-of-protocol-in-python\" target=\"_blank\" aria-label=\" (opens in a new tab)\" rel=\"noreferrer noopener\" class=\"ek-link\" rel=\"nofollow\" >Python Protocols: Leveraging Structural Subtyping<\/a><\/li>\n<\/ul>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;28528&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;8&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;4.7&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;11&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;4.7\\\/5 ( votes: 8)&quot;,&quot;size&quot;:&quot;18&quot;,&quot;title&quot;:&quot;Python vs. Java \u2013 podstawowe r\u00f3\u017cnice w podej\u015bciu do programowania obiektowego&quot;,&quot;width&quot;:&quot;130.8&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} ( {votes}: {count})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 130.8px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 14.4px;\">\n            4.7\/5 ( votes: 8)    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>Zar\u00f3wno Python, jak i Java, to j\u0119zyki programowania ciesz\u0105ce si\u0119 w ostatnich latach nies\u0142abn\u0105c\u0105 popularno\u015bci\u0105. Nie dziwi zatem fakt, i\u017c &hellip; <a class=\"continued-btn\" href=\"https:\/\/sii.pl\/blog\/python-vs-java-podstawowe-roznice-w-podejsciu-do-programowania-obiektowego\/\">Continued<\/a><\/p>\n","protected":false},"author":582,"featured_media":28532,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_editorskit_title_hidden":false,"_editorskit_reading_time":0,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","inline_featured_image":false,"footnotes":""},"categories":[1314],"tags":[1528,1512,1095,330,584],"class_list":["post-28528","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development-na-twardo","tag-jezyk-programowania","tag-poradnik","tag-sciezki-karier","tag-java","tag-python"],"acf":[],"aioseo_notices":[],"republish_history":[],"featured_media_url":"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2024\/07\/Programowanie-obiektowe-na-przykladzie-Pythona.jpg","category_names":["Development na twardo"],"_links":{"self":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/28528"}],"collection":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/users\/582"}],"replies":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/comments?post=28528"}],"version-history":[{"count":3,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/28528\/revisions"}],"predecessor-version":[{"id":29685,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/28528\/revisions\/29685"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media\/28532"}],"wp:attachment":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media?parent=28528"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/categories?post=28528"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/tags?post=28528"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}