Rozróżnianie wielkości liter nazw klas Java

Jeśli ktoś zapisuje dwie publiczne klasy Java o tej samej nazwie bez rozróżniania wielkości liter w różnych katalogach, to obie klasy nie mogą być używane w czasie wykonywania. (Przetestowałem to na Windowsie, Macu i Linuksie z kilkoma wersjami JVM HotSpot. Nie byłbym zaskoczony, gdyby były tam inne maszyny JVM, w których mogą być używane jednocześnie.) Na przykład, jeśli utworzę klasę o nazwiea i jeden nazwanyA w ten sposób:

// lowercase/src/testcase/a.java
package testcase;
public class a {
    public static String myCase() {
        return "lower";
    }
}

// uppercase/src/testcase/A.java 
package testcase;
public class A {
    public static String myCase() {
        return "upper";
    }
}

Trzy projekty zaćmień zawierające powyższy kod sądostępne na mojej stronie.

Jeśli spróbuję zadzwonićmyCase w obu klasach:

System.out.println(A.myCase());
System.out.println(a.myCase());

Sprawdzanie typu kodu powiedzie się, ale gdy uruchomię plik klasy generujący kod bezpośrednio powyżej, otrzymuję:

Wyjątek w wątku „main” java.lang.NoClassDefFoundError: testcase / A (błędna nazwa: testcase / a)

W Javie nazwy są zazwyczaj wrażliwe na wielkość liter. Niektóre systemy plików (np. Windows) nie uwzględniają wielkości liter, więc nie jestem zaskoczony, że powyższe zachowanie ma miejsce, ale wydaje sięźle. Niestety specyfikacje Java są dziwnie niezobowiązujące co do tego, które klasy są widoczne. TheJava Language Specification (JLS), Java SE 7 Edition (Rozdział 6.6.1, strona 166) mówi:

Jeśli klasa lub typ interfejsu jest zadeklarowany jako publiczny, można uzyskać do niego dostęp za pomocą dowolnego kodu, pod warunkiem, że jednostka kompilacji (§ 7.3), w której jest zadeklarowana, jest obserwowalna.

W rozdziale 7.3 JLS definiuje obserwowalność jednostki kompilacyjnej w bardzo mglistych terminach:

Wszystkie jednostki kompilacji predefiniowanego pakietu java i jego podpakietów lang i io są zawsze obserwowalne. Dla wszystkich innych pakietówsystem hosta określa, które jednostki kompilacji są obserwowalne.

TheSpecyfikacja wirtualnej maszyny Java jest podobnie niejasne (sekcja 5.3.1):

Następujące kroki są używane do ładowania i tworzenia w ten sposób klasy lub interfejsu C, oznaczonego jako [nazwa binarna] N przy użyciu programu ładującego klasy ładującej [...] W przeciwnym razie wirtualna maszyna Java przekazuje argument N do wywołania metody na program ładujący klasy bootstrap do wyszukiwania rzekomej reprezentacji C w sposób zależny od platformy.

Wszystko to prowadzi do czterech pytań w kolejności malejącej ważności:

Czy są jakieś gwarancje, które klasy są ładowane przez domyślne programy ładujące klasy w każdej maszynie JVM? Innymi słowy, czy mogę zaimplementować poprawną, ale zdegenerowaną maszynę JVM, która nie załaduje żadnych klas oprócz tych w java.lang i java.io?Jeśli istnieją jakiekolwiek gwarancje, czy zachowanie w powyższym przykładzie narusza gwarancję (tj. Czy zachowanie jest błędem)?Czy jest jakiś sposób na załadowanie HotSpotaa iA równocześnie? Czy napisanie niestandardowego programu ładującego klasy działa?

questionAnswers(3)

yourAnswerToTheQuestion