Ответы пользователя по тегу Java
  • Есть ли в java стандартные инструменты для написания программ на чистом bytecode?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Комментировать
  • Почему полиморфизм так работает?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Объяснить суть полиморфизма "на пальцах" довольно просто. Представьте себе класс Телефон. Его спроектировал некто в далеких 80-х, и определил в нем метод набратьНомер(). А потом другой программист в 90-х отнаследовал от него класс МобильныйТелефон и перекрыл метод набратьНомер(), т.к. грубо говоря, в новом устройстве набор производится уже не импульсно, а тонально. А потом третий программист отнаследовал от него класс Смартфон. При этом он не стал трогать метод набратьНомер(), а просто добавил методы для нового функционала, типа определитьПоложениеПоGPS() и т.д.

    Теперь представьте себе пользователя. Он родом из 80-х и понятия не имеет о тональном наборе и GPS... но если ему в руки дать любое из этих устройств, он сможет набрать номер и сделать звонок. Почему? Потому, что он умеет использовать метод набратьНомер(), и большего ему знать не нужно.

    А теперь представьте другого пользователя, нашего современника. Он вырос в эпоху смартфонов... но если ему в руки дать старый телефонный аппарат, он тоже сможет сделать звонок, т.к., опять же, знает метод набратьНомер().

    Применительно к ООП, пользователь - это переменная, содержащая ссылку на экземпляр класса. Ее тип (как она была объявлена) - это "набор знаний" о возможностях этого экземпляра. И т.к. Смартфон в своей основе является Телефон-ом, мы вполне можем дать его в руки гипотетическому пользователю из 80-х:
    Телефон устройство = new Смартфон();
    в результате чего он сможет сделать звонок:
    устройство.набратьНомер("03");
    А вот определить свое местоположение он не сможет, пока не узнает о существовании соотв. метода:
    Смартфон усовершенствованноеУстройство = (Смартфон)устройство;

    Это называется приведением типа. В данном примере у экземпляра класса уже был соотв. метод, но чтоб им воспользоваться, нужно сначала явно указать, что мы хотим рассматривать имеющееся у нас в руках устройство не как "простой" Телефон, а как Смартфон.

    P.S. Кстати, в этом примере мы затронули не только полиморфизм, но и наследование, и инкапсуляцию (пользователя "снаружи" совершенно не интересует, как именно производится набор номера - тонально, импульсно или еще как-то иначе)... так сказать, все три кита ООП в одном флаконе. И только так вообще имеет смысл рассматривать эти принципы, т.к. они по сути неотделимы друг от друга, как Отец, Сын и Святой Дух в Христианстве или же длина, ширина и высота в трехмерном пространстве :) Если это понять, ООП становится совершенно простой и естественной парадигмой программирования.
    Ответ написан
    8 комментариев
  • Как подключить java-сервер к внешнему сетевому интерфейсу в Linux?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Вместо:
    InetAddress.getLocalHost()
    использовать:
    InetAddress.getByName("10.10.23.45")
    Похоже, что getLocalHost() все еще неправильно разрешается (как уже обсуждалось в параллельном вопросе).
    P.S. Вот еще полезная инфа на тему.
    Ответ написан
  • Как создать Java приложение без GUI?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    public class Aaa {
    
        javax.swing.Timer dynTimer;
        public long startTime;
        public static boolean running = true;
    
        public static void main(String[] args) {
            Aaa p = new Aaa();
            p.init();
            p.start();
            
            while (running) {
                try {
                    Thread.sleep(100);
                    System.out.println("::: " + running);
                } catch (InterruptedException ie) {
                    System.out.println("Child thread interrupted! " + ie);
                }
            }
        }
    
        private void init() {
            System.out.println("> Инициализация");
            dynTimer = new javax.swing.Timer(100, (java.awt.event.ActionEvent e) -> {
                update(e.getWhen());
            });
        }
    
        private void start() {
            System.out.println("> Запуск");
            dynTimer.start();
            startTime = new java.util.Date().getTime();
        }
    
        private void update(long when) {
            System.out.println("Событие: " + (startTime + 1000) + " : " + when + " : " + running);
            if(startTime + 1000 < when) {
            	dynTimer.stop();
            	running = false;
            }
        }
    }
    Ответ написан
    3 комментария
  • Получить ответ от закрытой программы(C#/Java)?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Вам поможет только ProcessBuilder.

    Подробные примеры.
    Ответ написан
    3 комментария
  • Как в Java удалить крайний символ или строку, напечатанную на экране терминала?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Возможность есть, но она никак не связана с Java. Это можно сделать с помощью т.н. Escape-последовательностей, если они поддерживаются терминалом (если терминал работает в режиме эмуляции, например, VT-52 или VT-100). В таком режиме работает большинство терминалов в Linux.

    Удалить последнюю строку, выведенную с символом перевода каретки (когда после вывода строки курсор находится в позиции 1 следующей строки) можно, например, так:
    System.out.println("Hello world"); //Print the line
    
    System.out.print(String.format("\033[%dA",1)); // Move cursor up by 1 line
    System.out.print("\033[2K"); // Erase the line


    Полный список кодов можно найти, например, вот тут.
    upd:
    С помощью Escape-последовательностей можно делать намного больше: переключать цвета, позиционировать курсор, "стирать" части строки или весь экран, и т.д. и т.п. Для интенсивного использования ANSII, особенно под Виндой, може оказаться полезной Jansi.
    Ответ написан
    Комментировать
  • Как скомпилировать Jar файл с аргументом?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Сообщения об ошибках не читай - вопросы задавай :) А между тем, там конкретно написано, в чем именно проблема: Failed to load the native library.
    В src/native/windows/x64 лежат, вероятно, какие-то DLL-ки. Когда программа запускалась из папки проекта, все было хорошо. Теперь JAR переложили в др. место, а DLL-ки не прихватили... и они больше не находятса, т.к. путь к ним указан относительный.
    Решения проблемы два: либо указать абсолютный путь к DLL, либо прихватить их вместе с JAR в др. папку.
    Ответ написан
    1 комментарий
  • Правила объявления интерфейсов. "I" или "!I"?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Никакой "официальной" жесткой конвенции на этот счет нет. Как уже указал RGV, какую конвенцию использовать - личное дело команды / фирмы / техдира.
    Я сам в свое время пришел к Java из Pascal и .NET, и тоже придерживаюсь нотации с I, т.к. это позволяет в коде визуально отличить интерфейс от класса. Просто для примера:
    ...
      IProducer simpleProducer = new Producer();
      IProducer sofisticatedProducer = new SpecialProducer();
    ...
      public void produceSomething(IProducer producer);

    При взгляде на такой код сразу понятно, кто из ху, без всяких дополнительных кликов, наведения курсора и прочих пританцовываний с IDE.
    И хотя это никак явно не помешает креативному балбесу влепить класс там, где нужно использовать интерфейс, это поможет проводящему ревью заметить грабли невооруженным глазом :) С моей точки зрения цена такого удобства в 1 (один !) доп. символ в имени вполне оправдана.
    Ответ написан
    Комментировать
  • Объясните код, если можно то с комментариями?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Код - как код... умеренной кривизны. Тянет из какой-то БД параметры (таймаут и количество попыток), откладывает в Мэп некие статусы по ключу IP+Пользователь, и позволяет опрашивать их состояние (не вышел ли таймаут и не исчерпано ли заданное количество попыток) / удалять / сбрасывать... короче, очень похоже на кусок какой-то хрени для рассылки спама.

    Что конкретно непонятно в этом коде?
    Спрашивайте!.. не думаю, что кто-нибудь станет просто так комментировать каждую строчку этой простыни без конкретной постановки вопроса :)

    Update:
    @gurinderu
    Прикольно, а откуда инфа про базу данных? )))))))

    @Losted
    По DataBaseException, полагаю


    Именно... эта exception может прилететь только из getOption(). А в остальном все просто, как угол дома. Некая сущность создает экземпляр этого класса, передавая в конструктор контроллер, из которого при инициализации потянутся начальные "настройки". Т.к. метод synchronize() публичный, очевидно, данные в "базе" могут поменяться на лету, и его можно дернуть еще раз, чтоб перезачитать актуальные настройки. (Действительно ли за этим скрывается БД или что-то другое, сказать невозможно - детали абстрагированы фасадом SysOptionController.)

    Т.к. этот и др. публичные методы synchronized, очевидно, они могут дергаться разными потоками. (Кстати, синхронизация сделана довольно таки криво и может обернуться проблемами производительности... но это уже другая тема).

    Отсюда более-менее понятно, что делает эта некая сущность. Скорее всего, она предназначена для выполнения какого-то действия с "пользователями" (например, отправки им спама), которое может сработать с первого раза, а может и не сработать. На обработку одного пользователя отводится лимит времени и попыток. Пользователь идентифицируется по IP и имени. Скорее всего, там есть некий ЕхecutionService с пулом потоков. Поток получает экземпляр BFController и, в зависимости от того, что он делает, может воспользоваться соотв. методами:
    addTry() - когда начинается очередная "попытка"
    needWait() - чтоб проверить, продолжать ли попытки или лимит для пользователя исчерпан
    resetTries() - чтоб сбросить счетчик попыток.

    Помимо кривой синхронизации, семантика публичного интерфейса мутная, базируется на неких неочевидных предположениях об использовании класса и, вдобавок, реализация никак не очищает память. Короче, с т.з. объектного дизайна - уверенная троечка с плюсом :)
    Ответ написан
  • C# to Java или Чего стоит выучить новый язык, зная прежний?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Требование совершенно справедливое, т.к. зная один единственный язык стать хорошим (тем более, пригодным для должности ведущего) программистом просто невозможно. Как абсолютный минимум нужно знать:
    - ассемблер и устройство процессоров,
    - минимум один "взрослый" язык (C/C++/Pascal)
    - минимум один VM-ориентированный язык (C#/Java)

    Зная C#, выучить синтаксис Java - вопрос одного-двух дней, но научиться правильно писать на нем программы - это как минимум один-два серьезных проекта, т.е. годик-другой. Однако, не расстраивайтесь - после третьего языка "изучение" последующих уже практически не напрягает. А потом наступает состояние, когда "новых" языков не остается - есть лишь языки, которые еще не использовал... но если нужно - просто берешь и используешь, "изучая" их, практически, по ходу дела. Вот именно оно и есть признак пригодности для должности ведущего программиста.
    Ответ написан
    1 комментарий
  • Как сделать чтоб сообщения выводились одно под другим в чате на Java?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Если по условию задачи мы должны телепатическим методом узнать, что, куда и как именно выводится в этом приложении, то рискну предложить ответ: нужно к концу добавляемой строки добавлять "перевод строки".

    Сделать это можно так (правильно):
    myJTextArea.append(myString + System.lineSeparator());

    или так (наглядно):
    myJTextArea.append(myString + "\n");
    Ответ написан
    2 комментария
  • Зачем нужен интерфейс в java?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Для реализации модульности и слабой связанности. Интерфейс - это, по сути, контракт (на "поставляемое" множество и сигнатуры методов).

    Принципиальное отличие его от абстрактного класса в том, что в Яве нет множественного наследования и, соответственно, конкретный класс может наследовать только от одного абстрактного. А вот имплементировать разных интерфейсов он может, сколько душе угодно.

    Если же учесть при этом, что есть еще и абстрактные методы, становится понятно, что абстрактный класс/методы и интерфейс - инструменты для разных задач.

    Классический пример правильного использования интерфейсов - явовские коллекции. Прикиньте, учитывая соображения выше, какой бы это был геморой в использовании, если бы API было сделано не через интерфейсы, а через абстрактные классы :)
    Ответ написан
    2 комментария
  • Как с помощью java реализовать блокировку файла в файловой системе, для использования в многопоточном коде?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Дело в том, что гарантии блокировки файла дает (или НЕ дает), собственно, файловая система, а Ява просто довольствуется тем, что есть. Существует две принципиально разные идеологии: либо блокировка ФС таки блокирует (как в Винде), либо она носит скорее информативно-предупреждающий характер (как в Линуксе). Обе - со своими плюсами и минусами.

    В Яве есть механизм доступа к этому делу, в java.nio.channels.FileLock, но что и как с его помощю удастся реализовать, прямо зависит от платформы.

    В связи с этим, для решения указанной задачи существует два подхода.

    Кривой, исторически-обусловленный, используется, например, в HL7 (где проблема интероперабельности разных платформ через ФС все еще актуальна) определена иная семантика семафорных файлов: семафорный файл создается ПОСЛЕ того, как файл данных освобожден пишущим процессом (т.е. наличие семафора является гарантией ОТСУТСТВИЯ блокировки). Это элементарно реализуется на Яве созданием семафорного файла во временной папке с последующим move в целевую, ибо атомарность move-а гарантируется ФС. Недостаток этого подхода в том, что на однажды освобожденный файл нельзя повторно получить блокировку, в связи с чем вся эта костыльная кухня практически не масштабируется.

    Правильное, более универсальное и масштабируемое решение - вообще не использовать ФС в качестве shared memory (которая для этого, строго говоря, и не предназначена), а соединять процессы через брокер с внятным протоколом (очередь сообщений, сокеты, БД в конце концов).

    Так что, если это возможно, рекомендую попытаться решить проблему на уровне переосмысления общей архитектуры системы. Если нет, то придется клепать свой платформозависимый велосипед из java.nio.* и java.util.concurrent.* (например ReentrantLock)... т.е., фактически, переизобретать эдак добрую треть JEE :)

    P.S. Кстати, если это чудо должно еще и поверх smb крутиться, то я бы, лично, лучше сразу завернулся в простыню и пополз на кладбище, т.к. от smb с сетью в этом деле можно поиметь под нагрузкой еще как минимум столько же удовольствия.
    Ответ написан
    1 комментарий
  • Скажите, где ошибка в коде Java?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    //Проверяем, не ЗАБЫЛ ли пользователь ввести свое имя?
    if (name == null || name.trim().isEmpty()) { ...


    такая "хитрая" проверка нужна, т.к. readLine() вполне может вернуть null, и тогда мы упадем по NPE на name.trim()

    В Джава сравнение строк делается так
    if (name.equals("Вася"))
    a name=="" сравнит объект name с другим, новым объектом типа String, со значением "" ... которые, разумеется, никогда не будут равны (вне зависимости от того, равны ли между собой ЗНАЧЕНИЯ строк), ибо это два разных объекта!
    Ответ написан
    9 комментариев
  • Как хранить данные в классах-структурах в Java?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Правильный подход в объектном дизайне - не плодить сущности без нужды! "Красота", сама по себе - это не причина. Причина может быть в том, что, например, дома и пары координат где-то агрегируются в отдельных списках, в которые не хочется тащить ненужный хлам.

    А кроме того, если данные будут персистироваться, например, с помощью ORM, или сериализоваться, например в JSON, то всякое разделение - это дополнительный join с вытекающей отсюда потерей производительности/памяти и т.д.

    Если все же есть реальные оправданные причины разделять сущности, то правильно делать так:
    class House{
      private String number; // номер дома
      private String kladrCode; // код КЛАДР дома
      private String entrance; // подъезд
    
      public String getNumber(){ return this.number;}
      public String getKladrCode(){ return this.kladrCode;}
      public String getEntrance(){ return this.entrance;}
    
      public void setNumber(String number){ this.number = number;}
      public void setKladrCode(String kladrCode){ this.kladrCode = kladrCode;}
      //  и т.д.
    }
    class AddressParcel {
      private String streetType; // название типа улицы (улица, проспект, бульвар и т.д.)
      //...
      private House house = null; // это не обязательно, но "хорошая практика" - явно инициализировать объектные поля статически!
      // ...
      public House getHouse() { return this.house;}
      public void setHouse(House house) { this.house = house;}
    }


    А доступаться - вот так:

    String someType = someAddress.getStreetType();
    String someNumber = someAddress.getHouse().getNumber();


    И еще: типы данных (одни стринги!) наводят на некоторые нехорошие размышления...
    Ответ написан
    3 комментария
  • Как в java swing получить картинку из массива?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    С какими именно цифрами? В какое изображение? И самое главное - при чем тут вообще Swing?

    Если под "цифрами" подразумевается массив байт, содержащий, например, закодированное в JPEG изображение, которое хочется поиметь в ImageIcon (кажущаяся мне наиболее вероятной интерпретация вопроса в контексте Swing), то, например, вот так:
    byte[] arBytes;
    ...
    ImageIcon icon = new ImageIcon(arBytes);

    или так:
    BufferedImage image = ImageIO.read(new ByteArrayInputStream(arBytes));

    Если же цифры - действительно цифры, то тут, увы, нет иного способа "получить картинку", иначе как взять, да и отрисовать их на канвасе, например, вот так :
    int[] arInts = {0,1,2,3,4,5,6,7,8,9};
    ...
    BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2d = img.createGraphics();
    g2d.setPaint(Color.red);
    g2d.setFont(new Font("Serif", Font.BOLD, 18));
    FontMetrics fm = g2d.getFontMetrics();
    int x = 5;
    for(int i : arInts){
        String s = (new Integer(i)).toString();    
        g2d.drawString(s, x, 5);
        x += fm.stringWidth(s) + 5;
    }
    g2d.dispose();
    Ответ написан
    Комментировать