Nie byłem w sytuacji, w której błąd kompilatora spowodowany tymi słowami kluczowymi uratowałby mnie przed błędem.
Nie tyle zapisywanie autorów aplikacji przed błędami, co pozwalanie autorom bibliotek decydować, które części ich implementacji zobowiązują się utrzymywać.
Jeśli mam bibliotekę
class C {
public void foo() { ... }
private void fooHelper() { /* lots of complex code */ }
}
Mogę chcieć zastąpić foo
wdrożenie i ewentualnie zmienić się fooHelper
radykalnie. Jeśli grupa osób zdecydowała się użyć fooHelper
pomimo wszystkich ostrzeżeń w mojej dokumentacji, być może nie będę w stanie tego zrobić.
private
pozwala autorom bibliotek rozkładać biblioteki na możliwe do zarządzania metody (i private
klasy pomocnicze) bez obawy, że będą zmuszeni do zachowania tych wewnętrznych szczegółów przez lata.
Co byłoby warte wymuszenia ukrywania informacji przez kompilator?
Na marginesie, w Javie private
nie jest egzekwowany przez kompilator, ale przez weryfikator kodu bajtowego Java .
Czy odbicie może zastąpić ten mechanizm? Co byłoby warte wymuszenia ukrywania informacji przez kompilator?
W Javie nie tylko odbicie może zastąpić ten mechanizm. Istnieją dwa rodzaje private
Java. Tego rodzaju private
uniemożliwia jednej klasie zewnętrznej dostęp do elementów innej klasy zewnętrznej, private
co jest sprawdzane przez weryfikator kodu bajtowego, ale także tych, private
które są używane przez klasę wewnętrzną za pomocą metody prywatnego syntetycznego akcesorium pakietu jak w
public class C {
private int i = 42;
public class B {
public void incr() { ++i; }
}
}
Ponieważ klasa B
(naprawdę nazwana C$B
) używa i
, kompilator tworzy syntetyczną metodę akcesora, która pozwala B
na dostęp C.i
w sposób, który mija weryfikator kodu bajtowego. Niestety, ponieważ ClassLoader
pozwala ci stworzyć klasę z byte[]
, dość łatwo jest dostać się do szeregowców, którzy C
wystawili się na klasy wewnętrzne, tworząc nową klasę w C
pakiecie, co jest możliwe, jeśli C
słoik nie został zapieczętowany.
Właściwe private
egzekwowanie wymaga koordynacji między modułami ładującymi, weryfikatorem kodu bajtowego i polityką bezpieczeństwa, która może uniemożliwić odbijający dostęp do szeregowych.
Czy można go wykorzystać do zabezpieczenia tajnego stanu klasy przed atakiem?
Tak. „Bezpieczny rozkład” jest możliwy, gdy programiści mogą współpracować, zachowując jednocześnie właściwości bezpieczeństwa swoich modułów - nie muszę ufać autorowi innego modułu kodu, aby nie naruszył właściwości bezpieczeństwa mojego modułu.
Języki Object Objectabilities, takie jak Joe-E, wykorzystują ukrywanie informacji i inne środki umożliwiające bezpieczny rozkład:
Joe-E jest podzbiorem języka programowania Java zaprojektowanym do obsługi bezpiecznego programowania zgodnie z dyscypliną możliwości obiektowych. Joe-E ma na celu ułatwienie budowy bezpiecznych systemów, a także ułatwienie przeglądów bezpieczeństwa systemów zbudowanych w Joe-E.
Dokument połączony z tej strony podaje przykład, w jaki sposób private
egzekwowanie umożliwia bezpieczny rozkład.
Zapewnia bezpieczne enkapsulację.
Rysunek 1. Funkcja rejestrowania tylko z dołączaniem.
public final class Log {
private final StringBuilder content;
public Log() {
content = new StringBuilder();
}
public void write(String s) {
content.append(s);
}
}
Rozważmy ryc. 1, która ilustruje, w jaki sposób można zbudować narzędzie do rejestrowania tylko z dołączaniem. Pod warunkiem, że reszta programu jest napisana w Joe-E, recenzent kodu może mieć pewność, że wpisy dziennika można tylko dodawać, a nie można ich modyfikować ani usuwać. Ta recenzja jest praktyczna, ponieważ wymaga jedynie kontroli Log
klasy i nie wymaga przeglądu żadnego innego kodu. W związku z tym weryfikacja tej właściwości wymaga tylko lokalnego uzasadnienia dotyczącego kodu rejestrowania.