Mam w projekcie dwa pakiety: odp.proj
i odp.proj.test
. Są pewne metody, które chcę, aby były widoczne tylko dla klas w tych dwóch pakietach. W jaki sposób mogę to zrobić?
EDYCJA: Jeśli w Javie nie ma koncepcji podpakietu, czy można to obejść? Mam pewne metody, które chcę, aby były dostępne tylko dla testerów i innych członków tego pakietu. Czy powinienem po prostu wrzucić wszystko do tego samego opakowania? Zastosuj obszerną refleksję?
java
package
visibility
encapsulation
Nick Heiner
źródło
źródło
Odpowiedzi:
Nie możesz. W Javie nie ma pojęcia o podpakiecie, tak
odp.proj
iodp.proj.test
są całkowicie oddzielne pakiety.źródło
Nazwy twoich pakietów wskazują, że aplikacja tutaj służy do testowania jednostkowego. Typowym wzorcem jest umieszczenie klas, które chcesz przetestować, i kodu testu jednostkowego w tym samym pakiecie (w twoim przypadku
odp.proj
), ale w różnych drzewach źródłowych. Więc umieściłbyś swoje klasysrc/odp/proj
i kod testowy wtest/odp/proj
.Java ma modyfikator dostępu „pakiet”, który jest domyślnym modyfikatorem dostępu, gdy żaden nie jest określony (tj. Nie określono publicznego, prywatnego lub chronionego). Z modyfikatorem dostępu „pakiet” tylko klasy w
odp.proj
będą miały dostęp do metod. Należy jednak pamiętać, że w Javie nie można polegać na modyfikatorach dostępu do wymuszania reguł dostępu, ponieważ po odbiciu możliwy jest każdy dostęp. Modyfikatory dostępu są jedynie sugestywne (chyba że obecny jest restrykcyjny menedżer bezpieczeństwa).źródło
To nie jest żaden szczególny związek między
odp.proj
iodp.proj.test
- tak się składa, że nazywa się je pozornie spokrewnionymi.Jeśli pakiet odp.proj.test po prostu udostępnia testy, możesz użyć tej samej nazwy pakietu (
odp.proj
). IDE, takie jak Eclipse i Netbeans, utworzą oddzielne foldery (src/main/java/odp/proj
isrc/test/java/odp/proj
) z tą samą nazwą pakietu, ale z semantyką JUnit.Zauważ, że te IDE wygenerują testy dla metod w
odp.proj
i utworzą odpowiedni folder dla metod testowych, których nie ma.źródło
Kiedy robię to w IntelliJ, moje drzewo źródłowe wygląda następująco:
źródło
Prawdopodobnie zależy to trochę od twoich motywów ich niewyświetlania, ale jeśli jedynym powodem jest to, że nie chcesz zanieczyszczać publicznego interfejsu rzeczami przeznaczonymi tylko do testowania (lub inną wewnętrzną rzeczą), umieściłbym te metody w oddzielny interfejs publiczny i niech konsumenci metod „ukrytych” używają tego interfejsu. Nie powstrzyma to innych przed korzystaniem z interfejsu, ale nie widzę powodu, dla którego powinieneś.
W przypadku testów jednostkowych i jeśli jest to możliwe bez przepisywania partii, postępuj zgodnie z sugestiami, aby użyć tego samego pakietu.
źródło
Jak wyjaśnili inni, w Javie nie ma czegoś takiego jak „podpakiet”: wszystkie pakiety są izolowane i nie dziedziczą niczego po swoich rodzicach.
Łatwym sposobem uzyskania dostępu do chronionych elementów członkowskich z innego pakietu jest rozszerzenie klasy i zastąpienie elementów członkowskich.
Na przykład, aby uzyskać dostęp
ClassInA
w pakieciea.b
:utwórz klasę w tym pakiecie, która przesłania metody, których potrzebujesz w
ClassInA
:Dzięki temu możesz użyć klasy nadpisującej zamiast klasy z innego pakietu:
Zauważ, że działa to tylko dla chronionych elementów członkowskich, które są widoczne dla klas rozszerzających (dziedziczenie), a nie dla prywatnych członków pakietu, które są widoczne tylko dla klas podrzędnych / rozszerzających w tym samym pakiecie. Mam nadzieję, że to komuś pomoże!
źródło
Większość odpowiedzi stwierdzała, że w Javie nie ma czegoś takiego jak podpakiet, ale nie jest to do końca dokładne. Termin ten znajdował się w specyfikacji języka Java już w Javie 6 i prawdopodobnie później (nie wydaje się, aby istniała swobodnie dostępna wersja JLS dla wcześniejszych wersji Java). Język wokół podpakietów nie zmienił się zbytnio w JLS od czasu Java 6.
Java 13 JLS :
Koncepcja podpakietu jest istotna, ponieważ wymusza ograniczenia nazewnictwa między pakietami i klasami / interfejsami:
Jednak to ograniczenie nazewnictwa jest jedynym znaczeniem, jakie język nadaje podpakietom:
W tym kontekście możemy odpowiedzieć na samo pytanie. Ponieważ wyraźnie nie ma specjalnej relacji dostępu między pakietem a jego podpakietem lub między dwoma różnymi podpakietami pakietu nadrzędnego, w języku nie ma możliwości, aby metoda była widoczna dla dwóch różnych pakietów w żądany sposób. Jest to udokumentowana, celowa decyzja projektowa.
Albo metodę można upublicznić, a wszystkie pakiety (w tym
odp.proj
iodp.proj.test
) będą mogły uzyskać dostęp do podanych metod, albo metoda może zostać ustawiona jako prywatna (domyślna widoczność), a cały kod, który musi uzyskać bezpośredni dostęp, musi zostać umieszczony ten sam (pod) pakiet co metoda.To powiedziawszy, bardzo standardową praktyką w Javie jest umieszczanie kodu testowego w tym samym pakiecie co kod źródłowy, ale w innym miejscu w systemie plików. Na przykład w narzędziu do kompilacji Maven konwencja będzie taka, aby umieścić te pliki źródłowe i testowe odpowiednio w
src/main/java/odp/proj
isrc/test/java/odp/proj
. Kiedy narzędzie kompilacji to kompiluje, oba zestawy plików trafiają doodp.proj
pakietu, ale tylko tesrc
pliki są uwzględniane w artefakcie produkcyjnym; pliki testowe są używane tylko w czasie kompilacji do weryfikacji plików produkcyjnych. Dzięki tej konfiguracji kod testowy może swobodnie uzyskiwać dostęp do dowolnego kodu prywatnego lub chronionego kodu testowanego kodu, ponieważ będą one znajdować się w tym samym pakiecie.W przypadku, gdy chcesz udostępniać kod między podpakietami lub pakietami rodzeńskimi, które nie są przypadkiem testowym / produkcyjnym, jednym z rozwiązań, które widziałem w niektórych bibliotekach, jest umieszczenie tego udostępnionego kodu jako publicznego, ale udokumentuj, że jest on przeznaczony dla biblioteki wewnętrznej tylko do użytku.
źródło
Bez umieszczania modyfikatora dostępu przed metodą mówisz, że jest to pakiet prywatny.
Spójrz na poniższy przykład.
źródło
Z klasą PackageVisibleHelper i zachowując ją jako prywatną przed zamrożeniem PackageVisibleHelperFactory, możemy wywołać metodę launchA (przez PackageVisibleHelper) w dowolnym miejscu :)
źródło