Ответы пользователя по тегу Java
  • Classloader и с что он собой представляет?

    vlad20012
    @vlad20012
    Тема с загрузкой классов уже достаточно заезжена и теория по ней гуглится легко. За пару минут нашел
    официальные доки,
    довольно подробная статья из кого-то блога,
    запись выступления на конференции JUG.RU

    Определимся с начальными условиями. Как я понял, есть папка с jar-файлами. Необходимо пройтись по всем jar-файлам и на выходе получить список классов, реализующих Module. Что-то вроде
    List<Module> discoverModules(File dir) {}
    Будем считать, что 1 jar-файл может содержать только один модуль (здесь и далее, "модуль" - это класс, реализующий интерфейс Module). Здесь самый нетривиальный вопрос, как этот модуль найти внутри архива. Самый простой (для начала) способ - положить в каждый jar-файл по определенному пути некий конфиг, в котором указать путь к модулю. И такой конфиг в jar-файле уже есть - стандартный META-INF. В простейшем случае у нас получается jar-файл из двух файлов с такой структурой:
    MyMod.jar
    ├───META-INF
    │   └───MANIFEST.MF
    └───mymod
        └───MyMod.class

    Где MANIFEST.MF содержит строчку
    Main-Class: mymod.MyMod
    т.е. путь к классу MyMod.

    Класс MyMod нужно собирать отдельным проектом, добавляя в зависимость проект, содержащий интерфейс Module. Содержимое MyMod.java
    package mymod;
    
    public class MyMod implements Module {
        public int run() {
            System.out.println("MyMod loaded!");
        }
    }

    Будем считать, что MyMod.jar уже собран и лежит (возможно, вместе с другими модулями) в директории "/modules".

    Ну вот, это были начальные условия =) Теперь к сути вопроса.
    public class ModuleLoader {
    	public static void main(String[] args) {
    		List<Module> mods = new ModuleLoader().discoverModules(new File("/modules"));
    		for(Module mod : mods)
    			mod.run();
    	}
    
    	public List<Module> discoverModules(File dir) {
    		List<File> jarFiles = Stream.of(dir.listFiles())
    				.filter(f -> f.getName().endsWith(".jar"))
    				.collect(Collectors.toList());
    		URL[] moduleUrls = jarFiles.stream().map(this::toUrl).toArray(URL[]::new);
    
    		URLClassLoader classLoader = new URLClassLoader(moduleUrls, getClass().getClassLoader());
    		return jarFiles.stream()
    				.map(this::getMainClassName)
    				.map(name -> {
    					try {
    						return (Module) classLoader.loadClass(name).newInstance();
    					} catch(Exception e) {
    						throw new RuntimeException(e);
    					}
    				})
    				.collect(Collectors.toList());
    	}
    
    	private String getMainClassName(File file) {
    		try(JarFile jar = new JarFile(file)){
    			return (String) jar.getManifest().getMainAttributes().get("Main-Class");
    		} catch(IOException e) {
    			throw new RuntimeException(e);
    		}
    	}
    
    	private URL toUrl(File file) {
    		try {
    			return file.toURI().toURL();
    		} catch(MalformedURLException e) {
    			throw new RuntimeException(e);
    		}
    	}
    }
    Ответ написан
    Комментировать
  • Как сделать 2 корневых аппендера в log4j2?

    vlad20012
    @vlad20012
    Root должен быть только один, а вот аппендеров может быть много:
    <Loggers>
        <Root level="ERROR">
            <AppenderRef ref="CONSOLE" />
            <AppenderRef ref="MYSQL" />
        </Root>
    </Loggers>
    Ответ написан
    1 комментарий
  • Какой наилучший способ обновления информации в потоке?

    vlad20012
    @vlad20012
    public class Waiter {
        private static volatile boolean isWaiting;
    
        public static void start() {
            if(isWaiting) throw new IllegalStateException();
            isWaiting = true;
            System.out.print("Жду .");
            new Thread(() -> {
                for(int i = 1; isWaiting; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ignored) {}
                    System.out.print(i % 3 == 0 ? "\b\b" : ".");
                }
                System.out.println();
            }).start();
        }
    
        public static void stop() {
            if(!isWaiting) throw new IllegalStateException();
            isWaiting = false;
        }
    }
    Ответ написан
    Комментировать
  • Как можно намеренно уронить JVM?

    vlad20012
    @vlad20012
    Ну-ну, все ваши примеры - всего лишь необработанные исключения. Обычно под "уронить" подразумевают более веселые вещи. Давайте возьмем Unsafe и прочтем байт по нулевому адресу.
    import sun.misc.Unsafe;
    
    public class CrashTheJVM
    {
        private static final Unsafe UNSAFE = createUnsafe();
    
        private static Unsafe createUnsafe()
        {
            try
            {
                Field uf = Unsafe.class.getDeclaredField("theUnsafe");
                uf.setAccessible(true);
                return (Unsafe) uf.get(null);
            }
            catch (Exception e)
            {
                throw new RuntimeException(e);
            }
        }
    	
        public static void main(String[] args)
        {
            UNSAFE.getByte(0);
        }
    }

    Сегфолт! 100% падение. Ну, и если это запрещает делать SecurityManager или реализация JVM не поддерживает Unsafe, мы таки получим необработанное исключение.
    Ответ написан
    Комментировать
  • Какое условие выбрасывания StackOverflowError?

    vlad20012
    @vlad20012
    В дополнение к предыдущему ответу - есть параметр -XX:MaxJavaStackTraceDepth=1024. Т.е. если размер стека вызовов превысит 1024, будет брошен StackOverflowError. По умолчанию выставлено 1024. Но это, как уже было сказано, не единственная возможная причина возникновения данного исключения.
    Ответ написан
    Комментировать
  • Можно ли читать из нескольких сокетов в одном потоке?

    vlad20012
    @vlad20012
    А лучше смотрите в сторону Netty (на хабре писали здесь)
    Ответ написан
    Комментировать
  • Как использовать Keep-Alive в Java?

    vlad20012
    @vlad20012
    Обычно рекомендуют использовать apache http client.
    Не уверен, что дело тут вообще в Keep-Alive. Apache http client просто работает быстрее, чем HttpUrlConnection из стандартной библиотеки. Вот, к примеру, инструкция от оракла, как заставить Keep-Alive работать. Ничего особенного там не написано, так что должно работать по умолчанию.
    Ответ написан
  • Почему в языке Java нет таких языковых конструкций как "свойства" и "индексаторы"?

    vlad20012
    @vlad20012
    По тем же причинам, почему в Java нет перегрузки операторов и огромного количества других плюшек. Разработчики языка не любят всякий синтаксический сахар, а свойства и индексаторы - это и есть синтаксический сахар над простыми методами.
    Ответ написан
    Комментировать
  • Как получить месяц в именительном падеже?

    vlad20012
    @vlad20012
    Взять месяц как число, поставить switch дальше присваивать любые строки, какие хочется...
    Ответ написан
  • С чего начать разработку таск менеджера на Java?

    vlad20012
    @vlad20012
    Есть 2 большие проблемы. Во-первых, "специалисты" вашего уровня обычно пишут на каком-нибудь PHP, и информации о разработки подобных проектов на PHP можно найти тонны. Инфы по Java найти гораздо сложнее, ибо если ты пишешь на Java, то ты по умолчанию специалист, и тебе не нужно объяснять такие "простые" вещи. Во-вторых, те, кто в этом реально разбираются, скорее всего скинут вам пачку непроизносимых названий, вроде EJB, JSP, JSF, Spring, Hibernate и прочее и прочее, ибо это именно те технологии и фреймворки, с которыми обычно имеют дело java-разработчики.

    Лично я считаю (т.е. ИМХО, да?), что начинающему разработчику категорически противопоказано использовать какие-либо сторонние библиотеки и фреймворки. Только стандартная библиотека, только vanilla java, только хардкор. Только так можно понять, как там оно на самом деле работает, и стать действительно хорошим специалистом, а не фреймворк-разработчиком. Кстати, по поводу "упражняться с консолью и файлами". Не знаю какие книги вы читаете, но обычно там последовательно излагается все необходимое, от консоли и файлов до GUI и WEB-приложений. К примеру, есть отличная книжка Шилдта... в общем, рекомендую все-таки почитать, а не сразу рваться в бой.

    Но уверен, вы, конечно же, не прислушаетесь к предыдущему совету. Так что по поводу создания WEB-приложений. Поищите в направлении servlets API. Как я и говорил изначально, довольно сложно нагуглить что-нибудь толковое, тем более на русском. Может быть, ниже кто-нибудь подкинет хорошую статеечку. Установите IDE для JavaEE и напишите простой сервлет. С его помощью можно принимать HTTP запросы от клиентов и отправлять ответы. А что дальше зависит от ваших познаний о структуре WEB-приложений, о которых я не имею представления. А статей именно с упором на Java как-то... Короче, обычно свой путь в WEB-разработке далеко не с Java начинают.
    Ответ написан
    4 комментария
  • Нужно ли оптимизировать переменные в JAVA, и когда?

    vlad20012
    @vlad20012
    Хотел сначала написать это как комментарий к предыдущему ответу, но решил, что этот ответ все-таки не до конца верен. Тут человек спрашивает скорее "зачем нужны типы byte и short, если есть int", а не "когда нужно оптимизировать". На вопрос "когда нужно оптимизировать" ответ, безусловно, правильный.

    Типы с разрядностью, меньшей чем у int, нужно использовать только с точки зрения экономии памяти, например, в больших массивах или классах с большим количеством полей. Использовать их в качестве локальных переменных не имеет смысла, т.к. процессор в любом случае оперирует типами размером с машинное слово (а Java на 16-битных машинах не работает, так ведь?). Т.е. об оптимизации вообще речи не идет, разницы нет, и в качестве локальных переменных типы byte и short, в принципе, появляться не должны. А вот если у тебя массив из over9000 элементов, в качестве элементов которого пойдет и short, то int использовать не стоит.
    Ответ написан
    3 комментария
  • Как считать список классов из пакета который находится в том же jar-файле что и программа?

    vlad20012
    @vlad20012
    Еще как можно. annotation processing - хорошая вещица, не немного не ответ на вопрос. Предположим, что есть причины его не использовать. Тогда обычно источник кода (code source), т.е. jar архив с классами, берется как файл, из него, как из zip архива, читается список файлов, и, если название файла соответствует определенному шаблону (например, находится в определенном пакете), загружается класс тем же названием. Получить code source можно как-то так:
    getClass().getProtectionDomain().getCodeSource().getLocation();

    Хотя, этим будет получено лишь расположение текущего класса. Все линкованные URL можно получить так:
    ((java.net.URLClassLoader)getClass().getClassLoader()).getURLs();

    А дальше использовать ZipFile, читать список Entry, проверять соответствие шаблону.

    Вместо шаблона имени класса можно использовать те же аннотации, но тогда их придется читать через ASM без загрузки класса. Так что смотрите, что проще.

    Этот способ считается не очень хорошим, потому что классы могут загружаться не только из jar архивов. Как минимум, нужно учесть загрузку из директории, но в теории классы могут загружаться откуда угодно, а code source вполне может отсутствовать, т.е. getCodeSource() вернет null. Тем не менее, многие пользуются этим способом. Например, log4j загружает плагины таким образом, но annotation processing там тоже присутствует, комбинирование подходов таки никто не отменял.
    Ответ написан
  • Что такое агрегация?

    vlad20012
    @vlad20012
    Я писал, пишу и буду писать один и тот же ответ - читайте умные книжки, прежде чем задавать подобные вопросы. Лень читать все - посмотрите оглавление. Там вы найдете собственные вопросы и развернутые ответы на них. Ибо ваш вопрос даже не по Java, а по самым основам программирования на любом языке и с любой парадигмой.
    Ответ написан
    Комментировать
  • Как передать объект из одного класса в другой?

    vlad20012
    @vlad20012
    Чтобы можно было понять, почитай какую-нибудь книжку, а не задавай тут глупые вопросы. Шилдта, например.
    Ответ написан
  • Java: Почему не получается обработать JSON?

    vlad20012
    @vlad20012
    e.getMessage() не дает никакой информации о возникшем исключении, нужно строкой ниже писать e.printStackTrace(); Дополните вопрос тем, что было выписано в консоль после этого, а то скиллом телепатического поиска ошибок тут мало кто владеет.
    Ответ написан
    2 комментария
  • Как отобразить пустую таблицу?

    vlad20012
    @vlad20012
    Отрисовывать прямоугольники в Graphics2D?
    Ответ написан
    Комментировать
  • Что лучше учить новичку Java или Python?

    vlad20012
    @vlad20012
    Новичкам обычно Python советуют, здесь есть немного рассуждений на эту тему. Но вот если говорить про универсальность и востребованность, то выбирайте Java - не прогадаете. От высоконагруженных серверов до мобильников - неплохой размах. Только несколько огибает десктопы... Так сходу кроме эклипса и майнкрафта ничего десктопного на ждаве вспомнить не смог.
    Ответ написан
    4 комментария
  • Как удобнее всего эмитировать структуру С(С++) в java (под Android)?

    vlad20012
    @vlad20012
    В Java Обычной практикой является чтение/запись отдельно каждой переменной из/в DataInputStream/DataOutputStream. Чтобы читать/писать целую структуру, создаем методы writeTo(DataOutoutStream data), readFrom(DataInputStream data) и пишем туда все элементы структуры, например
    public class SomeStruct {
        public int i1;
        public int i2;
    
        public void writeTo(DataOutputStream data) {
            data.writeInt(i1);
            data.writeInt(i2);
        }
        public void readFrom(DataInputStream data) {
            i1 = data.readInt();
            i2 = data.readInt();
        }
    }


    Но из-за того, что запись производится в сишном коде, могут возникнуть проблемы. Дело в том, что существует два варианта порядка байтов. Какой конкретно попадется вам, зависит от платформы. На x86 используется little-endian. Но при чтении из DataInputStream используется big endian. Да и вообще, при передаче по сети принято использовать именно big endian. Так что при записи придется разворачивать байты. Но если очень припрет - можно и при чтении. Например, порядок байтов типа int можно изменить такInteger.reverseBytes(i1);
    Ответ написан
    5 комментариев
  • Почему CipherI/OStream не передаёт данные поверх Socket I/OStream?

    vlad20012
    @vlad20012
    Тут все дело в том, что в режиме ECB данные шифруются блоками. Соответственно, отправка будет происходить только при накоплении блока данных определенного размера. Для возможности отправки отдельно каждого байта, стоит использовать режим CTR.
    Cipher.getInstance("AES/CTR/PKCS5Padding");
    Ответ написан
    Комментировать
  • Как спроектировать/организовать TCP сервер на Java?

    vlad20012
    @vlad20012
    Если нужен высокопроизводительный NIO сервер, то нужно смотреть в сторону Netty (на хабре писали здесь)
    Ответ написан
    Комментировать