Чувствительность к регистру в именах классов Java

Если написать два общедоступных класса Java с одним и тем же нечувствительным к регистру именем в разных каталогах, то оба класса нельзя будет использовать во время выполнения. (Я тестировал это на Windows , Mac и Linux с несколькими версиями JVM HotSpot. Я не удивлюсь, если есть другие JVM, где их можно использовать одновременно.) Например, если я создам класс с именем aи класс с именем Aпримерно так:

// 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";
    }
}

Три проекта eclipse, содержащие приведенный выше код, доступны на моем веб-сайте.

Если попытаться вызвать myCaseдля обоих классов следующим образом:

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

Проверка типов выполняется успешно, но когда я запускаю файл класса, сгенерированный кодом, приведенным выше, я получаю:

Исключение в потоке " main" java.lang.NoClassDefFoundError: testcase/A (неправильное имя: testcase/a)

В Java имена обычно чувствительны к регистру. Некоторые файловые системы (например, Windows) нечувствительны к регистру, поэтому я не удивлен, что происходит вышеописанное, но кажется неправильным. К сожалению, спецификации Java странно уклончивы в отношении того, какие классы видны. Спецификация языка Java (JLS), Java SE 7 Edition(раздел 6.6.1, стр. 166) гласит:

Если класс или тип интерфейса объявлен общедоступным, доступ к нему может осуществляться любой код при условии, что единица компиляции (§7.3), в которой он объявлен, наблюдаемый.

В Разделе 7.3 JLS определяет наблюдаемость единицы компиляции в очень расплывчатых терминах:

Все единицы компиляции предопределенного пакета java и его подпакетов lang и io всегда доступны для наблюдения. Для всех остальных пакетов хост-система определяет, какие единицы компиляции являются наблюдаемыми.

Спецификация виртуальной машины Javaтакже расплывчата (раздел 5.3.1):

Следующие шаги используются для загрузки и, таким образом, создания класса без массива или интерфейс C, обозначенный [бинарное имя] N с использованием загрузчика классов начальной загрузки [...] В противном случае виртуальная машина Java передает аргумент N вызову метод в загрузчике классов начальной загрузки для поиска предполагаемого представления C в зависимости от платформы.

Все это приводит к четырем вопросам в порядке убывания важности:

  1. Существуют ли какие-либо гарантии того, какие классы загружаются загрузчиком классов по умолчанию в каждой JVM? Другими словами, могу ли я реализовать допустимую, но вырожденную JVM, которая не будет загружать никакие классы, кроме классов java.lang и java.io?
  2. Если есть какие-либо гарантии, нарушает ли поведение в приведенном выше примере гарантию (т. е. является ли поведение ошибкой)?
  3. Есть ли способ заставить HotSpot загружать aи Aодновременно? Будет ли работать написание собственного загрузчика классов?

47
задан JasonMArcher 21 October 2014 в 21:09
поделиться