Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Принудительная инициализация класса 
V
    Опции темы
x8m6
Дата 2.8.2010, 21:54 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 156
Регистрация: 11.12.2008

Репутация: нет
Всего: нет



Нужно выполнить принудительную инициализацию класса, но сделать это не в коде (исп. Class.forName()) а как-им либо декларативным путем, т.е. указать заранее (до начала выполнения программы) JVM что "вот именно этот класс нужно проинициализировать в первую очередь, еще до того как к нему произойдет какое-либо обращение". Может быть существует какая-то аннотация, пригодная для этого? Как вообще System CL загружает и инициализирует классы из cp?
Я так понимаю не сразу все, а используется принцип load on demand, т.е. в момент первого обращения к классу (создание экземпляра класса или вызов статик метода/поля)? 
PM MAIL   Вверх
ki6opr
Дата 3.8.2010, 08:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 67
Регистрация: 20.12.2006

Репутация: нет
Всего: нет



почитать можно например тут
PM MAIL ICQ   Вверх
ivanovpv
Дата 3.8.2010, 09:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Варвар
**


Профиль
Группа: Участник
Сообщений: 639
Регистрация: 26.1.2005
Где: Москва

Репутация: 4
Всего: 28



Цитата(x8m6 @  2.8.2010,  22:54 Найти цитируемый пост)
Я так понимаю не сразу все, а используется принцип load on demand, т.е. в момент первого обращения к классу


JVM использует 3 загрузчика: bootstrap, extension и system. В ходе исполнения когда встречается название класса работает сначала bootstrap загрузчик, который фактически ищет класс среди стандартных runtime библиотек, затем загрузчик extension который ищет класс в расширениях (lib/ext) и только в последнюю очередь вступает в действие системный загрузчик, который ищет класс в CLASSPATH.

В вашем случае надо вставить в ваш код вызов какого-либо статического метода класса, тогда загрузчик загрузит класс до начала исполнения кода (IMHO мне так кажется - лично не проверял). Полезной будет трассировка порядка загрузки классов: ключ verbose:class при вызове JVM

Это сообщение отредактировал(а) ivanovpv - 3.8.2010, 09:59


--------------------
Aut viam inveniam aut faciam
PM MAIL Skype   Вверх
x8m6
Дата 3.8.2010, 11:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 156
Регистрация: 11.12.2008

Репутация: нет
Всего: нет



ki6opr, в статье описываются способы инициализации во время выполнения программы. Повторяюсь, мне же нужно сделать это не в коде.
Цитата

вашем случае надо вставить в ваш код вызов какого-либо статического метода класса, тогда загрузчик загрузит класс до начала исполнения кода (IMHO мне так кажется - лично не проверял). Полезной будет трассировка порядка загрузки классов: ключ verbose:class при вызове JVM


Спасибо, но это опять же вариант не совсем подходит. 
Думаю сделать так: 
создать аннотацию @prepareInitialization и свой лоадер. Лоадер должен будет пройтись по классам и найти аннотированные. Их он и загрузит первыми. Тогда вопрос в том как это сделать : "пройтись по классам и найти аннотированные"?

Это сообщение отредактировал(а) x8m6 - 3.8.2010, 11:22
PM MAIL   Вверх
aleksandy
Дата 3.8.2010, 12:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 260
Регистрация: 17.12.2006

Репутация: 4
Всего: 5



x8m6, а нафига тебе такой геморрой? Чего ты хочешь этим добиться, подменить какой-то стандарный класс своим?

Это сообщение отредактировал(а) aleksandy - 3.8.2010, 12:59
PM   Вверх
x8m6
Дата 3.8.2010, 16:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 156
Регистрация: 11.12.2008

Репутация: нет
Всего: нет



Цитата

а нафига тебе такой геморрой? Чего ты хочешь этим добиться, подменить какой-то стандарный класс своим?

Нет, для инициализации списка фабрик.
PM MAIL   Вверх
ki6opr
Дата 4.8.2010, 03:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 67
Регистрация: 20.12.2006

Репутация: нет
Всего: нет



Цитата(x8m6 @ 3.8.2010,  16:24)
Нет, для инициализации списка фабрик.

а не проще ли проводить инициализацию фабрики при первом обращении к ней ? 
PM MAIL ICQ   Вверх
x8m6
Дата 4.8.2010, 15:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 156
Регистрация: 11.12.2008

Репутация: нет
Всего: нет



Цитата

а не проще ли проводить инициализацию фабрики при первом обращении к ней ? 

Нет, обращение происходит только к абстрактной фабрике. А все остальные фабрики определяются в статических контекстах тех классов, для создания экземпляров которых они и применяются(т.е. в каждом подклассе своя фабрика). Создание же объектов занимается только абстрактная фабрика, у которой есть список фабрик для подклассов и фабричный метод. Чтоб было понятно вот пример:
Код


public abstract class Factory {
    
    // кэш для хранения фабрик, которые создают объекты подклассов
    private static  Map<String,Factory> factories = new HashMap<String,Factory>();

    // добавляет фабрику в кэш
    public static void addFactory(String type, Factory factory){
      factories.put(type,factory);
    }

    // фабричный метод, который создает объект указанного типа
    public static  MyObj createMyObj(String type){
    if (factories.containsKey(type))
     return  factories.get(type).create();
    else
         throw new IllegalArgumentException("factory with such type doesn't exist");
    }

    //  метод создает конкретный объект. Реализуется в фабриках-подклассов
    public abstract MyObj create();
    
}




