Страницы

Поиск по вопросам

воскресенье, 12 мая 2019 г.

Когда может понадобиться самому загружать классы в java?

Помогите пожалуйста разобраться с динамической загрузкой классов в 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. Вы просто пишите новые класс, который в рантайме подтягивается. Или просто неизвестно какой класс будет использоваться в итоге, решение принимаете в рантайме и грузите необходимый класс.
Бывает случаи, когда классы хранятся в базе (да-да, бывает такое). Их иначе и не загрузить вовсе.

Комментариев нет:

Отправить комментарий