Создание пользовательского класса String

Я попытался создать пользовательский класс String в пакете java.lang в рабочей области eclipse. первоначально я подозревал, что один и тот же класс в одном пакете не может быть создан, но, к моему полному удивлению, мне удалось создать класс (String) в том же пакете, то есть java.lang

Теперь я запутался
1) почему это возможно и 2) что может быть причиной, если это разрешено.
3) какой будет использование, если этот тип создания классов Java разрешен в Java.

Ответ 1

Вы можете создать новый класс в пакете java.lang. Если было запрещено, как разработчики Oracle могли бы вообще развивать Java? Я уверен, что они используют тот же javac, что и мы.

Но вы не сможете загрузить его, потому что java.lang.ClassLoader(который распространяется любой загрузчик классов) не позволяет этого, каждый загружаемый класс проходит через эту проверку

...
        if ((name != null) && name.startsWith("java.")) {
            throw new SecurityException
                ("Prohibited package name: " + name.substring(0, name.lastIndexOf('.')));
        }
...

чтобы вы оказались в чем-то вроде

Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.lang
    at java.lang.ClassLoader.preDefineClass(ClassLoader.java:649)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:785)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    at Test1.main(Test1.java:11)

Что касается классов, которые теневают существующие классы, такие как ваш java.lang.String, они не могут быть загружены, потому что System ClassLoader (по умолчанию один) использует стратегию "родительский первый", поэтому классы java.lang будут загружаться из rt.jar с помощью загрузчика bootstrap. Поэтому вам нужно будет заменить String.class в rt.jar вашей версией. Или переопределить его с помощью опции -Xbootclasspath/p: java, которая добавляет пути к пути поиска загрузчика класса загрузки. Таким образом, вы можете

1) copypaste real String.java содержимое в ваш String.java

2) измените метод, например

public static String valueOf(double d) {
    return "Hi";
}

и скомпилируйте свой String.java

3) создать тестовый класс

public class Test1 {

    public static void main(String[] args) throws Exception {
        System.out.println(String.valueOf(1.0d));
    }
}

4) запустите его как

java -Xbootclasspath/p:path_to_your_classes Test1

и вы увидите

Hi

Ответ 2

Это называется затенением класса.

1.) Это возможно, потому что классы Java не статически связаны, а связаны с временем загрузки класса.

2.) Если бы это было не разрешено, то вся загрузка класса была бы намного сложнее. Тогда, например, вам также придется создавать свой проект против конкретной версии Java. потому что классы Java могут меняться от версии к версии. Это не будет поддерживаемым подходом.

3.) osgi использует это, чтобы иметь возможность загружать разные версии одного и того же пакета. Другим распространенным вариантом использования является замена багги-классов в фреймворках, где нет другого способа обхода пути. Однако этот метод следует использовать осторожно, потому что ошибки могут быть трудно отлаживать.

Обратите внимание, что, тем не менее, классы затенения в пакетах java. * недопустимы, так как это сломает изолированную программную среду Java. Таким образом, у вас будут проблемы во время выполнения.

Ответ 3

Да, вы можете создать пакет с именем java.lang, а также классом с именем Строка.

Но вы не сможете запустить свой класс String.

1) почему это возможно: Компилятор успешно скомпилирует ваш класс.

2) , что может быть причиной, если это разрешено: У вас есть допустимое имя для вашего пакета и класса, поэтому компилятор не жалуется.

3) , что будет использовать, если этот тип создания классов Java разрешен в Java:. Но этот класс String не так много используется. Загрузочный класс Bootstrap загрузит класс из пакета sun java.lang. Таким образом, ваш пользовательский класс String не будет загружен и, следовательно, он не сработает во время выполнения.

Загрузочный загрузчик класса Bootstrap является частью реализации JVM и загружает классы Java API (который включает java.lang.String). Также для каждого загружаемого класса JVM отслеживает, какой загрузчик класса загружен или загружен пользователем. Поэтому любая попытка загрузить пользовательский класс String завершится неудачно, поскольку класс String уже загружен.