Страницы

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

суббота, 28 декабря 2019 г.

Yii framework или обычный php?

#framework #php #yii


Здравствуйте, гуру. Недавно узнал о неком волшебном Yii framework (да и вообще о
фреймворках на php). Посмотрел, да, вещь хорошая, но я не знаю стоит ли уходить с чистого
php на него, потому что 2 их я думаю трудноват о выучить (каша в голове будет)... В
Yii я делаю приложения немного быстрее, но на php привычней... Вот сижу мучаюсь, помогите
с выбором
PHP учу уже 1,5 года
    


Ответы

Ответ 1



Ну изначально тебе стоит изучать сам язык вне зависимости от того какой фреймворк на php ты будешь юзать. фреймворк и язык программирования разные вещи. Учи язык, фрейм поможет создавать приложения просто быстрее.

Ответ 2



На гуру не претендую, но могу сказать, что yii стоит того что его нужно изучить. Будет взрыв мозга.

Ответ 3



Все верно, используй Yii framework для развертывание проектов, если боишься забыть чистый php, возьми ученика кого нибудь_) обучение других, даст тебе отточенный инструмент, который в любое время будет готов к бою)

Ответ 4



Изучение фреймворков это хорошая практика) Хотябы для личного опыта. В них уже реализованны повседневные задачи, плюс вы застрахованны от ошибок при разработке(не от всех конечно). Вывод изучайте YII)

Ответ 5



Yii - фреймверк среднего уровня, надо начинать с более простого. http://habrahabr.ru/post/178833/

Автоматическое форматирование кода в Intellij IDEA

#java #intellij_idea


Привет! Знаю, что вопрос вообще не к вам, но в гугле пока что не получается найти.
Как в упомянутой в заголовке ide сделать так, чтобы она автоматически форматировала
код, который я ввожу, руководствуясь настройками code style
То есть, я ввожу
if(a


Ответы

Ответ 1



Ctrl+Alt+L - Reformat code IntelliJ IDEA Default Keymap.pdf

Ответ 2



'Ctrl + WindowsBtn + Alt + L' - Reformat code (Linux) 'WindowsBtn' - кнопка значка 'Windows' Для Mac это сочетание клавиш: Alt + Command + L Объяснение: В некоторых системах и виртуальных машинах сочетание клавиш 'Ctrl + Alt + L' вызовет совсем не ту реакцию, которую вы ожидали. В Linux Ubuntu такое сочетание вызовет блокировку сессии пользователя. Блокировку экрана. Официальная документация по Idea PS. В Idea вы можете изменить сочетание клавиш по умолчанию. Это может понадобится, если они конфликтуют с сочетаниями клавиш вашей системы.

Эффект размытия фона / Эффект матового стекла — CSS

#css #веб_дизайн


как сделать эффект размытия фона или эффект матового стекла как в iOS? я понимаю,
что можно добавить фильтр на картинку.. но как мне добавить этот фильтр на отдельный
слой и наложить этот слой поверх n'ое количество картинок??
    


Ответы

Ответ 1



Используйте filter: blur(5px);, ниже пример. img { width: 300px; } .blur { -webkit-filter: blur(5px); -moz-filter: blur(5px); -o-filter: blur(5px); -ms-filter: blur(5px); filter: blur(5px); }


Почему нет доступа к конструктору

#c_sharp


Всем привет. Есть такой код:

class a
{
    protected a(string s)
    {
        this.s = s;
    }
    public string s;   
}
class b : a
{
    public b(string s)  : base(s)
    { }
    public a RetObj()
    {
        return new a("jk"); //не работает
    }
}


Почему не создается объект в методе RetObj() ведь доступ к конструктору из класса
b открыт для этого же класа. При этом выдается ошибка Ошибка   1   a не содержит конструктор,
который принимает 1 аргументов Подскажите, что тут не так ?? Можно конечно сделать
в этом методе return this; но хотелось бы понять почему нельзя создать объект класса а.
    


Ответы

Ответ 1



Это ограничение стандарта языка. В C# 1 то, о чём вы говорите, было возможно. В более новых версиях языка (начиная с C# 2) действует следующее правило: Вы можете обращаться к статическим защищённым полям, свойствам и методам из дочернего класса без ограничений. Вы можете обращаться к нестатическим защищённым полям, свойствам и методам из дочернего класса только через какой-то (любой) объект этого самого дочернего класса. Причём имеется в виду не динамический (runtime-), а статический (compile time) тип объекта. Конструктор причисляется к группе, покрываемой вторым случаем. Мотивация: Откуда взялось такое дополнительное требование для instance-методов? А вот откуда. Допустим, что такого требования не было бы. Тогда всю защиту, накладываемую protected, было бы очень легко обойти. Действительно, пусть у нас есть такой класс: class B { protected int X = 0; } Кто угодно мог бы обойти защиту и изменить X таким образом: class Attacker : B { static public void ModifyX(B b, int value) { b.X = value; } } (Этот приём известен как паттерн «Паблик Морозов».) Правило 2 запрещает такие трюки. С этим правилом, автор класса Attacker может «испортить» только объекты своего класса, но не чужой объект. Поскольку на защите через атрибуты контроля доступности наподобие private/protected базируется безопасность библиотеки .NET, подобный метод «обхода» защиты был бы серьёзной дырой. Фактически, подобные дыры были найдены в коде .NET framework, так что это ограничение их ликвидирует. Ответ основан на статье Many Questions: Protected Constructors из блогов MSDN.

ToUpper/Lower vs Unsafe

#c_sharp #unsafe


Думаю всем известно что строки (System.String) неизменяемые по своей природе. Поэтому
часто работа с такими методами, как string.ToUpper() и прочими, порождает новый объект,
почти идентичный предыдущему. 

Я даже не хочу выяснять причины этого, у меня явно ума поменьше чем у ребят, которые
придумали такую обертку над массивом Char, но все же изменить строки можно, как минимум
через указатели.

Написал такой расширяющий метод:

public static unsafe String ToUpperUnsafe ( this String value )
{
    fixed ( Char* arrChr = value )
    {
        for ( var i = 0 ; i < value.Length ; ++i )
        {
            var temp = Char.ToUpper( value[ i ] );
            arrChr[ i ] = temp;
        }
    }

    return value;
}


Как видно, на вход принимается один объект, изменяется и возвращается без клонирования.
Вопрос в том, насколько это безопасно. Смотрел бегло исходники оригинального метода,
там много всего, что я не понял, из-за этого возникла мысль, что в определенных ситуациях
это может не прокатить.

p.s. Кстати ванильный метод работает быстрей, зато этот выигрывает в памяти.
    


Ответы

Ответ 1



Так делать нельзя. Дело в том, что весь framework исходит из того, что строки неизменяемы. Поэтому, например, если вы поместите строку в HashSet, а потом измените её, вы потом не сможете её оттуда удалить (а вместе с вами и другие куски программы, находящиеся далеко от вас и не знающие, что вы сломали строку). Метод сортировки, который не учитывает, что у него из-под носа могут заменить значение, имеет право зациклиться бесконечно или вылететь по обращению к неправильному индексу. Представьте себе, что будет, если строка, которую вы ломаете, интернирована. Тогда каждый, у кого была строковая константа "abc", внезапно без предупреждения получит строковую константу "ABC": string lo = "abc", hi = "ABC"; string villain = "abc"; villain.ToUpperUnsafe(); Console.WriteLine(lo == hi); // true Представьте себе так же, что вы сломаете строку, которая является названием типа. Что произойдёт при попытке применить рефлексию? Словом, ваш метод привносит в язык undefined behavour, отсутствие которого выгодно отличало C# от C++. Вся эта катавасия, которую может устроить одна «маленькая» оптимизация, совершенно не стоит выгоды в несколько микросекунд.

Ответ 2



Вопрос в том, насколько это безопасно. Да вообще небезопасно. Думаю всем известно что строки (System.String) неизменяемые по своей природе. ... Я даже не хочу выяснять причины этого Зря не хочешь. Представь всё, что записывается литералами. Это числа. В VB ещё даты. Всё это value-типы. int x = 50; x.Add(10); // Ну представим, что такой метод есть int y = 50; // Ну ты же не ждёшь, что теперь y равен 60? Аналогично со строками: string s = "abc"; s.ToUpper(); string t = "abc"; // Упс.. Твоя реализация сделает t = "ABC" По-моему, одного этого достаточно, чтобы никогда твой метод не использовать. А теперь, почему же reference-тип? Да это просто оптимизация - не надо копировать огромные строки при каждой передаче. Мы просто не меняем оригинал, поэтому семантически нет разницы между value и reference. А вот если мы хотим поменять, то надо создать новую строку.

Ответ 3



Вы только что изобрели велосипед :), используя unsafe, вместо класса StringBuilder, созданный именно для представления изменяемых строк.

Task не запускает метод

#c_sharp


Всем привет. Подскажите пожалуйста, почему в этом коде на выходе пустой экран.

class a
{
    static void Meth(int x, int y)
    {
        Console.WriteLine(x + y);
    }
    static void Main()
    {
        Task t = new Task(() => Meth(5, 4));
        t.Start();
    }
}


Что особенно меня удивило, что через пошаговую отладку, компилятор вообще не заходит
в метод Meth. Почему ?
    


Ответы

Ответ 1



Дело вот в чём. t.Start запускает Task на текущем TaskScheduler'е. Поскольку вы запускаете из не-UI-потока, у вас в нём работает TaskScheduler по умолчанию — тот, который выполняет Task в thread pool'е. Затем, что происходит сразу после запуска задания? Main завершается, и программа умирает, не успев выполнить задание. Задание уходит в thread pool, но программа успевает завершиться до начала выполнения задания. Потоки thread pool'а не приостанавливают завершение программы, если функция Main завершается, то при этом завершается вся программа. Попробуйте t.Wait() после t.Start().

Ответ 2



