• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Wnioskowanie typu, a dostęp do pola prywatnego

Object Storage Arubacloud
+1 głos
246 wizyt
pytanie zadane 7 grudnia 2022 w Java przez Whiskey_Taster Pasjonat (15,610 p.)

Mam sobie pusty interfejs InterFace i taki oto kod

public static void main(String[] args) {

        var test = new InterFace() {
          private int count = 0;  
        };
        
        System.out.println(test.count);
    }

Pytanie brzmi: dlaczego używając wnioskowania typu, mam dostęp do prywatnego pola obiektu test? Gdy zamiast var użyć po prostu InterFace, wówczas naturalnie nie mam dostępu do pola count.

2 odpowiedzi

+2 głosów
odpowiedź 8 grudnia 2022 przez VBService Ekspert (253,340 p.)

W pewnym sensie w drugiej części pytania

Gdy zamiast var użyć po prostu InterFace, wówczas naturalnie nie mam dostępu do pola count.

sam sobie udzieliłeś odpowiedzi, bo użycie wnioskowania typu w podanym kodzie pozwala dostać się do prywatnego pola count obiektu test, ponieważ występuje tam błąd składni. Zamiast tworzyć anonimową implementację interfejsu InterFace i używać var, należy użyć nazwy klasy, która implementuje ten interfejs np.

InterFace test = new InterFaceImpl() {
    private int count = 0;  
};

W powyższym kodzie została utworzona klasa anonimowa, która dziedziczy po klasie InterFaceImpl i implementuje interfejs InterFace. Klasa ta zawiera prywatne pole count, które nie jest dostępne z zewnątrz, ponieważ jest ono prywatne.

Jeśli chcesz mieć dostęp do pola count, musisz je zadeklarować jako publiczne lub dostarczyć publiczne metody dostępu (gettery i settery) do tego pola. Wówczas będziesz mógł uzyskać dostęp do tego pola za pomocą wywołania np. test.getCount().

 

BTW, wnioskowanie typu (var) w Twoim kodzie nie ma znaczenia dla dostępu do pola count, ponieważ jest to błąd składni. Użycie var pozwala zapisać kod w sposób bardziej skrócony, ale nie zmienia to faktu, że należy użyć nazwy klasy, która implementuje interfejs, aby utworzyć obiekt.

2
komentarz 8 grudnia 2022 przez Wiciorny Ekspert (270,110 p.)
edycja 8 grudnia 2022 przez Wiciorny

troche tak, ale nie do końca. Dostęp jest blokowany przez kompilator, gdyż nie ważne z jakim obiektem mamy do czynienia, najważniejsze jest na jaki TYP referencji wskazuje dany obiekt i tylko ten typ referencji danej zmiennej umożliwia korzystanie z elementów w ramach tej referencji. 
Co ciekawe Java umożliwia  keyword var do bycia generycznym w ramach rozwiązania
Co dokladnie powoduje, że typ referencyjny będzie rozpoznawany:
 

Var<Object> v = new Var<Object>(); //blad
var v = new Var<Object>(); // to juz nie 

 Natomiast dostęp do prywatnej zmiennej jest możliwy tylko dlatego, że var jest ograniczone w Javie i nie ma możliwości korzystania z niego w innym kontekście niż lokalny, a lokalność zapewnia gwarancje znajomości i zachowania hermetyzacji w ramach aktualnie wykonywanej metody na stosie.
Var wywnioskuje sobie typ samodzielnie  traktując referencje obiektu który został przypisany " jako kontekst this" - a że to/ to jest "to" to mam dostęp do tego co jest moje. 

I jeszcze tylko jedno 

Zamiast tworzyć anonimową implementację interfejsu InterFace i używać var, należy użyć nazwy klasy, która implementuje ten interfejs np.
 

To nie jest to samo, to są dwa inne rozwiązania używanie var nie jest wymienne z tworzeniem klasy anonimowej, przeznaczenie jest totalne inne i tak naprawdę masz odczynienia z dwiema innymi rzeczami.  

Reszta fajnie wyjaśniona.

komentarz 8 grudnia 2022 przez Whiskey_Taster Pasjonat (15,610 p.)

