Помогите пожалуйста разобраться с динамической загрузкой классов в java. Как я понимаю, при старте программы загружаются классы из rt.jar, потом загружается главный класс, а все остальные пользовательские классы загружаются по мере необходимости (например класс A загружается только когда в программе создается объект класса A).
Первый мой вопрос заключается в следующем: что собственно значит "JVM загружает класс"? Имеется в виду что в этот момент происходит компиляция класса?
Так же мне интересно, зачем JVM загружает класс, когда используется его статический метод? Я провел небольшой эксперимент: написал класс, в котором есть один статический метод и несколько нестатических.
public class StExmp {
static{
c = 5;
}
private int a;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public int getB() {
return b;
}
public void setB(int b) {
this.b = b;
}
private int b;
private static int c;
public StExmp(int a, int b){
this.a = a;
this.b = b;
c = 5;
}
public static void show(){
System.out.println(c);
}
}
Вызываю статический метод в главном классе StExmp.show();, потом запускаю программу с флагом -verbose:class и вижу что когда программа дошла до вызова этого метода, она загрузила весь класс. А почему нельзя загружать только статические члены класса? Ведь получилось что из-за вызова одного маленького метода пришлось загрузить весь класс, хотя он больше никак и не используется.
И главный вопрос: Когда может потребоваться самому загружать классы? Например с помощью ClassLoader.loadClass()? Вот этого я совсем не могу понять. Ведь если мы загружаем какой то класс, значит мы собираемся его как то использовать? Почему тогда нельзя просто использовать его в программе (например, создать объект) JVM же сама его загрузит. А когда это может потребоваться делать методом ClassLoader.loadClass()?
Ответ
Ну и топик. Про загрузку классов можно много чего написать. Тема интересная, правда, уже 100 лет теорией не занимался. В контексте треда, пожалуй, отвечу на вопросы конкретные. Если в чём-то не прав, поправляйте, критика приветствуется.
Первый мой вопрос заключается в следующем: что собственно значит "JVM
загружает класс"?
У вас есть скомпилированные байт коды классов, ClassLoader их грузить по мере необходимости.
Зачем нам держать в памяти класс, если он не используется? Класс будет загружен только в момент использования. Точно так же, если на класс не осталось никаких ссылок, то ClassLoader может выгрузить класс из памяти при проходе GC.
Имеется в виду что в этот момент происходит компиляция класса?
Ваши классы уже скомпилированы javac. ClassLoader в память его грузит. Это если в 2-х словах, на самом деле там происходит верификация байт-кода и т.п.
Так же мне интересно, зачем JVM загружает класс, когда используется
его статический метод?
Статически метод, константы - это метаданные класса. Не представляю, как их можно загрузить в отрыве без класс.
А почему нельзя загружать только статические члены класса? Ведь
получилось что из-за вызова одного маленького метода пришлось
загрузить весь класс, хотя он больше никак и не используется.
Предположим, есть у вас:
public class StExmp {
public static void show(){
System.out.println(c);
}
}
Ок, давайте методом рассуждения выведем необходимость грузить класс. Вы хотите, чтобы метод show был загружен без класса. Но ведь в коде вы потом вызываете метод как StExmp.show()? Если класс не загружен, как вы себе представляете вызов метода? Ну хорошо, предположим загрузчик метод добавить в какую-то общую таблицу виртуальных методов. А потом вы создадите класс:
public class StExmp2 {
public static void show(){
System.out.println(c);
}
}
Метод show загрузчик так же добавит его в общую таблицу статических методов? Проблему уже видите? Как потом при вызове StExmp2.show() понять какой из этих методов вызвать?
Когда может потребоваться самому загружать классы? Например с помощью
ClassLoader.loadClass()? Вот этого я совсем не могу понять. Ведь если
мы загружаем какой то класс, значит мы собираемся его как то
использовать? Почему тогда нельзя просто использовать его в программе
(например, создать объект) JVM же сама его загрузит. А когда это может
потребоваться делать методом ClassLoader.loadClass()?
Например, у вас high-load проект. Приложение должно работать непрерывно. Но вам понадобилось заменить реализацию какого-то метода. Не перезапускать же всё приложение? Если оно стетйтлесс, то ещё ладно, но если там в памяти много данных/кэш и т.п.?
Можно заменить налету. Когда это надо? Ну, скажем, вы хотите поправить какой-то критический баг, оптимизировали метод и т.п.
Тут можно много чего придумать. К примеру у вас игра, в которой есть возможность добавлять кастомных npc. Вы просто пишите новые класс, который в рантайме подтягивается. Или просто неизвестно какой класс будет использоваться в итоге, решение принимаете в рантайме и грузите необходимый класс.
Бывает случаи, когда классы хранятся в базе (да-да, бывает такое). Их иначе и не загрузить вовсе.
Комментариев нет:
Отправить комментарий