Этот код не успевает выполниться, так как программа завершает работу. Попробуй так: class Program { static void Meth(int x, int y) { Console.WriteLine(x + y); } static void Main() { Task task = new Task(() => Meth(5, 4)); task.Start(); task.Wait(); //Console.ReadKey(); } }

Ответ 3



Иногда задачу (скорее задачу ContinueWith) хорошо выполнить в том же потоке, что и пользовательский интерфейс. class Program { static void Meth(int x, int y) { Console.WriteLine(x + y); } static void Main() { SynchronizationContext.SetSynchronizationContext(new SynchronizationContext()); Task.Factory .StartNew( () => Meth(5, 4) ,CancellationToken.None ,TaskCreationOptions.None ,TaskScheduler.FromCurrentSynchronizationContext() ); //Console.ReadKey(); } } Когда я делал так в WPF, то SetSynchronizationContext устанавливать не надо было.

Как вставить картинку в RichTextBox?

#c_sharp #winforms


Как вставить картинку в RichTextBox? Находил нормальный пример только на WPF, а мне
нужно на WinForms. У меня текст в RichTextBox записывается с файла, и в некоторых местах
текста нужно вставить определенную картинку. Мне нужно программно вставлять изображение
с файла. Как это можно сделать? И есть ли какой-то годный аналог RichTextBox? 
    


Ответы

Ответ 1



Нужно модифицировать код RTF. Изображения в RTF представляются в следующем формате: "{\pict\wmetafile8\picw[N]\pich[N]\picwgoal[N]\pichgoal[N] [BYTES]}", где \pict - группа изображения \wmetafile[N] - индикатор того, что изображение является Windows Metafile. [N] = 8 указывает, что размеры осей метафайла могут быть изменены независимо. \picw[N] и \pich[N] - указывает размер изображения, где [N] указывается в сотых миллиметра (0.01мм). \picwgoal[N] и \pichgoal[N] - указывает желаемый размер изображения, где [N] указыается в 1/1440 дюйма. [BYTES] - HEX-представление изображения. Почитать о том, как правильно реализовать модифицию RTF-кода, можно тут: https://stackoverflow.com/questions/18017044/insert-image-at-cursor-position-in-rich-text-box

Ответ 2



Можно попробовать вставить картинку, используя метод Paste(): Image img = Image.FromFile("winter.jpg"); Clipboard.Clear(); Clipboard.SetImage(img); richTextBox1.Paste(); Clipboard.Clear();

зачем нужен synchronized()

#java #android #многопоточность #synchronized


Интент-сервис регистрации/логина в приложении.

@Override
protected void onHandleIntent(Intent intent) {
    try {
        // ЗАЧЕМ ?
        synchronized (TAG) {
            // [START register_for_gcm]
            // Initially this call goes out to the network to retrieve the token,
subsequent calls
            // are local.

            // [START get_token]
            InstanceID instanceID = InstanceID.getInstance(this);

            String token = instanceID.getToken(
                    getString(R.string.gcm_defaultSenderId),
                    GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
            // [END get_token]

            if (intent.getStringExtra("state").equals("registration")) {
                //make registration request with callback
            } else if (intent.getStringExtra("state").equals("login")) {
                //make login request with callback
            }


            subscribeTopics(token);

            // [END register_for_gcm]
        }
    } catch (Exception e) {
    }
}


Вопросы:


Зачем тут используется synchronized() ?
Для чего в целом нужен synchronized() , где его использовать?


Читал про многопоточность, но не особо понял что и как.
Буду рад объяснением простыми словами.
    


Ответы

Ответ 1



Простыми словами: если у вас есть переменные, которые изменяются в одном из потоков, и читаются в другом, то их использование нужно синхронизировать. То есть, заключать их использование в блок synchronized. Использование блока synchronized исключает одновременное выполнение этих блоков (синхронизирующихся по одному и тому же объекту) разными потоками. Зачем именно тут используется synchronized — скорее всего, какая-то часть кода внутри работает с разделяемыми переменными.

Ответ 2



В вашем примере используется synchronized-блок чтобы сделать потокобезопасным код внутри блока, т.е. если этот код уже выполняется в каком-то потоке, то другой поток не сможет начать выполнение этого кода, пока предыдущий поток не завершит выполнение. Подробно о синхронизации и многопоточности лучше читать в официальной документации java

Получить id объекта с помощью jQuery

#jquery


есть кусок html

    
Год:
Неделя:
Пытаюсь получить значение активной недели $("#week ul li.active").attr('id'); получаю 2016, т.е. показывает год, а не неделю. Не могу понять в чем косяк.


Ответы

Ответ 1



В html ошибка: 3/li>, а должно быть 3 Чтобы получить 3, пишете так: var v = $("#week .active").text(); или так var v = $("#week .active").attr("id"): если на странице несколько тегов с id="week", и надо получить последний, то так var v = $("#week .active").last().attr("id"); UPDATE Т.к. в селекторе "#week .active" не указан тег li, то селектор будет работать, даже если изменить html на следующий:
5


Ответ 2



Это все из-за не правильного селектора $("#week ul li.active") данный селектор ищет список ul внутри элемента с id="week". А у вас сам ul имеет этот id. Таким образом, нужно изменить этот селектор, сказав что мы ищем именно ul с таки id $("ul#week li.active") либо вообще опустить ul $("#week li.active") так как id должен быть уникальным на странице этого селектора достаточно Что касается получаю 2016, т.е. показывает год, а не неделю. судя по предоставленному куску кода - вывод вашего селектора должен быть undefined. Если вы получаете именно 2016, можно предположить, что данный кусок кода расположен внутри контейнера с id="week", т.е. на странице у вас как минимум два элемента с таким id. Пример console.log($("#week ul li.active").attr('id')); $('body').append($("#week ul li.active").attr('id')); console.log($("#week ul li.active"));
Год:
Неделя:


Ответ 3



У вас здесь ошибка: $("#week ul li.active").attr('id'); ID week это и есть список ul, должно быть так: $("#week li.active").attr('id');

Ответ 4



Эх.. Никто не вспоминает про prop... $("#week .active").prop('id');

Как найти точку на отрезке?

#алгоритм


У меня есть отрезок с известными координатами концов. На этом отрезке есть точка.
Я знаю расстояние от начала отрезка до этой точки. Мне надо найти координаты этой точки.
 Как найти эти координаты?

Пример: Есть 2 точки А(3,3) и В(6,4). Длина отрезка примерно 3,16. И есть точка С(?,?)
на отрезке. Как найти координаты, если от А до С =1,8 ???
    


Ответы

Ответ 1



Алгоритм без кода (довольно элементарный): Имеем: Две точки A, B; len - расстояние от точки А до требуемой точки C full_len = |B - A| // длина вектора, соединяющего две точки == длина отрезка C = A + (B - A) * (len / full_len) Сложение векторов и умножение на число - очевидные операции.

Ответ 2



Имеется отрезок AB с координатами A(Xa, Ya) и B(Xb, Yb). Требуется найти координаты точки C(Xc, Xc), лежащей на отрезке AB на расстоянии Rac от точки A. Rab = sqrt((Xb-Xa)^2 + (Yb-Ya)^2) k = Rac / Rab Xc = Xa + (Xb-Xa)*k Yc = Ya + (Yb-Ya)*k

Ответ 3



nodet - точка конец вектора, в твоем случае точка b nodef - точка начало вектора, в твоем случае точка a dx = nodet.x - nodef.x dy = nodet.y - nodef.y dz = nodet.z - nodef.z r = math.sqrt(dx ** 2 + dy ** 2 + dz ** 2) xx = dx * (step/r) yy = dy * (step /r) zz = dz * (step /r) newnode = node(nodef.x + xx,nodef.y + yy,nodef.z + zz) newnode - новая точка на заданом расстоянии

Получить ключ по значению

#python #python_3x


Есть словарь:

d = {'a': '1', 'b': '2', 'c': '3'}


и есть строка: 

stroka = 'a3a2c'


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

Т.е. для строки 'a3a2c' ожидаемый вывод '113' и 'cb'


Как вывести значения по ключу - я разобрался:

for i in stroka:
    if i in d.keys():
        print(d[i], end='')


А вот вывести ключ по значению у меня не получается:

for j in stroka:
    if j in d.values():
        print(?????, end='')

    


Ответы

Ответ 1



Как то так: d = { 1: '1', '2': 2, 3: '3', } def get_key(d, value): for k, v in d.items(): if v == value: return k print(get_key(d, '1')) print(get_key(d, 2)) print(get_key(d, 42)) Консоль: 1 2 None Вообще, когда мне нужно получать значение по ключу и ключ по значению, я завожу два словаря.

Ответ 2



Т.е. для строки 'a3a2c' ожидаемый вывод '113' и 'cb' Если есть словарь d и коллекция ключей keys, то чтобы получить соответствующие значения, используя default значения для отсутствующих ключей: def get_values(d, keys, default=None): return (d.get(k, default) for k in keys) Пример: d = {'a': '1', 'b': '2', 'c': '3'} s = 'a3a2c' print(''.join(get_values(d, s, ''))) # -> 113 inv_d = dict(zip(d.values(), d.keys())) print(''.join(get_values(inv_d, s, ''))) # -> cb Если хочется сразу отфильтровать отсутствующие ключи: def get_existing_values(d, keys): return filter(None, map(d.get, keys)) Пример: >>> ''.join(get_existing_values(inv_d, s)) 'cb'

Ответ 3



d=dict(a='1',b='2',c='3') # первый словарь print(d) stroka = 'a3a2c' print('stroka=',stroka) for m in stroka: #поиск элементов из stroka в ключах d if m in d.keys(): #вывод значений этих лючей print('буква ', m, 'из строки "stroka" является ключом значения ', d[m]) s=[] for i in d.keys(): #второй s.append((d[i],i)) #словарь b=dict(s) #является обратным для первого #значения являются ключами, а ключи значениями stroka_=stroka for i in stroka_: #поиск элементов из stroka в значениях d if i in b.keys(): #вывод ключей этих значений print('цифра ', i, 'из строки "stroka" является значением ключа', b[i]) Но задача была бы чуть интересней, если бы представление значений словаря было не строчным, а целочисленным.

Ответ 4



Для словаря {'a': 1, 'b': 2, 'c': 3} (значения словаря являются элементами типа int) d=dict(a=1,b=2,c=3) # первый словарь print(d) stroka = 'a3a2c' print('stroka=',stroka) for m in stroka: #поиск элементов из stroka в ключах d if m in d.keys(): #вывод значений этих лючей print('буква ', m, 'из строки "stroka" является ключом значения ', d[m]) s=[] for i in d.keys(): #второй s.append((d[i],i)) #словарь b=dict(s) #является обратным для первого #значения являются ключами, а ключи значениями stroka_=stroka #stroka_ = 'a3a2c' #поиск элементов из stroka в значениях d #вывод ключей этих значений v=','.join(str(b.keys())) #v=d,i,c,t,_,k,e,y,s,(,[,1,,, ,2,,, ,3,],) s_=[] for i in v: try: s_.append(int(i)) except ValueError as e: continue # s_= [1, 2, 3] i=0 while i < len(s_): s_[i]=str(s_[i]) i+=1 # s_= ['1', '2', '3'] #поиск элементов из stroka в значениях d #вывод ключей этих значений for i in stroka_: #stroka_ = 'a3a2c' if i in s_: # s_= ['1', '2', '3'] print('значение', stroka_[stroka_.index(i)], 'из строки "stroka" является значением ключа', b[int(i)])

Ответ 5



for key in a: print ("%s -> %s" % (key, a[key])) #python3

Ответ 6



решил вашу проблему немного по-другому. просто превратите ключи словаря в tuple методом list() и сохраните его в новой переменной, затем вызовите значения ключа и сохраните его в переменной, и в конце уже можно print(переменная_1[индекс ключа которую вы сохранили], переменная_2[индекс ключ]

Как склеить 4 unsigned char в один unsigned int

#cpp #битовые_операции


Объясните, пожалуйста, как использовать битовый сдвиг для того, чтобы из четырёх
переменных unsigned char получить одну unsigned int, затем проделать обратное действие.
    


Ответы

Ответ 1



Последовательно в младшую часть int кладем очередной байт и сдвигаем влево на 8 бит. Что бы положить 1 байт в младшую часть используем логическое ИЛИ: unsigned char c1=5,c2=10,c3=98,c4=67; unsigned int I; I=c4; // c4 в младших 8и битах, остальные 0 I<<=8; // Сдвигаем int влево на 8 бит. Младшие 8 бит становятся 0, c4 становится в 9-16 битах. I|=c3; // Логическое ИЛИ заменяет 0 биты на те, что в байте c3 I<<=8; I|=c2; I<<=8; I|=c1; // Аналогично кладем остальные байты Для обратного действия сдвигаем int так, что бы нужный нам байт был самым младшим и маскируем остальные биты логическим И: c1=I & 0xFF; c2=(I>>8) & 0xFF; c3=(I>>16) & 0xFF; c4=(I>>24) & 0xFF; Только следим за порядком байт, на разных архитектурах числа в int принято класть по разному.

Ответ 2



Если вам нужно делать только такую операцию упаковки/распаковки то могу предложить вообще не используя битовые операции. unsigned int UI = 0x12345678; char *CC = (char *)(&UI); for (int i=3;i>=0;i--) cout << (int)CC[i]<<" "; unsigned char NC[4] = {120,86,52,18}; unsigned int TI = *(unsigned int *)(NC); cout << TI; Идея основана на явном преобразовании указателя. https://ideone.com/1P4tfc запускаемый пример.

Ответ 3



Например, вот так: int main() { unsigned char ch1 = 0x1; unsigned char ch2 = 0x2; unsigned char ch3 = 0x3; unsigned char ch4 = 0x4; unsigned int value = ch1; value <<= 8; value |= ch2; value <<= 8; value |= ch3; value <<= 8; value |= ch4; } Или чуть более общий вариант решения: #include const size_t BYTE_COUNT_IN_INT = 4; const size_t BITS_COUNT_IN_BYTE = 8; unsigned int getIntFromCharsArray(const std::array& charsArray) { unsigned int result = charsArray[0]; for (size_t i = 1; i <= BYTE_COUNT_IN_INT - 1; ++i) { result <<= BITS_COUNT_IN_BYTE; result |= charsArray[i]; } return result; } std::array getCharsArrayFromInt(unsigned int value) { std::array result; for (size_t i = 0; i <= BYTE_COUNT_IN_INT - 1; ++i) { result[BYTE_COUNT_IN_INT - i - 1] = value; value >>= BITS_COUNT_IN_BYTE; } return result; } int main() { const std::array charsArray = { 0x1, 0x2, 0x3, 0x4 }; unsigned int intFromCharsArray = getIntFromCharsArray(charsArray); auto charsArrayFromInt = getCharsArrayFromInt(intFromCharsArray); }

Ответ 4



Дополню. Если нужна именно конвертация и можно не использовать битовые сдвиги, то самое простое решение через union: union converter { unsigned int number; unsigned char bytes[4]; }; Число в байты: converter c; c.number = 123; // c.bytes[0] == 0xD2 // c.bytes[1] == 0x04 // c.bytes[2] == 0x00 // c.bytes[3] == 0x00 Байты в число: converter c; c.bytes[0] = 1; c.bytes[1] = 2; c.bytes[2] = 3; c.bytes[3] = 4; // c.number == 0x04030201 (big-endian)

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

#алгоритм


Есть алгоритм  сложности O(n*Log(n)), есть ЭВМ с процессором 2.1Ггц.
Проблема: как вычислить время работы алгоритма на машине если мы знаем N?

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

При вычислении времени работы алгоритма по функции сложности меня смущает то, что
вот такие вещи не учитывается:

a = a+b;// O(1) 1с
b = b+1;// O(1) 1с


Итого время выполнения этих операций равно 2с, функция сложности равна O(1).
По функции сложности как-то не удается получить время выполнения алгоритма.
Возможно ли d принципе определить время работы алгоритма, зная его сложность?
    


Ответы

Ответ 1



Это невозможно. "Функция сложности" O(f(N)), как Вы её назвали, отвечает на вопрос о том, с какой скоростью растёт число операций алгоритма (f(N)), когда N устремляется к бесконечности. То есть, например, если сортировка имеет сложность O(N^2), то значит при удвоении размера массива Вы получите учетверение числа операций, необходимых для сортировки, при условии, что N - это очень большое число. Никакого отношения ко времени работы данная функция не имеет. O(1) Означает, что скорость работы функции не зависит от размера входного параметра N, при этом время работы может быть от нуля секунд до миллиарда лет (и больше). Ещё Вам следует понять разницу между алгоритмом, и программой, его реализующей. Сложность алгоритма - это одно, а скорость программы - это совсем другое. Эти величины могут быть связаны, но далеко не всегда очевидным образом. Подробности (но весьма сложные) можно прочитать здесь.

Ответ 2



Сложность говорит не о самом времени, а о том, как оно будет меняться с изменением n. Вы можете замерить время работы вашей программы на целевой машине для некоторого конкретного (например, небольшого) n, и зная сложность, оценить, сколько времени займет работа при других (например, очень больших) значениях.

Как редактировать код в загруженных библиотеках?

#java #android #gradle #android_library


Здравствуйте, я загрузил библиотеку

compile 'com.daimajia.slider:library:1.1.5@aar'

и в ней есть баг, мне надо его пофиксить. Но я не могу вносить правки в проект, он
закрыт для редактирования.



Пожалуйста помогите!
    


Ответы

Ответ 1



Просто так вносить изменения в подключаемую через jar библиотеку нельзя. Для того, чтобы исправить баг клонируйте репозиторий с проектом к себе на машину, подключайте как локальный модуль и тогда уже вносите изменения в нее. Если вы используете у себя в проекте систему контроля версий git, то легче всего подключить библиотеку как подмодуль. Для этого: В командной строке переходите в коталог со своим проектом; Выполняете команду git submodule add git://github.com/path_to_lib; В корневом файле settings.gradle добавляете ее так include ':libName'; В build.gradle модуля приложения добавляете так compile project(':LibName:library'). После этого вы можете вносить изменения в библиотеку, которые потом будут отображены в вашем проекте. После чего вы легко сможете отправить pull request автору библиотеки с фиксом бага. Про то, как работать с подмодулями в гит, и как они себе ведут при коммите прочтите на официальном сайте(ссылка выше).

Ответ 2



Вбейте в гугл пакет библиотеки. По первой ссылке перейдите на страницу либы на GitHub-e Скачайте библиотеку как набор исходных файлов в архиве. Распакуйте архив. Откройте код в IDE Отредактируйте. Соберите *.jar файл библиотеки (опционально) Подключите исправленную версию библиотеки или с помощью файла из п.7 или добавьте проект с библиотекой в виде зависимости.

Ответ 3



Вы не можете изменять уже собранные библиотеки (строго говоря можете, но это плохой и сложный путь). Вы можете либо отнаследоваться от проблемного класса, исправить поведение в наследнике и использовать его если косяк не слишком глубокий. Либо если это open source библиотека форкуть её, исправить и либо отправить пулл реквест с исправлением автору оригинальной библиотеки что бы он включил его в свой репозиторий и обновил библиотеку, либо собрать свою реализацию и использовать её в своём проекте.

Ответ 4



При подключении библиотеки способом, который у вас в вопросе, вы получаете скомпилированный файл, который нельзя редактировать. Для решения вашей проблемы вам нужно подключить данную библиотеку в виде исходных кодов (пункт 3 ответа), если разработчик предоставляет такой формат распространения своей библиотеки (исходники) и внести исправления в своей локальной копии, либо, что предпочтительнее и правильнее, писать ему багрепорт, чтобы он исправил баг в новой версии своей библиотеки и использовать ее.

Тип для хранения материала предмета

#java #c_sharp #cpp #алгоритм


Допустим есть класс Item - предмет
И у этого класса есть переменная, которая хранит в себе значение - тип предмета
Это может быть стол, или ключ или что-то еще
И вот возникает потребность узнать что за предмет перед нами? Всем сразу понятно,
нужно написать геттер
Но вот мне не понятно: лучше хранить в переменной целочисленного типа или же строкового?
Например(Java):

private final int ID;
/* куча кода */
ID = 255;


Или же

private final String TYPE;
/* еще одна куча кода*/
TYPE = "Stone";


P.S.: пример кода написан на Java, но он относится не только к этому языку
    


Ответы

Ответ 1



Не храните тип(класс) объекта в объекте если вы имеете дело с языком с сильной типизацией. Как правило, это ошибка проектирования. Вы можете легко нагуглить русский перевод книги "Скользкие места C++", где подробно описано, почему так делать нельзя - за исключением очень редких случаев - вкратце: накладные расходы, лишний код, ручные проверки, гора ошибок. Для других языков, думаю, подобные статьи/учебники тоже легко найти. Поймите, что тип объекта и его значение - это две абсолютно разные концепции. Полиморфизм придуман как раз для того, чтобы программист не выбирал, например "а какую функцию вызвать, если объект должен двигаться?" Камень - не двигается Птица - летит Курица - (якобы не птица), ходит. но если испугана, подпрыгивает и немножко летит, и почти всегда летит, если прыгает с высоты. Кот - ходит Машина - едет Мина с детектором движения - взрывается в языке с сильной типизацией и поддержкой полиморфизма вы просто вызываете метод move и объект сам выполняет свой метод move, а если у него нет такого метода, вы (можете) получить ошибку при компиляции. Без лишних проверок, без лишних ошибок P.S. кроме того, в C++ и Java есть свои способы узнать тип объекта: для C++ - RTTI в рантайме или SFINAE на этапе компиляции для Java - someObject.getClass() для Java, я так полагаю, вызов getClass может нести дополнительные накладные расходы в рантайме, если вы начнете еще и хранить тип отдельным значением, расходы (память/цпу) еще больше возрастут для C++ использование RTTI всегда несет дополнительные расходы (и еще кучку проблем), и применяется достаточно редко P.P.S. если говорить про метапрограммирование, то в C++ с использованием шаблонов/библиотеки в духе boost:hana понятия типа/значения могут слегка размываться, но это совсем другая тема для беседы P.P.P.S. если вам неймется и/или очень надо (например, в случае, когда ваши материалы это не какие-то классы, а просто номера текстур), то их надо хранить в константах, доступных языку (для c++ это define/enum/enum class), а не в строковых значениях. Константы будут обработаны на этапе компиляции, займут в памяти меньше места, и кроме того, вы получите поддержку автодополнения вашей IDE (поскольку она увидит, что константа MATERIAL_TYPE_CONCRETE (ака бетон, допустим) присутствует в коде), а строчки будут болтаться туда-сюда со всеми их конструкторами и накладными расходами и без всякой поддержки со стороны IDE P.P.P.P.S конкретно к вопросу не относится, но может вам помочь: если вы делаете игру или нечто похожее, что требует много разнообразных ресурсов, текстур, моделей объектов и т.д., я бы на вашем месте сделал следующее: запихиваете все ресурсы в бд (mysql/postgres/sqlite - по ситуации смотрите) допустим в виде записи (айди, имя, тип ресурса, хэш объекта может быть) делаете простой веб-редактор или командный скрипт для добавления ресурса в бд. пишете простой скриптик, который генерирует вам заголовочный файл C++ или Java-класс из этой базы данных это потребует день-два работы, зато профит вы начнете ощущать каждый раз, когда вам не придется руками добавлять файл в код, размещать его в нужном каталоге и т.д. если для дебаг-режима вы добавите еще и запись в бд по частоте использованя ресурса,сможете например, легким запросом получить статистику, какие ресурсы у вас не используются, или для каких ресурсов слишком мало текстур и т.д.

Как правильно работать с транзакциями в MS SQL Server?

#sql #sql_server


Запустил 3 запрос на обновление 3-ех разных таблиц и обернул в Begin Tran и Commit Tran.

На втором запросе получил ошибку, но данные в первой таблице не откатились.

Разве не должен был быть откат?

UPD

Как я понимаю, я должен был использовать вместо

BEGIN TRAN
UPDATE 1
UPDATE 2
UPDARE 3
COMMIT TRAN


Вот это

    BEGIN TRAN
    UPDATE 1
    UPDATE 2
    UPDARE 3
if @error<>0
    rollback tran
    COMMIT TRAN


?

Если это так, то статься на MSDN https://msdn.microsoft.com/ru-ru/library/ms190295.aspx

Вводит в заблуждение, так не показан пример с проверкой на ошибки...

Еще не понял вот такого поведения:

Делал такой эксперимент:
Сначала делаю N раз вот этот запрос:

BEGIN TRAN
INSERT INTO ttt VALUES  (GETDATE())


--Транзакцию специально не закомитил

Затем отдельно делаю:

COMMIT TRAN


Затем 

ROLLBACK tran


У меня откатились все мои N инсертов, хотя я сделал COMMIT TRAN, а лишь потом ROLLBACK
tran.  По идее транзакция должна была завершиться и на откат ничего не должно было пойти...
    


Ответы

Ответ 1



В случае конструкции BEGIN TRAN UPDATE 1 UPDATE 2 --error UPDATE 3 COMMIT TRAN (при выполнении команд не в блоке TRY ... CATCH ...) если на втором UPDATE возникнет ошибка, исполнение команд может продолжиться и дойти до COMMIT. Использование варианта BEGIN TRAN UPDATE 1 UPDATE 2 UPDATE 3 IF @@ERROR <> 0 ROLLBACK TRAN ELSE COMMIT TRAN не будет правильным, т.к. глобальная переменная @@ERROR содержит номер ошибки для последней исполненной команды. Это означает следующее: если UPDATE 1 или UPDATE 2 завершится с обшибкой, а UPDATE 3 - без ошибки, то после UPDATE 3 значение переменной @@ERROR станет равно 0, что сделает ложным вывод об успешности всей транзакции. Если нужно при ошибке делать откат, то тут могут быть два варианта. Первый - это исполнение команд в блоке TRY ... CATCH ... BEGIN TRY BEGIN TRAN UPDATE 1 UPDATE 2 --error UPDATE 3 COMMIT TRAN END TRY BEGIN CATCH ROLLBACK TRAN END CATCH В этом случае, при возникновении ошибки на 2м шаге, исполнение не продолжится, а по-возможности перейдёт в блок CATCH, где можно принудительно вызвать ROLLBACK. Второй вариант - включение опции XACT_ABORT перед входом в транзакцию. SET XACT_ABORT ON BEGIN TRAN UPDATE 1 UPDATE 2 --error UPDATE 3 COMMIT TRAN В этом случае при возникновении ошибок (определённого рода, не любых) на 2-м UPDATE выполнение команд будет прервано и произойдёт автоматический откат изменений. (Может быть даже не стоит считать этот вариант самостоятельным, на мой взгляд включение XACT_ABORT - это некое дополнительное средство; не припомню случая, когда бы я для отката транзакции пользовался этой опцией обособленно). В некоторых случаях используется и то и другое. Ниже чуть подробнее об автоматическом и управляемом откате. Автоматический ROLLBACK ROLLBACK может происходить автоматически, при закрытии соединения, если для данного соединения есть незавершенные транзакции. Т.е. создали, например, таблицу create table test (id int primary key); Открываем соединение и в нём выполняем begin tran; insert into test (id) values (1); select * from test; закрываем соединение, не завершив транзакцию (ни COMMIT, ни ROLLBACK не сделали). SqlServer сделает откат такой транзакции, при разрыве соединения. Запросив затем данные из таблицы в новом соединении, мы увидим, что она пустая. Также автоматический ROLLBACK может происходить при возникновении ошибок (таких как, например, нарушение PK, FK ограничений при вставке или удалении данных), если включена опция XACT_ABORT (по умолчанию OFF). Например: set xact_abort on; begin tran; insert into test (id) values (2); select * from test; insert into test (id) values (2); --error: Violation of PK ... select * from test; commit tran; в этом случае до второго select и до commit дело не дойдёт, и откат произойдёт автоматически. Теперь при выключенном xact_abort (то что по умолчанию): set xact_abort off; begin tran; insert into test (id) values (3); insert into test (id) values (3); -- error insert into test (id) values (4); commit tran; select * from test; Несмотря на ошибку дело дойдёт и до commit (соответственно отката не будет) и до select после него. К сожалению опция set xact_abort on полезна далеко не всегда. В частности она не откатывает транзакцию при генерации пользовательских исключений (в том числе сгенерированных в DML-триггерах). Например: set xact_abort on; begin tran; insert into test (id) values (5); if not exists (select 1 from test where id = 0) raiserror('Bad data', 16, 1); commit tran; select * from test; Несмотря на set xact_abort on и сгенерированное исключение дело дойдёт и до commit и до select после него. Поэтому полезнее может быть целенаправленный вызов rollback. -- вернули опцию в состояние по-умолчанию, если она была оставлена в состоянии ON set xact_abort off; Управляемый ROLLBACK Часто применяется в catch блоке, при оборачивании транзакции в try ... catch ... конструкцию: begin try begin tran; -- тут делаем что-то commit tran; end try begin catch rollback tran; end catch При xact_abort off (т.е. по умолчанию) ROLLBACK не происходит автоматически, если транзакция была открыта, но из-за ошибки не достигла COMMIT. В этом случае SqlServer позволяет программисту самому решить будет ли откат полезен при той или иной ошибке, или нет. Далее пара примеров, когда откат может быть полезен в catch и когда вреден. Пример 1: Изменение данных в транзакции. Пусть есть процедура, которая в транзакции делает вставку данных в две связанных таблицы: create procedure dbo.SetUserInfo ( @uid uniqueidentifier = NULL, @info xml ) as begin try set nocount, xact_abort on; if @info is NULL or @info.exist('/User') = 0 begin raiserror('No or bad data provided.', 16, 1); return; end; begin transaction; declare @inserted table (ID int not NULL); declare @id int; merge into dbo.Users t using( select @uid, @info.value('(/User/@FirstName)[1]', 'nvarchar(50)'), @info.value('(/User/@LastName)[1]', 'nvarchar(50)') ) s(UID, FirstName, LastName) on t.UID = s.UID when matched then update set t.FirstName = s.FirstName, t.LastName = s.LastName when not matched then insert (UID, FirstName, LastName) values (s.UID, s.FirstName, s.LastName) output inserted.ID into @inserted (ID) ; select @id = ID from @inserted; merge into dbo.UserContacts t using ( select @id, ct.ID, x.c.value('@Value', 'nvarchar(400)') from @info.nodes('/User[1]/Contacts[1]/Contact') x(c) join dbo.UserContactTypes ct on ct.Type = x.c.value('@Type', 'nvarchar(400)') ) s (UserID, ContactTypeID, ContactInfo) on t.UserID = s.UserID and t.ContactTypeID = s.ContactTypeID when not matched by source then delete when matched then update set t.ContactInfo = s.ContactInfo when not matched then insert (UserID, ContactTypeID, ContactInfo) values (s.UserID, s.ContactTypeID, s.ContactInfo) ; commit transaction; end try begin catch declare @errMsg nvarchar(4000) = error_message(), @errLine int = error_line(), @procName sysname = quotename(object_schema_name(@@procid)) + '.' + quotename(object_name(@@procid)) ; if @@trancount > 0 rollback transaction; raiserror('%s in %s at %d', 16, 1, @errMsg, @procName, @errLine); end catch GO Допустим теперь, что произошёл вызов процедуры и началась вставка данных. Предположим, что вставка в Users прошла успешно, а при вставке в UserContacts произошел конфликт с уникальным индексом (UserID, ContactTypeID) (из-за того, например, что в @info один и тот же затесался дважды). Если логикой приложения продиктовано, что либо сущность вставляется целиком, либо вообще не вставляется - тогда в catch делается rollback (как в данном примере). Но возможны ситуации, когда ошибки, возникшие в результате выполнения каких-то отдельных запросов, не являются серьёзным основанием для отката всех совершенных действий. Например, если у нас не две связанных таблицы, а импорт данных в несколько независимых таблиц, и мы не хотим откатывать ту часть данных, что была уже успешно внесена. Тогда в catch можно попытаться сделать commit (не любая ошибка сделает это возможным, о том как это сделать корректно - в следующем примере). Т.е. rollback не обязан происходить при возникновении любой ошибки. Делать откат, или нет - зависит от семантики данных и логики приложения. Пример 2: Чтение данных в транзакции. Транзакции для изменения данных достаточно привычны, но иногда в транзакции нуждается и чтение. Для таких транзакций необдуманно вызванный rollback может оказать медвежью услугу. Пусть есть процедура, которая в repeatable read или snapshot транзакции читает данные: create procedure dbo.GetSalesData ( @dateFrom datetime, @dateTo datetime ) as begin try set nocount on; declare @userID int; select @userID = UserID from #Session; if @userID is NULL begin raiserror('Access denied.', 16, 1); return; end; create table #Orders (OrderID int not NULL); alter table #Orders add primary key (OrderID); set transaction isolation level snapshot; begin transaction; insert into #Orders (OrderID) select op.OrderID from dbo.OrderPermissions(@userID) op join dbo.Orders ord on ord.ID = op.OrderID where op.[Permissions] > 0 and ord.[Date] >= @dateFrom and ord.[Date] < @dateTo -- some check based on #Order and other data if exists (select 1 from #Orders o join ... where ...) begin raiserror('Check fail.', 16, 1); return; end; select ... from dbo.Orders ord join #Orders o on o.OrderID = ord.ID select ... from dbo.Invoices inv join #Orders o on o.OrderID = inv.OrderID select ... from dbo.Shipment sh join #Orders o on o.OrderID = sh.OrderID commit transaction; end try begin catch declare @errMsg nvarchar(4000) = error_message(), @errLine int = error_line(), @procName sysname = quotename(object_schema_name(@@procid)) + '.' + quotename(object_name(@@procid)) ; if xact_state() = 1 commit transaction; else if xact_state() = -1 rollback transaction; raiserror('%s in %s at %d', 16, 1, @errMsg, @procName, @errLine); end catch GO В процедуре происходит следующее. Открывается транзакция. В ней заполняется фильтрующая таблица #Orders (чтобы потом дать пользователю только то, что ему разрешено видеть). Затем некоторая проверка на основании #Orders и других данных. Если проверка проходит, то данные отдаются, если нет - генерируется ошибка. Предположим, что эта проверка не была успешной. Открыта транзакция и произошла ошибка raiserror('Check fail.', 16, 1), вследствие чего управление передаётся в catch. Должен ли в catch произойти rollback? Нет. Ведь мы только читаем данные и ничего не изменяем (кроме временной таблицы #Orders). Более того, таблица #Orders создана до входа в транзакцию, а заполнялась в транзакции. Вследствие чего, если бы мы стали делать rollback начал бы происходить откат вставленных в неё данных, а это дольше, чем commit и простое уничтожение #Orders при выходе из процедуры. Т.е. в данном случае в catch лучше попытаться сделать commit, возможность или невозможность которого определяется функцией XACT_STATE().

Вернуть true если скобки совпадают

#javascript


Помогите с примером: необходимо вернуть true если скобки совпадают, или false если
нет. Набор скобок такой: ()[]{}

Например text with([brackets]) true 
text with ([wrong brackets)] false
    


Ответы

Ответ 1



Ну как-то так: /** * Проверяем корректный порядок скобок в строке * * @param {String} exp Строка с скобками для проверки * * @return {Boolean} */ function test(exp){ // Если передали не строку - выходим if(typeof exp !== 'string') return false; let stack = [], // Сюда можно добавлять свои скобки: ключ - открываемая, значение - закрываемая brackets = {'(': ')', '{': '}', '[': ']'}, openRegExp = [], closeRegExp = [], str = exp; // Создаём регулярные выражения для поиска Object.keys(brackets).forEach(e => openRegExp.push(`\\${e}`)); openRegExp = new RegExp(openRegExp.join('|')); for(let i in brackets) if(brackets.hasOwnProperty(i)) closeRegExp.push(`\\${brackets[i]}`); closeRegExp = new RegExp(closeRegExp.join('|')); // Добавляем все найденные открывающие скобки в стёк while((tmp = openRegExp.exec(str)) && (str = str.substr(++tmp.index))) stack.push(tmp[0]); str = exp; // Если нашли какую-то закрывающую скобку while((tmp = closeRegExp.exec(str)) && (str = str.substr(++tmp.index))) // То проверяем: Или закончился стёк, а закрывающие скобки всё прибывают // Или является ли найденная скобка парой к открывающей скобке в конце стёка (самой глубокой) if(!stack.length || brackets[stack.pop()] !== tmp[0]) return false; // Всё ОК return true; } [ `text with([brackets]) true`, `text with ([wrong brackets)] false`, `()[]{}()sdgsdg(sdg((((sg))))))(([[{sds}]]))` ].forEach(t => console.info(t, test(t)));

Ответ 2



Несмотря на то, что ответ уже дан (и помечен как правильный) существует намного более простой и эффективный (с точки зрения вычислительных ресурсов) способ решения задачи. (Это особенно важно, если речь идет о собеседовании.) Суть его заключается в обходе строки и поиске "несбалансированных" скобок с использованием стека. Алгоритм имеет вид: Выбираем первый символ строки Если это открывающая скобка - помещаем ее в стек Если это закрывающая скобка, извлекаем последнее значение из стека и проверяем скобки на соответствие. Если стек пуст или закрывающая скобка не соответствует открывающей - прерываем выполнение и возвращаем false Переходим к следующему символу строки и повторяем действия с п.2 Если по окончании выполнения алгоритма стек не пуст (это возможно, если открывающих скобок больше, чем закрывающих) - возвращаем false. Реализация на JavaScript может иметь вид: var test = function(str) { var chars = str.split(''), stack = [], open = ['{', '(', '['], close = ['}', ')', ']'], closeIndex, openIndex; // Проходимся по строке, проверяя каждый ее символ (п.4). for (var i = 0, len = chars.length; i < len; i++) { openIndex = open.indexOf(chars[i]); if (openIndex !== -1) { // Нашли открывающую скобку. Помещаем ее в стек (п.2). stack.push(openIndex); continue; } closeIndex = close.indexOf(chars[i]); if (closeIndex !== -1) { // Нашли закрывающую скобку. Проверяем ее соответствие открывающей (п.3). openIndex = stack.pop(); if (closeIndex !== openIndex) { return false; } } } // Проверяем дисбаланс открытых/закрытых скобок (п.5). if (stack.length !== 0) { return false; } return true; } Проверить этот код можно вот на таких примерах: console.log(test('text with([brackets])')); // true console.log(test('text with ([wrong brackets)]')); // false console.log(test('text with [wrong brackets')); // false А вот и рабочий пример на JSFiddle.

Ответ 3



Попробовал сам, вот что получилось: var input = document.querySelector('#input'), output = document.querySelector('#output'); input.addEventListener('keydown', update); input.addEventListener('keyup', update); input.addEventListener('change', update); function update () { var errorMessage; try { balanced.matches({source: input.value, open: ['{', '(', '['], close: ['}', ')', ']'], balance: true, exceptions: true}); } catch (error) { errorMessage = error.message; } input.style.border = '10px solid ' + (errorMessage ? 'red' : 'green'); output.innerHTML = errorMessage || ''; } update(); body { background: #333; font-family: arial; } #input { outline: none; } #output { color: grey; }



Особенности полиморфизма

#java #jvm #полиморфизм


Всем доброго времени суток.

Только начал готовиться к собеседованию на Java Junior`а, как произошло небольшое
недопонимание по поводу полиморфизма. Я изучал Java Core по книге Кэти Сьерра и Берта
Бейтса("Изучаем Java. 2-е издание"). 

Там механизм наследования (и вообще хранения объектов в куче JVM) представлялся вот так:

public class A{
//code...
}

public class B extends A{
//code...
}

public class TestApp{

public void init(){
B val = new B();
}

}


И в JVM это все выглядит таким образом:



Допустим, у нас есть такой код:

public class Animal{

public void makeSomthing(){
System.out.println("Animal"); 
} 

}


public class Dog extends Animal{

//переопределенный метод
@Override
public void makeSomthing(){
System.out.println("Dog");
} 

public void fMagic(){

this.makeSomthing(); //Console: Dog    
super.makeSomthing(); //Console: Animal [?]   

}

}


public class TestApp{

public static void main(String[] args){

Dog dogPet = new Dog();

dogPet.fMagic();

}

}


Выходит, что при вызове метода fMagic() у объекта dogPet так же вызывается метод
makeSomthing() у "внешнего" объекта Dog и еще этот же метод вызывается у "внутреннего"
объекта Animal(у суперкласса). Как я понял, по логике этой книги, конструкция переопределения(@Override)
методов заключается в том, что метод по сути один, а когда мы его переопределяем, то
как-бы изменяем его во "внутреннем" объекте c помощью "внешнего". А уже при вызове
dogPet.fMagic() он вызывается изнутри.



Но при этом:

класс Dog

   public void fMagic(){

    this.makeSomthing(); //Console: Dog
    super.makeSomthing(); //Console: Animal [?]

    //Console:  Dog@74a14482 -  адрес Dog. Dog@74a14482 - адрес Animal. 
    System.out.println("links:"+"\n" + this + " -  адрес Dog. "+ super.getObjectLink()
+ " - адрес Animal.");

}


класс Animal

 public Object getObjectLink(){ return this; }


Но самое странное на мой взгляд заключается вот в этом:
При сужении типа до его родителя, вызов функции дает "Dog", а не "Animal". Т.е в
данном случае, переопределение метода в классе Dog изменяет метод saySomthing(). А
вот в случае вызова метода fMagic() у класса Dog, вызываются 2 разные функции И переопределение
функции суперкласса, как я понимаю, ничего не дает. 

 Animal dogPet = new Dog();

 dogPet.makeSomthing(); //Console: Dog


Суть вопроса: Как же именно все эти процессы и механизмы ООП происходят на самом
деле? И почему же при вызове fMagic() на консоль выводится две разные надписи "Dog"
и "Animal", а не одна и та же надпись "Dog", как в случае с Animal dogPet = new Dog();?
    


Ответы

Ответ 1



Во-первых завязывайте с такой терминологией, нет никаких внешних и внутренних объектов. У вас есть класс Dog, который расширяет класс Animal. Наследование представляет собой отношение типа является(is a). Следовательно в Вашем случае объект Dog является объектом Animal, а значит содержит в себе его поведение. Поведение родительского класса может использоваться в подклассе при помощи ключевого слова super, что Вы и продемонстрировали. Ключевое слово this используется для получения объектом ссылки на самого себя, что в данном случае делается по-умолчанию. Т.е. Вы получите такой же результат если опустите его. Чтобы лучше понять преимущества полиморфизма разберите паттерн проектирования "Стратегия". На мой взгляд один из самых ярких примеров. Также если Вы пишете Animal dog = new Dog(); Вы говорите машине: "Создай мне объект Dog и помести его в переменную типа Animal". Вы можете это сделать, поскольку Dog является Animal. Однако обращаясь к этой переменной у Вас будет вызываться метод класса Dog поскольку в ней содержится объект Dog. Animal здесь - это тип переменной, а не объекта.

Запретить конструктор копирования и оператор присваивания

#cpp #конструктор


Если в базовом классе запретить конструктор копирования и оператор присваивания,
нужно ли в производных классах делать то же самое?
    


Ответы

Ответ 1



Это делать не обязательно. Например есть вспомогательный класс boost::non_copyable который используется чтобы запретить копирование. Однако, при попытке копирования в сообщении об ошибке будет написано только про boost::non_copyable, но не про класс-наследник, что затруднит понимание в каком именно месте произошла ошибка. Поэтому лучше запрещать копирование явно, в классе-наследнике. Рекомендуемый способ - это =delete; struct X { X(const X&) = delete; X& operator=(const X&) = delete; }; Если код компилируется для С++03, то конструктор и оператор присваивания надо объявить в private секции, и не определять. Тогда будет либо ошибка компиляции (из за private), либо ошибка линковки. struct X { private: X(const X&); // noncopyable X& operator=(const X&); // noncopyable };

Меню под Toolbar. Нет названия табов

#android #material_design #menu #android_toolbar


Пытаюсь сделать так - 



Java код

//Pager
    TabsViewPagerAdapter adapter = new TabsViewPagerAdapter(getSupportFragmentManager());
    adapter.addFragment(new Fragment1(), "Первый");
    adapter.addFragment(new Fragment2(), "Second");
    viewPager.setAdapter(adapter);

    //Set tabs
    tabLayout.setupWithViewPager(viewPager);


Так же вот вам мой класс -

public class PagerAdapterHelper extends FragmentPagerAdapter {
private final List mFragmentList = new ArrayList<>();
private final List mFragmentTitleList = new ArrayList<>();

public PagerAdapterHelper(FragmentManager manager) {
    super(manager);
}

@Override
public Fragment getItem(int position) {
    return mFragmentList.get(position);
}

@Override
public int getCount() {
    return mFragmentList.size();
}

public void addFragment(Fragment fragment, String title) {
    mFragmentList.add(fragment);
    mFragmentTitleList.add(title);
}


@Override
public CharSequence getPageTitle(int position) {
    switch (position) {
        case 0:
            return "ONE";
        case 1:
            return "TWO";
        default:
            return "WTF";
    }
}


}

После запуска Активити есть тулбар и поле под ним, но почему-то самих табов на нем
нет. Так же сами фрагменты спокойно отображаются/листаются. На табы можно тыкать, все
норм, только надписей нет(
    


Ответы

Ответ 1



Для этого применяются табы. Код разметки: Код добавления: Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); assert toolbar != null; setSupportActionBar(toolbar); viewPager = (ViewPager) findViewById(R.id.viewpager); tabLayout = (TabLayout) findViewById(R.id.tabs); TabsViewPagerAdapter adapter = new TabsViewPagerAdapter(getSupportFragmentManager()); adapter.addFragment(new Fragment1(), "ssss"); adapter.addFragment(new Fragment2(), "Second"); viewPager.setAdapter(adapter); viewPager.setAdapter(adapter); assert tabLayout != null; tabLayout.setupWithViewPager(viewPager); tabLayout.setupWithViewPager(viewPager); tabLayout.getTabAt(0).setText("1"); tabLayout.getTabAt(1).setText("2"); Код адаптера: public class TabsViewPagerAdapter extends FragmentPagerAdapter { private final List mFragmentList = new ArrayList<>(); private final List mFragmentTitleList = new ArrayList<>(); public TabsViewPagerAdapter(FragmentManager manager) { super(manager); } @Override public Fragment getItem(int position) { return mFragmentList.get(position); } @Override public int getCount() { return mFragmentList.size(); } public void addFragment(Fragment fragment, String title) { mFragmentList.add(fragment); mFragmentTitleList.add(title); } @Override public CharSequence getPageTitle(int position) { return mFragmentTitleList.get(position); } }

Ответ 2



build.gradle dependencies { compile 'com.android.support:design:23.1.1' } activity_pull_to_refresh.xml TabLayoutActivity.class public class TabLayoutActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_pull_to_refresh); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout); ViewPager viewPager = (ViewPager) findViewById(R.id.pager); if (toolbar != null) { setSupportActionBar(toolbar); } viewPager.setAdapter(new SectionPagerAdapter(getSupportFragmentManager())); tabLayout.setupWithViewPager(viewPager); } public class SectionPagerAdapter extends FragmentPagerAdapter { public SectionPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { switch (position) { case 0: return new FirstTabFragment(); case 1: default: return new SecondTabFragment(); } } @Override public int getCount() { return 2; } @Override public CharSequence getPageTitle(int position) { switch (position) { case 0: return "First Tab"; case 1: default: return "Second Tab"; } } } }

Java, типы данных

#java


int a = 'a';
int b = ('a' + 'b');


int объявляется как тип данных char, что означают эти строчки?
    


Ответы

Ответ 1



Смотрите. У вас переменные объявлены как int, а вот значение им присваивается с помощью констант типа char. В Java, в отличие от C++, char — 16-битный числовой беззнаковый тип* (в отличие от 8-битного знакового byte). При сложении char'ов, однако, происходит integer promotion: char'ы преобразуются к 32-битному типу int, и складываются. При этом, очевидно, переполнения не будет. Результат сложения есть тоже int, он-то и присваивается переменной b. *хотя его константы (литералы) задаются символами вида '\u1f2d', а не числами

Ответ 2



На самом деле char - целочисленный тип, аналог byte иногда беззнаковый. Его можно неявно привести в int (по коду символа) и сложить. Код не очень красивый и смущает тех кто пришёл из С++. UPD. Спасибо за уточнения, был не совсем прав, смотри ответ VladD.

Открыть файл Sketch на Windows

#photoshop


Ребят, как открыть sketch-формат на Windows? Есть программуля avocode, но там нужно
ставить доп. плагин, который на этой странице у меня выдает только версию для OS X.
    


Ответы

Ответ 1



Есть еще бесплатный сервис lunacy Он работает оффлайн тоже

Ответ 2



На данный момент мне известны три популярных решения - Avocode, Zeplin и Sympli. Лично работал только с Zeplin. Это веб-сервис (а с июня-июля 2016 - еще и webkit-based приложение, под windows), через который можно делиться работами в Sketch. Именно делиться, но не открывать sketch-файлы. Работает это так: Автор sketch-макетов, c OS X, регистрируется в Zeplin и добавляет туда макеты Другие люди могут теперь заходить в Zeplin в аккаунт к автору макетов и просматривать их Вероятно, вам нужно обратиться к автору макетов, с OS X на компьютере, и попросить его организовать вам доступ к его макетам в Zeplin (или аналогичном сервисе).

Ответ 3



Помимо выше перечисленных есть еще Figma, в котором можно импортировать .sketch файл и работать с ним. Тут еще упоминали Lunacy, разработчики которого заявляют, что добавили поддержку нового формата файла Sketch 43.

Странное поведение php

#php


Столкнулся с очень странным поведением PHP (хотя может быть дело и не в нем).
Скрипт не видит (или не имеет доступа) к файлам и каталогам, находящемся вне каталога,
в котором расположен сам скрипт. Данное поведение наблюдается только на сервере, на
локалке все работает как надо.  

Права на каталоги выставлял на разрешить все и всем, но не помогло.
Грешу на какие-то настройки PHP или Apache, но не знаю что именно смотреть.
Подскажите, куда копать?

Сервер - Debian 8
PHP версии 5.6.24.
    


Ответы

Ответ 1



Такое поведение связано с настройками безопасности. В данном случае это директива open_basedir Ограничивает указанным деревом каталогов файлы, которые могут быть доступны для PHP, включая сам файл.

Ответ 2



Хороший вопрос. И ответ на него будет полезен многим пользователям пхп. Любое странное поведение всегда сопровождается сообщениями об ошибках. поэтому надо настроить свой сервер так, чтобы он сообщал обо всех ошибках. для этого по возможности в php.ini или.htaccess, а на крайний случай - прямо в скрипте через ini_set задать следующие настройки: для сайта в режиме разработки error_reporting = -1 display_errors = 1 и смотреть ошибки прямо на экране для сайта в боевом режиме error_reporting = -1 display_errors = 0 log_errors = 1 и смотреть ошибки в логе ошибок веб-севрера После прочтения сообщения об ошибке необходимость писать в Спортлото с вопросом "Куда мне копать?" отпадает. Равно как отпадает и необходимость в услугах разнообразных гадателей и телепатов, пытающихся по косвенным признакам угадать одну из немногих известных им проблем.

Git откатить rebase [дубликат]

#git #git_rebase


        
             
                
                    
                        
                            This question already has an answer here:
                            
                        
                    
                
                        
                            Как вернуться (откатиться) к более раннему коммиту?
                                
                                    (1 ответ)
                                
                        
                                Закрыт 6 месяцев назад.
            
                    
Такая ситуация, что вместо merge сделал rebase. Получается изменения коряво слились,
как можно откатиться к моему локальному коммиту, до того как был сделан rebase и коммит ?
    


Ответы

Ответ 1



Ищите в рефлоге прошлый HEAD-коммит ветки, которую нужно восстановить к прошлому состоянию: $ git reflog # это просто пример, у вас будут другие id и строки 91e9b6e HEAD@{0}: rebase finished: returning to refs/heads/master 91e9b6e HEAD@{1}: rebase: checkout @{-1} a26257f HEAD@{2}: checkout: ... 91e9b6e HEAD@{3}: commit: ... ... Просто ищите коммит с тем сообщением, которое вам нужно. Он будет третьим в списке, если вы больше ничего не делали после ребейза. На всякий случай сделаем бэкап git branch backup Потом восстановим текущую ветку к найденному коммиту. Можно использовать как id, так и указатель HEAD@{номер} git reset --hard HEAD@{2} Если всё прошло удачно, можно удалять бэкап git branch -D backup Подробнее о git reset --hard: Как вернуться (откатиться) к более раннему коммиту?

Ответ 2



В дополнение к ответу выше. Чтобы не использовать git-reflog и не копировать хэши, поможет команда с откатом по времени, например: git reset --hard master@{"10 minutes ago"} или git reset --hard master@{12:30} также должны поддерживаться такие варианты: {yesterday}, {1 month 2 weeks 3 days 1 hour 1 second ago}, {1979-02-26 18:30:00} Если Вы примерно знаете, когда совершили лишнее действие, то можете откатиться с помощью данной команды.

Как запретить Dialog исчезать после нажатия за его пределами

#android #android_dialog


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

Как запретить Dialog исчезать после нажатия за его пределами?
    


Ответы

Ответ 1



То же самое из кода: dialog.setCanceledOnTouchOutside(false); Запретить закрывать диалог по кнопке Back: dialog.setCancelable(false);

Ответ 2



В стилях к Диалогу добавить пункт.

Требует return, а он находится в блоке if

#java #android


class SenderThread extends AsyncTask {
@Override
protected String doInBackground(String... params) {
    try{
        // Создаем сокет
        Socket socket=new Socket("192.168.0.102",6666);
        if(socket.getKeepAlive() == true) {
            // Получаем потоки ввод/вывода
            InputStream sin = socket.getInputStream();
            OutputStream sout = socket.getOutputStream();
            DataInputStream in = new DataInputStream(sin);
            DataOutputStream out = new DataOutputStream(sout);
            String line;
            out.writeUTF("getRandomNumber");
            out.flush();
            line = in.readUTF();
            return line.toString();
        }

}catch(Exception ex)
    {
        return ex.toString();
    }

  }// тут требует return
}


Мне нужно возвращать конкретно line или ex. Спасибо 
    


Ответы

Ответ 1



Прежде всего Вам нужно решить, что нужно делать с переменной, если не выполняется условие socket.getKeepAlive() == true. Если невыполнение этого условия является ошибкой, то Вам следует выбросить некоторый Exception: throw new Exception("Socket not alive!"); Или, если это не является ошибкой и Вам нужно вернуть просто какую-то дефолтную или пустую строку или null можете прописать в блоке else сделать return. Например: } else { return null; //or return ""; //or return "default String"; } Также, как уже было сказано предыдущим участником - если Вам нужно вернуть какой-то default-значение, то Вы можете инициализировать переменную ДО блока try.

Ответ 2



Инициализируйте свою переменную перед try String line = null; try { //line = ... } catch { } return line

Числа Фибоначчи

#java #алгоритм #математика



Что такое числа Фибоначчи?
Как найти первые n чисел Фибоначчи?

    


Ответы

Ответ 1



Определение чисел Фибоначчи Числа Фибоначчи это последовательность натуральных чисел, которая начинается с чисел ноль и один, а каждое следующее число равно сумме двух предыдущих: Первые 10 чисел Фибоначчи: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 Получение первых n чисел Фибоначчи Чтобы найти первые n чисел Фибоначчи, можно создать массив размера n, первые два элемента будут равны нулю и единице, а остальные элементы можно получить, используя цикл и вышеприведённую формулу: int[] f = new int[n]; f[0] = 0; f[1] = 1; for (int i = 2; i < n; ++i) { f[i] = f[i - 1] + f[i - 2]; } В коде предполагается существование переменной n, которую можно ввести с клавиатуры, например так: Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); После заполнения массива f полученные первые n чисел Фибоначчи можно вывести на экран с помощью цикла: for (int i = 0; i < n; ++i) { System.out.println(f[i]); } Онлайн пример кода Стоит заметить, что тип int в Java позволяет хранить только числа до 231-1, поэтому вышеприведённым способом получится вычислить только первые 46 чисел Фибоначчи (при попытке вычислить сорок седьмое число Фибоначчи произойдёт переполнение и получится отрицательное число). Используя тип данных long вместо int без переполнения получится вычислить первые 91 число Фибоначчи. Чтобы вычислять последующие числа Фибоначчи можно воспользоваться классом BigInteger, который реализует длинную арифметику в Java. Получения n-ого по счёту числа Фибоначчи Для получения только n-ого числа Фибоначчи не обязательно использовать массив, достаточно завести две переменных a и b, в которых будут храниться последние два числа Фибоначчи, и пересчитывать эти переменные n - 2 раза: int a = 0; int b = 1; for (int i = 2; i <= n; ++i) { int next = a + b; a = b; b = next; } System.out.println(b); Онлайн пример кода Рекурсивное вычисление чисел Фибоначчи Существует также рекурсивный способ вычисления чисел Фибоначчи. Однако его не рекомендуется использовать, потому что, в отличии от предыдущих двух способов, которые работают за линейное время от n, рекурсивный способ может работать значительно дольше. // функция, возвращающая n-ое число Фибоначчи public static int f(int n) { if (n == 0) { return 0; } else if (n == 1) { return 1; } else { return f(n - 1) + f(n - 2); } } Онлайн пример кода Рекурсивный способ работает за экспоненциальное время от n, например для n равного 46 рекурсивный способ работает дольше пяти секунд, а способ с запоминанием последних двух чисел Фибоначчи работает менее одной десятой секунды). Рекурсивный способ может работать долго, потому что в процессе вычисления функция будет много раз вызываться от одного и того же аргумента (например, при вычислении f(5) функция сделает рекурсивные вызовы к f(4) и f(3), оба рекурсивных вызова обратятся к f(2)), что приведёт к многократному повторению одних и тех же операций. Быстрое вычисление чисел Фибоначчи с помощью быстрого умножения матриц (используя O(log n) операций умножения) Рассмотрим матрицу: Используя матричное умножение, рекуррентное соотношение для последних двух чисел Фибоначчи может быть записано так: Расписывая это соотношение, получаем: Таким образом, чтобы найти n-ое число Фибоначчи достаточно возвести матрицу A в степень n - 1. Это можно сделать алгоритмом быстрого возведения в степень. // матричное умножение двух матриц размера 2 на 2 public static BigInteger[][] matrixMultiplication(BigInteger[][] a, BigInteger[][] b) { // [a00 * b00 + a01 * b10, a00 * b01 + a01 * b11] // [a10 * b00 + a11 * b10, a10 * b01 + a11 * b11] return new BigInteger[][]{ {a[0][0].multiply(b[0][0]).add(a[0][1].multiply(b[1][0])), a[0][0].multiply(b[0][1]).add(a[0][1].multiply(b[1][1]))}, {a[1][0].multiply(b[0][0]).add(a[1][1].multiply(b[1][0])), a[1][0].multiply(b[0][1]).add(a[1][1].multiply(b[1][1]))}, }; } // возведение матрицы размера 2 на 2 в степень n public static BigInteger[][] matrixPowerFast(BigInteger[][] a, int n) { if (n == 0) { // любая матрица в нулевой степени равна единичной матрице return new BigInteger[][]{ {BigInteger.ONE, BigInteger.ZERO}, {BigInteger.ZERO, BigInteger.ONE} }; } else if (n % 2 == 0) { // a ^ (2k) = (a ^ 2) ^ k return matrixPowerFast(matrixMultiplication(a, a), n / 2); } else { // a ^ (2k + 1) = (a) * (a ^ 2k) return matrixMultiplication(matrixPowerFast(a, n - 1), a); } } // функция, возвращающая n-ое число Фибоначчи public static BigInteger fibonacci(int n) { if (n == 0) { return BigInteger.ZERO; } BigInteger[][] a = { {BigInteger.ONE, BigInteger.ONE}, {BigInteger.ONE, BigInteger.ZERO} }; BigInteger[][] powerOfA = matrixPowerFast(a, n - 1); // nthFibonacci = powerOfA[0][0] * F_1 + powerOfA[0][0] * F_0 = powerOfA[0][0] * 1 + powerOfA[0][0] * 0 BigInteger nthFibonacci = powerOfA[0][0]; return nthFibonacci; } public static void main(String[] args) { System.out.println(fibonacci(1024)); } Онлайн пример кода

Помощь с Split С#

#c_sharp #split


У меня есть длинная строка, в которой есть переходы на новую строку, вопросительные,
восклицательные знаки, точки.
Мне нужно получить массив строк, которые будут делиться по правилу, 

String[] lines = myText.Split(new char[] { '\r', '\n', '.', '!', '?' }, StringSplitOptions.RemoveEmptyEntries);


Такое решение делит всё верно, но проблема в том, что оно удаляет знаки препинания.
Я хотел бы оставлять '.', '!', '?' вот эти знаки и удалять переходы на новую строку \r, \n.
Пример: 

Lorem ipsum, dolor sit amet, elit. Nullam! Faucibus congue?
Phasellus molestie, orci
Ut aliquam nulla tristique nec?
Nec bibendum tortor sodales!


Результат

1-Lorem ipsum, dolor sit amet, elit.
2-Nullam!
3-Faucibus congue?
4-Phasellus molestie, orci
5-Ut aliquam nulla tristique nec?
6-Nec bibendum tortor sodales!


Всем большое спасибо! Все ответы рабочие:)
    


Ответы

Ответ 1



Сначала подготавливаем текст, добавляя в знаки !?. \n. var prepair = myText.Replace(".",".\n").Replace("!","!\n").Replace("?","?\n"); String[] lines = prepair.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);

Ответ 2



Давайте разделим текст с помощью регулярки: string text = "Lorem ipsum, dolor sit amet, elit. Nullam! Faucibus congue?\r\nPhasellus molestie, orci\r\nUt aliquam nulla tristique nec?\r\nNec bibendum tortor sodales!"; string pattern = @"((?<=[.?!])|\r?\n) *"; foreach (string s in Regex.Split(text, pattern).Where(s => !string.IsNullOrWhiteSpace(s))) Console.WriteLine(s); Правда, придется удалить пустые строки вручную (я делаю это с помощью Where), так как в Regex.Split() нету аналога StringSplitOptions.RemoveEmptyEntries Здесь паттерн описывает формат разделителя: (?<=[.?!]) - положительный просмотр назад, т.е. ищем один из символов . или ? или !, но они сами в разделитель не входят, они войдут в часть перед разделителем \r?\n - перевод строки, поддерживает варианты как \r\n, так и просто \n | - "или", т.е. разделитель удовлетворяет или одному шаблону, или другому * - и любое число пробелов, они будут принадлежать разделителю и в результат не попадут

Создание новой БД в Oracle

#sql #oracle


Попытался вызвать CREATE DATABASE в Oracle и он меня послал:


  Error report - ORA-01501: CREATE DATABASE failed ORA-01100: database
  already mounted


Хотя в MS SQL это прокатывало. Полез гуглить и наткнулся на документацию.

Я правильно понимаю, что в Oracle на каждую БД нужно создавать свой экземпляр Oracle?

Немного не привычно после использования MS SQL Server, где можно много БД создавать
на 1 экземпляр.
    


Ответы

Ответ 1



Для целей логического разделения в Oracle служат "схемы" (фактически пользователи-владельцы). Для физического разделения служат табличные пространства. При этом логическое и физическое разделения действуют независимо, вы можете хранить все схемы в одном наборе файлов, а можете и одну разбить на несколько (например вынести архивные таблицы на боле медленные носители или отделить индексы от данных). При этом потребности создавать второй экземпляр на одной и той же машине обычно не возникает. Для каждого независимого проекта, если вы хотите отделить все его объекты, вместо create database выполняйте create user.

Ответ 2



Я правильно понимаю, что в Oracle на каждую БД нужно создавать свой экземпляр Oracle? Не правильно. На машине может существовать несколько экземпляров Oracle, каждый из которых уникально определяется парой: ORACLE_HOME и ORACLE_SID. В определённый промежуток времени один экземпляр может работать только с одной БД, которых может быть сколько угодно. ORA-01100: database already mounted Экземпляр уже смонтировал одну БД. Для создания новой выполните в командной строке: sqlplus / as sysdba В sqlplus: SQL> select name, open_mode from v$database; NAME OPEN_MODE --------- -------------------- MYDB READ WRITE SQL> shutdown immediate; SQL> startup nomount; SQL> select name, open_mode from v$database; ORA-01507: database not mounted Теперь можете создавать новую БД.

Ответ 3



В качестве дополнения к уже данным ответам стоит упомянуть об относительно новом (доступно, начиная с Oracle 12.1.0.1) виде БД - Pluggable DB (PDB). Т.е. в одном экземпляре БД (CDB - Container DB) может существовать много "pluggable" БД, которые будучи практически независимыми друг от друга совместно и экономно используют общие ресурсы - память, фоновые процессы и т.д. Такие "pluggable" DB можно легко переносить между разными CDB. Кроме того это сильно упрощает задачи администрирования.

Считается ли хорошим вариантом создавать объект внутри его класса?

#java #ооп #классы


Привет!  Я начал глубже разбираться в классах и их взаимодействии. 

Я решил создать маленькую программу, которая содержит:


класс test(который содержит метод main);
User(который содержит информацию о пользователе, геттеры и сеттеры для логина и "пароля"
для пользователя);
Menu(В этом классе пока существует один метод, который использует геттеры и сеттеры
класса User, задает ему имя и пароль, такая себе регистрация);


Класс User содержит в себе такой код: 

public class User {
    private String userName;
    private String password;

    public static User user = new User();

    public void setName(String name){
        userName = name;
    }

    public String getName(){
        return userName;
    }

    public void setPassword(String pass){
       password = pass;
    }

    public String getPassword(){
        return password;
    }

}


Когда я создавал обьект пользователя в классе Menu, в методе register, где после
этого и присваивал ему никнейм и пароль, я заметил, что я не смогу использовать этот
объект в других методах и классах, ибо чтобы обратится к нему и получить никнейм, я
должен был бы написать, к примеру в классе test: Menu.user.getName()  , но работать
это не будет.

Поэтому я создал объект в том же классе, где находятся его сеттеры и геттеры. Теперь,
если я хочу обратиться к объекту User, у которого название, к примеру, user

( User user = new User(); ) 

с любого уголка программы, я просто пишу User.user.setName("John");

Считается ли это хорошей практикой, создавать объект в его же классе, (потому-что
иначе я пока не знаю, как к нему обратится из другого метода или класса)? Если существует
правильная альтернатива, как она должна выглядеть?

Буду рад каждому совету, даже если он будет о моем ужасном коде или непонимании,
я приму каждый совет, я уважаю мнение каждого пользователя!

Upd.: тот единственный метод в классе Menu: 

public class Menu {

public static void register(){


    Scanner sc = new Scanner(System.in);

    do {
        System.out.println("Create your nickname:");
        User.user.setName(sc.nextLine());
    }while(User.user.getName().equals(""));

    do {
        System.out.println("Create your password:");
        User.user.setPassword(sc.nextLine());
    }while(User.user.getPassword().equals(""));
}


}
    


Ответы

Ответ 1



Краткий ответ на ваш вопрос - зависит от обстоятельств. В конкретно вашем случае - это очень плохая практика. Теперь детальнее. Строкой public static User user = new User(); вы создаете единый глобальный объект на всю систему. Обычно такие объекты обозначают некоторые константы, как, например, BigInteger.ONE или некоторые интерфейсные объекты. Т.е. объекты не хранящие свое внутреннее состояние, а выполняющие только какие-то действия. Но в любом случае, такие объекты создают с модификатором final, чтобы предотвратить возможность перезаписывания их в любом месте программы User.user = null; В вашем же случае нужно четко представлять область видимости объекта и предоставлять соответствующий уровень доступа. Если вы пишете public static void register(){ ......... User user = new User(); ......... } то такой объект будет виден (и существовать) только в этом методе. Может быть, вам нужно вернуть его из метода public static User register(){ ......... User user = new User(); ......... return user; } и тогда пусть вызывающая сторона заботится о его существовании. В том числе отдает всем заинтересованным в нем объектам. С учетом того, что метод register у вас статический, мне это видится самым адекватным решением. Еще есть вариант сделать этот объект статическим полем класса Menu (но зачем в меню пользователь для меня загадка) class Menu { private static User user; public static User getUser() { return user; } public static void register() { ......... User user = new User(); ......... } } в этом случае мы опять получаем единый глобальный объект, но уже без возможности его перезатирания (но по прежнему остается возможность его несанкционированной модификации) Также можно объявить метод register нестатическим. Тогда и объект будет нестатическим, а обычным полем класса со всеми возможностями первого способа. Но повторюсь - адекватность связи меню и пользователя у меня вызывает сомнения.

Ответ 2



Идеологически Menu вряд ли состоит из User, но скорее всего использует его для своей работы, то есть это зависимость. Зависимости лучше внедрять извне, тогда можно будет добавить ссылки на User в любой объект, который от него зависит. Пусть: public interface AbstractUser {...} public class StandardUser implements AbstractUser {...} public class SpecialUser implements AbstractUser {...} Внедрять зависимости можно через конструктор (когда Menu требует для своей работы User) public class Menu { public class Menu(AbstractUser user) { this.user = user; } private AbstractUser user; } ... var user = new SpecialUser(); var menu = new Menu(user); ... или через поле/сеттер (когда зависимость опциональна и/или существует подходящий умолчательный вариант). public class Menu { public class Menu() { this.user = new StandardUser(); } public void setUser(AbstractUser user) { this.user = user; } private AbstractUser user; } ... var menu = new Menu(); // uses StandardUser as default impl. var user = new SpecialUser(); menu.setUser(user); // switch to optional impl. ...

Laravel: сервис-контейнеры и сервис-провайдеры. Что это и зачем?

#php #laravel


Недавно перешел с фреймворка CodeIgniter (в котором была простая схема MVC) на изучение
Laravel. Фреймворк очень понравился, но есть некоторые моменты, которые я никак не
могу понять, сколько бы не читал документацию. В частности что такое сервис-контейнеры
и сервис-провайдеры и зачем они нужны. Прошу помочь разобраться.  
    


Ответы

Ответ 1



Ну что-ж, попробую объяснить. С Богом! Все возможности я не опишу, просто попытаюсь дать представление и возможно (скорее всего) не совсем точно. Введение: Вообще эти штуки нужны, в первую очередь, для удобства, как плюс — они реализуют паттерн Dependency Injection. С него и начнём. class myClassA { private $obj; function __construct() { $this->obj = new myClassB; } } Красиво?... Нет! Почему? А в друг нам понадобится, чтобы при создании класс myClassB принимал аргументы в свой конструктор? Придётся переписывать. Вы скажете: "перепишу, ничего страшного", но если таких классов myClassA много, то тут уже косяк — надо разруливать, для этого и придумали паттерн, глянем на то, как надо: function __construct(myClassB $classB) { $this->obj = $classB; } Т.е. мы в конструктор передали уже существующий класс myClassB, но где мы его создали? ведь new нигде не писали. Магия? Можно представить, что мы в Хогвартсе и зачитать заклинание "PHP Reflection" (но это уже отдельная тема). Так а Laravel что? Сложно описать, давайте покажем, переведем наш класс myClassA в контроллер: namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Http\Requests; use App\MyClass\MyClassB; class MyController extends Controller { private $obj; public function __construct(MyClassB $classB) { $this->obj = $classB; } public function index() { echo $this->obj->myMethod(); } } Но нужно теперь и MyClassB создать. Сразу вспомним начало, нам нужно учитывать что класс должен что-то принимать. Создаем папочку app\MyClass и там файлик MyClassB.php с текстом: action = $action; } public function myMethod() { return "Laravel - ".$this->action; } } Ну что? Запускаем? Не-не... надо ж как-то передать какой нибудь $action в конструктор. Плюс, вот тут уже справедливо сказать, что Laravel не понимает, что у нас с зависимостями (ведь класс myClassA зависит от myClassB). А мы только тупо создали файл и в нём класс, надо что-то ещё. Вот тут НАКОНЕЦ-ТАКИ мы переходим к Сервис-провайдеру, просим всемогущего Artisan создать нам новый провайдер: php artisan make:provider MyProvider Далее, во вторую вкладочку открываем документацию и заполняем его (а сам файлик должен быть тут - app\Providers): app->bind(MyClassB::class, function(){ return new MyClassB('MyAction'); }); } } Из документации видно, что внутри метода register() как раз и должны быть наши связывания, простенькие примеры: // Если хотим, чтобы каждый вызов, возвращался новый класс $this->app->bind(MyClassB::class, function(){ return new MyClassB('MyAction'); }); // Если хотим, чтобы был создан только один объект и всегда он возвращался $this->app->singleton(MyClassB::class, function(){ return new MyClassB('MyAction'); }); Стоит также одним глазком глянуть в документацию на строчку: Если вы откроете файл config/app.php, поставляемый с Laravel, то увидите массив providers. В нём перечислены все классы сервис-провайдеров, которые загружаются для вашего приложения. Наш MyProvider тоже должен быть в этом списке. Теперь можно запускать и, в принципе, всё должно работать. Теперь мы знаем, что MyProvider - это и есть Сервис-провайдер (внимательные заметили, что расширяет наш класс именно ServiceProvider. Совпадение?). Грубо говоря, это инструкция, которая создаст нам класс, чтобы другие классы могли им пользоваться (и в других местах). Вроде разобрались с Сервис-провайдерами. Абасаца... А теперь еще Сервис-контейнер. Продолжаем стори... Так а где был создан MyClassB? Так вот, можно сказать, что он был создан в Сервис-контейнере. Srsly? Можно сказать что Сервис-контейнер — это массив (array(key => value)), где ключ MyClassB::class, а значение это new MyClassB('MyAction'), и запись мы произвели с помощью метода bind. Но, на самом деле, помимо условного массива — это целый механизм, который позволяет делать такую магию в целом, вспоминаем наше заклинание из Хогвартса и зовется сие - Сервисом. Дочитали до конца? Бонусы: 1) Когда мы в app.php прописали провайдер, он будет автоматически создан и занесён в контейнер, а если он не так часто используется, зачем его каждый раз создавать? Для этого воспользуемся термином Отложенный-провайдер, для этого в нашем провайдере (мы-же теперь знаем, что это), нужно прописать protected $defer = true; тогда он будет создан только по запросу. 2) Мы можем и в коде обращаться к нашему контейнеру, например $getClass = $this->app->make('MyClassB'); (либо resolve('MyClassB');) (подробнее в документации) P.S. В конце хочу добавить, что критику принимаю :) Подправим, допилим, может в будущем кому пригодится.

Ответ 2



В кратце Сервис-контейнер - инструмент для управления зависимостями классов и внедрения зависимостей. Сервис-провайдеры - центральное место для конфигурирования. Вот пару постов: https://webzone.kz/publication/laravel-service-container https://webzone.kz/publication/laravel-service-providers