Co nieco mi Panowie rozjaśnili, a już na pewno 

Natomiast dostęp do prywatnej zmiennej jest możliwy tylko dlatego, że var jest ograniczone w Javie i nie ma możliwości korzystania z niego w innym kontekście niż lokalny, a lokalność zapewnia gwarancje znajomości i zachowania hermetyzacji w ramach aktualnie wykonywanej metody na stosie.

ten fragment odpowiedział na moje pytanie. Tak coś myślałem, że ma to związek z lokalnością samej zmiennej, ale nie wiedziałem, że tak zadziała wraz z klasą anonimową. 

Nie rozumiem tylko jednej rzeczy, mianowicie:

BTW, wnioskowanie typu (var) w Twoim kodzie nie ma znaczenia dla dostępu do pola count, ponieważ jest to błąd składni.

 Co tutaj jest "błędem składni"? Możemy zarówno implementować interfejs, jak i rozszerzać klasę przy pomocy klasy anonimowej. Rozumiem już, że użycie var pociąga za sobą lokalność, a więc i dostęp do zmiennych, ale to nie zmienia faktu, że kompilator sam wytypuje typ obiektu jako InterFace

komentarz 8 grudnia 2022 przez VBService Ekspert (253,340 p.)
edycja 8 grudnia 2022 przez VBService
AFAIK

Błędem składni jest użycie słowa kluczowego var (w tym kontekście) w deklaracji zmiennej test, ponieważ var służy do deklarowania zmiennych bez konkretnego typu, a w tym przypadku typ zmiennej jest wyraźnie zdefiniowany jako anonimowa implementacja interfejsu InterFace. W tej sytuacji należy użyć pełnego typu zmiennej, czyli InterFace zamiast var, aby uniknąć błędu składni.

Jeśli chodzi o dostęp do pola count, to fakt, że test jest typu InterFace nie ma tutaj znaczenia, ponieważ test jest deklarowane jako anonimowa implementacja interfejsu InterFace, a więc nie ma dostępu do pól lub metod interfejsu, w tym do pola count. Aby mieć dostęp do pola count, należy zadeklarować je jako publiczne lub dostarczyć publiczną metodę dostępową, która umożliwi dostęp do tego pola z poziomu klasy main.
komentarz 8 grudnia 2022 przez Whiskey_Taster Pasjonat (15,610 p.)

ponieważ var służy do deklarowania zmiennych bez konkretnego typu, a w tym przypadku typ zmiennej jest wyraźnie zdefiniowany jako anonimowa implementacja interfejsu InterFace

Z tego co wiem, w Javie nie ma czegoś takiego, jak zmienna bez konkretnego typu. Przecież używając var już nawet sam kompilator podpowiada, jaki typ ma zmienna. Ja wiem, że używamy var, aby poprawić czytelność, na przykład:
 

var userChannels = new HashMap<User, List<String>>();

jednak wciąż jest to konkretny typ. 

ponieważ test jest deklarowane jako anonimowa implementacja interfejsu InterFace, a więc nie ma dostępu do pól lub metod interfejsu

A tutaj to w ogóle się gubię. Sam nawet napisałeś, że jest to "anonimowa implementacja interfejsu", a więc ogółem jest to klasa, która implementuje dany interfejs, stąd wręcz musi mieć dostęp do metod interfejsu. Tak samo samo pole count nie znajduje się w interfejsie, tylko należy do klasy anonimowej, która owy interfejs implementuje. 

Aby mieć dostęp do pola count, należy zadeklarować je jako publiczne lub dostarczyć publiczną metodę dostępową, która umożliwi dostęp do tego pola z poziomu klasy main.

No tak, ogółem samo pytanie "dlaczego użycie var pozwala to ominąć w klasach anonimowych" zrodziło się, bo zobaczyłem tę "sztuczkę" w jakimś kodzie, a kłóciło mi się to z ideą pól prywatnych i brakiem getterów. 

2
komentarz 9 grudnia 2022 przez Wiciorny Ekspert (270,110 p.)
edycja 9 grudnia 2022 przez Wiciorny

