Если написать два общедоступных класса 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 в зависимости от платформы.
Все это приводит к четырем вопросам в порядке убывания важности:
a
и A
одновременно? Будет ли работать написание собственного загрузчика классов?