Допустим есть класс машины:
внутри него определяется своя фабрика как вложенный статический класс
Код


public class Car extends MyObj {
    
    private static class CarFactory extends Factory{
        @Override
        public MyObj create() {            
            return new Car();
        }                    
    }
    
    // далее мы должны сразу же добавить эту фабрику в кэш фабрик, поэтому делаем это в стат. инициализирующем блоке:
    static{
          System.out.println("car's factory initialization");
          Factory.addFactory("cars", new CarFactory());
        }
    
}



Ну и теперь главный метод:
Код

public class RunClass {

    /**
     * @param args
     * @throws ClassNotFoundException 
     */
    public static void main(String[] args) throws ClassNotFoundException {
                        
        Class clazz = Class.forName("Car"); // принудительная инициализация класса Car    
        Car  car  =  (Car) Factory.createMyObj("cars"); // фабрика создает тачку
        
    }

}



Закоментируйте Class.forName и увидите что список фабрик оказывается пустым, т.к. класс Car не был проинициализирован. 

Это сообщение отредактировал(а) x8m6 - 4.8.2010, 15:27
PM MAIL   Вверх
LSD
Дата 4.8.2010, 17:38 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 210
Всего: 538



Цитата(x8m6 @  4.8.2010,  16:20 Найти цитируемый пост)
Нет, обращение происходит только к абстрактной фабрике. А все остальные фабрики определяются в статических контекстах тех классов, для создания экземпляров которых они и применяются(т.е. в каждом подклассе своя фабрика). Создание же объектов занимается только абстрактная фабрика, у которой есть список фабрик для подклассов и фабричный метод.

Для подобных вещей в JDK 6 был добавлен Service Provider механизм.


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
x8m6
Дата 4.8.2010, 19:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 156
Регистрация: 11.12.2008

Репутация: нет
Всего: нет



Цитата

Для подобных вещей в JDK 6 был добавлен Service Provider механизм. 

т.е. для данного примера я должен определить Factory как сервис,  а CarFactory как ServiceProvider?

Получилось. Спасибо вам LSD. Вот теперь как выглядит класс фабрики:
Код

public abstract class Factory {
    
    // кэш для хранения фабрик для подклассов
    private static  Map<String,Factory> factories = new HashMap<String,Factory>();

    static{
        // предзагружает все имеющиеся фабрики в кэш
        ServiceLoader<Factory> loader = ServiceLoader.load(Factory.class);
        Iterator<Factory> it = loader.iterator();
        while (it.hasNext())
            addFactory(it.next());
    }
    
    // добавляет фабрику в кэш
    public static void addFactory(Factory factory){
      factories.put(factory.getType(),factory);
    }

    // фабричный метод, который создает объект указанного типа
    public static  MyObj createMyObj(String type){
    if (factories.containsKey(type))
     return  factories.get(type).create();
    else
         throw new IllegalArgumentException("factory with such type doesn't exist");
    }

    //  метод создает конкретный объект. Реализуется в фабриках для подклассов
    public abstract MyObj create();
    
    // Возвращает тип объектов, производимых фабрикой
    public abstract String getType();
    
}


вот фабрика для машин:

Код

public class CarFactory extends Factory{
        
    @Override
    public MyObj create() {            
        return new Car();
    }

    @Override
    public String getType() {            
        return "cars";
    }        
}


Так  же получилось сделать через аннотацию, но это более геморройный вариант:
Код

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * Аннотация, которой будут помечатся  классы, 
 * требующие предварительной инициализации
 *
 */
@Retention(RetentionPolicy.RUNTIME)
public @interface PrepareInitialize {}


Помечаем класс фабрики машин этой аннотацией:
Код

@PrepareInitialize
public class CarFactory extends Factory{
        
    static{
        Factory.addFactory(new CarFactory());
    }
    
    @Override
    public MyObj create() {            
        return new Car();
    }

    @Override
    public String getType() {            
        return "cars";
    }        
}


Далее пишем своего инициализатора:
Код

public class Initializer {

    // находит классы из classpath и инициализирует те, которые помечены аннотацией @PrepareInitialize
    public void findAndInit(){
        
        String classPath = System.getProperty("java.class.path");
        String[] paths = classPath.split(";");
        String path;
        File pathFile;
        for (int i = 0;i<paths.length;i++){
            pathFile = new File(paths[i]);
            File[] classFiles;
            if (pathFile.isDirectory()){
                classFiles = pathFile.listFiles(new FileFilter(){
                    @Override
                    public boolean accept(File file) {                                                                
                        return file.isFile() && file.getName().endsWith(".class");
                    }
                });
                init(classFiles);                                            
            }
            else{
                // if jarfile
                // TODO insert code
                
            }
            
       }
    }
    
    
    private void init(File[] classFiles){
        
        if (classFiles!=null && classFiles.length>0){
            try {
                String className;
                Class clazz;
                for (int j = 0;j<classFiles.length;j++){
                    className = classFiles[j].getName().split(".class")[0];                    
                    clazz = Class.forName(className,false,Thread.currentThread().getContextClassLoader()); // загружаем класс
                    if (clazz.isAnnotationPresent(PrepareInitialize.class)){                        
                        Class.forName(className,true,Thread.currentThread().getContextClassLoader()); // загружаем еще рас но уже с   инициализацией
                    }                                            
                    
                }
                }
                catch (ClassNotFoundException e) {}
             
        }
    }
    
}



Это сообщение отредактировал(а) x8m6 - 4.8.2010, 23:21
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0556 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.