wszystko co jest w zasięgu lokalnym jest prywatne... dlatego masz dostęp...
A gwarancję tego, że typ będzie mógł być wywnioskowany na etapie kompilacji daje  właśnie ten zakres i dzieki temu i tak Java dobrze wie, że te dane są hermetyczne.

Jakbyś miał doświadczenie jako programista Java byś wiedział do razu. Po pierwsze lokalnie wszystko znajduje się na stosie w kolejności deklaracji  - więc po prostu skoro  tutaj została inicjalizowana klasa anonimowa to ona jest kompilowana na stos pierwsza stąd wszystko jest widoczne.
jakbyś sprawdził jak wygląda "klasa- plik po kompilacji" to byś widział, polecam miec taką znajomość chyba, że Java to nie twój język i robisz cos 4fun.  
Ale to są podstawy kompilowania programu do plików wykonawczych.

Tak samo jak napiszesz lokalnie private final String value= "wartosc"; to masz to widoczne lokalnie, tak samo jest tutaj

I ostatnie - klasą anonimową tworzysz INSTANCJE/EGZEMPLARZ a instancja ma dostęp do swojego pola w lini  System.out.println(test.count); odwołujesz się do obiektu który w tym zakresie jest utworzony, a w swoim zakresie wszystko ma widoczne
kod

1
komentarz 10 grudnia 2022 przez Whiskey_Taster Pasjonat (15,610 p.)

Jakbyś miał doświadczenie jako programista Java byś wiedział do razu.

To się rozumie samo przez się, ale nie mam.  

jakbyś sprawdził jak wygląda "klasa- plik po kompilacji" to byś widział

O, i to jest myśl. Będąc szczerym, nigdy tego nie robiłem, a faktycznie można by się wiele dowiedzieć w ten sposób. 

polecam miec taką znajomość chyba, że Java to nie twój język i robisz cos 4fun

 Właśnie jakiś czas temu odkryłem w sobie zamiłowanie do Javy, więc od jakichś czterech, góra pięciu miesięcy staram się pogłębiać wiedzę. Stąd też moja dociekliwość. 

Ogółem wszystko stało się już jasne, co i dlaczego, więc na sam koniec miałbym jedno pytanie: jak sobie otworzyć takiego inspektora, jak to zaprezentowałeś u góry? 

+2 głosów
odpowiedź 8 grudnia 2022 przez Wiciorny Ekspert (270,110 p.)
edycja 8 grudnia 2022 przez Wiciorny

Popatrz na przykład:
 

package com.jadevirek.eventbooking.model.converters;

public class OverTheHood {

  public static void main(String[] args) {
    // ponizszy kod totalnie nie ma sensu, gdyz tworzy Ci lokalny obiekt/instancje typu InterFace
    // Widziany tylko w zakresie lokalnym, stad wszystko co lokalnie deklarowane jest widziane lokalnie. 
    var test = new InterFace() {
      private int count = 0;
      public int defaultCount = 100;
    };
    overTheHoodMethod(test);
    System.out.println(test.count);
    System.out.println(test.defaultCount);
  }

  private static void overTheHoodMethod(InterFace test) {
    //Brak dostepu do wlasciwosci.  nawet publicznej...
    // gdyż nie są one czescia interfejsu...
    System.out.println(test);
    var test2 = test;
  }
}

interface InterFace {

}



Var sciagą Ci typ, tak naprawdę w zakresie lokalnym twoja instancja staje się "bez-płciowa", nie ma znaczenia jaki ma Typ gdyż przez to że jest on przypisany to var - traci swoje właściwości, a jedynie staje się obiektem lokalnym, a  wszystko w zakresie lokalnym jest w zakresie hermetycznym więc jest widzialne przez program.

Jeśli typ byłby zachowany i dalej referencja przypisana do słówka "var" byłaby rozpoznawana, wtedy  pro paginując zmiany do innej metody  obiekt byłby rozpoznawalny i możliwy byłby dostęp do publicznego pola, a nie jest... gdy przekazując zmienna, przekazana jest tylko znajomość LOKALNEGO TYPU, a skoro zewnętrzny interfejs (jako typ) nie ma właściwości, to jego lokalna instancja jak kolega napisał zwana klasą anonimową nie może zostać przekazana, gdyż java PRZEKAZUJE WARTOŚC REFERENCJI do typu, a nie obiekt/instancje bezpośrednio.


Ten zapis ze słówkiem kluczowym var nie ma totalnie sensu i zastosowania a jak już słusznie zostało powiedziane jest to błąd składni a dlaczego dlatego że tworzymy klasę anonimową którą moglibyśmy wykorzystać do nadpisywania jakichś zmian w danym kontekście lub skorzystania z proxy których nie możemy wykorzystać przez to gdyż przypisujemy je do zmiennej var.

Klasy anonimowe są dobre kiedy chcemy zablokować jakieś mechanizmy refleksji lub skorzystać z jakiegoś dynamicznego nadpisania zachowania ale to działa i tak tylko i wyłącznie lokalnie dlaczego prywatne właściwości w takim razie są dostępne i widziane lokalnie dlatego że lokalny zakres jest prywatny i Java dobrze wie że ten obiekt poza nie istnieje szczególnie gdy jest przypisany do war

Ważny inny przypadek, żebyś zrozumiał czym w ogółem jest typ referencyjny i dlaczego to takie istotne w kontekście zakresu dostępu.
 

public class OverTheHood {

  public static void main(String[] args) {
    var test = new InterFace() {
      private int count = 50;
      public int defaultCount = 100;

      @Override
      public int someCalculation() {
        return count+defaultCount;
      }
    };
    System.out.println(test.count);
    System.out.println(test.defaultCount);
    System.out.println(test.someCalculation());
    overTheHoodMethod(test);
  }
  // Z faktu, ze java to jezyk obiektowy silnie typowany i zmienne sa wskaznikami do 
  // wartosci referencji, a nie sama referencja. Dalej 
  private static void overTheHoodMethod(InterFace test) {
    // w tym wypadku staje się to dosyć niebezpieczne.
    System.out.println("From over-theHood."); 
    System.out.println(test.someCalculation()); //150 
    var  assignTest= test;
    // jednak w tym wypadku nie mozna wywolac juz metody...
   // test.someCalculation()
  }
}

interface InterFace {
  int someCalculation();
}

 

komentarz 8 grudnia 2022 przez Whiskey_Taster Pasjonat (15,610 p.)

To może po kolei: 

W pierwszym przykładzie test jest obiektem lokalnym oraz deklaracja pól odbywa się również lokalnie, stąd ta widoczność w metodzie main. Z kolei jeśli przekazujemy referencję obiektu test do metody overTheHoodMethod, to tak jakby tracimy informację o tym, że jest to klasa anonimowa i traktujemy ten sam obiekt jako pewną instancję interfejsu InterFace, a więc nie mamy dostępu do żadnych pól, jedynie mamy dostęp do metod tego interfejsu. 

I ogółem fajnie - rozumiem wszystko, czym jest błąd składni i tak dalej, bardzo mi to rozjaśniliście. Ale jeszcze mam pytanie co do drugiego przykładu, mianowicie ostatni komentarz: "jednak w tym wypadku nie mozna wywolac juz metody..." - dlaczego? Przecież pomimo tego, że oryginalny typ jest nieznany, to jednak wiemy, że test jest instancją klasy implementującej interfejs InterFace, stąd też metoda someCalculation() musi być zaimplementowana przez ten obiekt, a więc mamy do niej dostęp. I rzeczywiście, jeśli dopisać w metodzie overTheHoodMethod kod 
 

System.out.println(test.someCalculation());
System.out.println(assignTest.someCalculation());

to wszystko się zgadza. Co innego, gdybyśmy uprzednio dodali jakąś metodę podczas deklaracji naszej anonimowej klasy. 

Podobne pytania

0 głosów
1 odpowiedź 359 wizyt
pytanie zadane 6 lipca 2019 w Java przez miro Pasjonat (23,870 p.)
0 głosów
1 odpowiedź 835 wizyt
pytanie zadane 1 lutego 2018 w Java przez rubesom Obywatel (1,690 p.)
+4 głosów
1 odpowiedź 251 wizyt
pytanie zadane 18 lutego 2022 w JavaScript przez rafal.budzis Szeryf (85,260 p.)

92,570 zapytań

141,422 odpowiedzi

319,643 komentarzy

61,958 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...