Страницы

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

четверг, 4 октября 2018 г.

Найти объём скопившейся после дождя воды на тропическом острове

Текст задачи:
Предположим, в один прекрасный день вы оказались на острове прямоугольный формы.
Ландшафт этого острова можно описать с помощью целочисленной матрицы размером MxN, каждый элемент которой задаёт высоту соответствующей области острова над уровнем моря.
К примеру, вот небольшой остров размером 3x3:
4 5 4 3 1 5 5 4 1
В сезон дождей остров полностью заливает водой и в низинах скапливается вода. Низиной будем считать такую область острова, клетки которой граничат с клетками, большими по высоте. При этом диагональные соседи не учитываются, а уровень моря принимается за 0. В приведённом выше примере на острове есть только одна низина — это клетка со значением 1 в середине острова (она граничит с клетками высотой 3, 5, 5 и 4).
Таким образом, после дождя высота клеток острова изменится и станет следующей:
4 5 4 3 3 5 5 4 1
Мы видим что в данном примере высота низины изменилась с 1 до 3, после чего вода начала переливаться на соседние клетки, а затем — в море. Общий объём воды, скопившейся на острове — 2 кубические клетки.
Вот пример посложнее:
5 3 4 5 6 2 1 4 3 1 1 4 8 5 4 3
После дождя карта острова принимает следующую форму:
5 3 4 5 6 3 3 4 3 3 3 4 8 5 4 3
Общий объём скопившейся после дождя воды на таком острове составляет целых 7 кубических клеток!
Ваша программа должна быть по одному из шаблонов ниже.
На вход функции подается массив массивов, на выходе ожиается int - значения общего объёма воды, скапливающейся на острове после сезона дождей для каждого из входных примеров Ограничения: Размер острова N и M — целые числа в диапазоне [1, 50] Высоты на острове могут принимать значения из диапазона [1, 1000]. Вот примеры входных данных:
4 5 4 3 1 5 5 4 1
5 3 4 5 6 2 1 4 3 1 1 4 8 5 4 3
2 2 2 2 1 2 2 1 2 2 1 2

Для приведённых выше данных, результат функции программы должен быть следующим:
2
7
0


Ответ

Возьмем две матрицы: исходную, обозначим ее I. И рабочую, такого же размера как исходная, но заполненную максимально возможным теоретическим значением уровня (я взял с запасом 10000), обозначим ее W. Далее обходим рекурсивно все поле, последовательно начиная с каждой крайней клетки острова. Рекурсивная функция на вход принимает координаты обрабатываемой клетки и текущий уровень воды. Если полученный текущий уровень ниже, чем изначальная высота клетки (берем из I) то принимаем текущий уровень равным высоте клетки. Таким образом мы получаем тот уровень, до которого может подняться вода у всех соседних клеток, если их высота ниже. В рабочей же матрице мы фиксируем минимальный уровень соседей, т.е. максимально возможный уровень для данной клетки. Напомню, изначально мы его приняли за 10000. Так вот, если уровень в рабочей матрице для клетки оказался выше, чем текущий уровень то принимаем его равным текущему. Таким образом мы понижаем уровень до минимально возможного при проходе через всех соседей. И еще одно важное правило: если текущий уровень оказался больше, чем уже зафиксированный в рабочей матрице то рекурсивный обход тут же прекращаем. Раз в W уровень ниже, значит мы уже приходили на эту клетку с клеток с более низким стоком и проверять дальше соседей уже нет смысла, мы там были и там максимум ниже.
Для ускорения работы можно обходить граничные клетки в порядке увеличения высоты. Тогда мы сходу зальем минимумами все доступные от них области. И при анализе от более высоких клеток повторно обходить эти области не будем.
Пример на perl
#!/usr/bin/perl use strict; use warnings;
my @I; # Исходная матрица my @W; # Рабочая матрица my ($MX,$MY); # Размеры матрицы while() { # Читаем исходую матрицу my @row=(); chomp; last if(!$_); push @row, $_ for split / +/; push @I, \@row; $MX=@row; $MY++; # Запоминаем размеры my @row2=(); # И заполняем начальными значениями рабочую push @row2,10000 for(1..$MX); push @W, \@row2; } $MX--; $MY--; # обходим все 4 стороны прямоугольника cell(0,$_,0) for(1..$MY); cell($MX,$_,0) for(1..$MY); cell($_,0,0) for(1..$MX); cell($_,$MY,0) for(1..$MX);
# Печать результирующей матрицы и расчет объема воды my $summ=0; my $y=0; for(@W) { $,=" "; print "@$_
"; for my $x(0..$MX) { $summ+=$W[$y][$x]-$I[$y][$x]; } $y++; }
print "RESULT = $summ
";
# Основная рабочая, рекурсивная функция sub cell { my($x, $y, $lev)=@_; return if($x<0 || $y<0 || $x>$MX || $y>$MY); # Проверяем выход за пределы поля return if($W[$y][$x]<=$lev); # Максимум клетки ниже или равен - мы тут были $lev=$I[$y][$x] if($lev < $I[$y][$x]); # Повышаем текущий уровень, если ниже изначального для клетки $W[$y][$x]=$lev; # Устанавливаем текущий максимум cell($x-1,$y,$lev); # И обходим всех 4х соседей рекурсивно cell($x+1,$y,$lev); cell($x,$y-1,$lev); cell($x,$y+1,$lev); }

Что такое __all__ в Python?

Объясните, пожалуйста, что такое __all__ (я так понимаю, это некий список), в каких случаях он используется в Python и как это применяется при импортировании? Читаю Бизли, но там как-то мудрёно написано и пример непонятный, я не понял, честно говоря. Гугление тоже особо не помогло...


Ответ

__all__ в Pythone - это список публичных объектов данного модуля. Т.е, допустим, у вас есть некий mymodule.py, в нем описано очень много объектов, и не требуется давать пользоваться ими всеми со стороны. В __all__ в mymodule.py вы списком определяете названия объектов, которые можно импортировать (__all__ = ["MyClass", "MyClass2"]). Т.е., например при from mymodule import * импортированы будут только те объекты, которые вы описали в __all__ Возможно, директиву __all__ правильно будет назвать одним из уровней инкапсуляции в Python.

Циклы и прочие штуки, взятые в { … }

Здравствуйте! Волнует такой вопрос. Есть в с++ такие вот скобки {}. Если в методе, в них объявить переменную как тут: void funct(){ int g=0; { int g=0; } } то компилятор не будет ругаться. Почему? Если объяснить на языке ассемблера то что произойдет? Произойдет вызов функции с передачей всех переменных доступных верхней функции в {}? если да, то как передадутся переменные, в стеке? Для чего вообще может быть допустима приведенная выше конструкция? И вот еще. Вот этот символ ";" означает конец операции, например int t=a+b;. А что он выполняет? почему его можно ставить так: void f(){ ; } или void f(){ }; и ошибки не будет? Что делает компьютер, когда натыкается на ;? Спасибо.


Ответ

{....} - это блок кода и он может быть вставлен везде, где можно вставить одиночную строку. Вас ведь не смущает код: if (....) doSmth(); и if (....) { doSmth(); } Но у этих скобок есть одна особенность - они объявляют новую область видимости. void funct(){ int g=0; { int g=0; // это другая переменная g, она имеет другой адрес! // предыдущая g не доступна по своему имени до закрывающей фигурной скобки. } // а здесь снова доступна первая переменная. } На уровне ассемблера это выглядит так funct(): push rbp mov rbp, rsp mov DWORD PTR [rbp-8], 0 ; первая g mov DWORD PTR [rbp-4], 0 ; вторая g pop rbp ret как передадутся переменные, в стеке? как обычно. Хотя никто не мешает компилятору проанализировать и сделать хорошо. Для чего вообще может быть допустима приведенная выше конструкция? например для любителей длинных функций, когда хочется добавить ещё сотню строк, а переменные (имена) закончились. Но если серьезно, то подобные конструкции используются постоянно - циклы, условия. Вот этот символ ";" означает конец операции, например int t=a+b;. А что он выполняет? он выполняет декоративную роль для программиста. Это синтаксический сахар. Но компилятор может пользоваться им в том случае, если в коде много ошибок, что бы хотя бы как то разделять операторы. Вот в Go точку с запятой можно пропускать, когда и так понятно, что она там должна быть. В ассемблерном коде она никак не отображается.

Как сделать закрытый веб-API для Андроид приложения

Как можно защитить свое API, чтобы никто не смог в обход приложения отправлять свои запросы на веб-сервис?
Допустим имеем:
1) Веб-сервис/API (к примеру написанный на PHP) по адресу myapi.com (адрес вымышленный)
2) Андроид приложение, которое общается с нашим веб-сервисом.
К примеру, наше приложение обращается к нашему API для получения информации, к примеру по адресу: http://myapi.com/?action=getnews&limit=5
При фильтрации трафика, можно увидеть по какому адресу приложение получает информацию, и соответственно можно самому слать запрос и читать всю информацию как угодно.
Мы можем посылать еще хэш сумму с солью которая известна только веб-сервису и приложению (md5("getnews5blablabla")), и веб-сервис будет ее проверять на валидность.
К примеру запрос стал таким: http://myapi.com/?action=getnews&limit=5&hash=efd46105a8915cb92df4641d86eb0505
Таким образом, даже узнав куда слать запросы, надо узнать еще саму соль, чтобы знать как генерируется хэш-сумма и отправлять валидные запросы.
Но с андроидом есть проблема получается, ведь любое приложение можно декомпилировать, и соответственно увидеть каким образом генерируется все запросы и вновь появится возможность подделывать их.


Ответ

Есть вариант завязать аутентификацию на in-app billing через Google Play. То есть делаем так: Публикуем свою прогу в Google Play и регистрируем там managed in-app item Юзер покупает данный item и при покупке пишем в developer payload наш случайный хэш (или ключ) сгенерированный аппой и/или веб сервером Далее перед коннектом с нашим веб API, аппа обязана получить хэш от сервера Google Play и с этим хэшем обратиться к сервису - иначе reject Естественно можно закэшировать хэш, чтобы каждый раз не бегать к Google Play и проч., но это уже детали. Общий смысл в том, что появляется доверенный источник между нашей аппой и веб сервисом, которому оба доверяют. Google Play в общем то подходит для этого, поскольку связка наше приложение - Google Play работает железобетонно и реализовано на уровне системного сервиса Android'а - другое приложение не сможет встроиться в эту связку (вернее можно, но очень и очень сложно)

Синтаксис замыканий в JS

Первый раз столкнувшись с замыканиями и не зная, что это такое, пробовал синтаксически понять, что происходит в коде вида: (function(){})(). Известно, что конструкция "()" - это вызов функции. Возникал вопрос по поводу первых круглых скобок
Позже, проникнувшись темой, вопрос первых круглых скобок меня волновать не перестал. Зачем они нужны, если без них всё работает?
При этом ни одного примера в статьях про замыкания без применения первых круглых скобок я не видел.
Классический пример замыкания в JavaScript:
buttons[i].onclick = (function(a){ return function(){ console.log(a);} })(i)
без первых скобок:
buttons[i].onclick = function(a){ return function(){ console.log(a);} }(i)
Зачем во всех примерах эти, получается лишние, синтаксические элементы?


Ответ

Ключевое слово function в js может употребляться в двух контекстах - это контекст объявления функции и контекст выражения, где это слово создает анонимную функцию.
Если строка начинается со слова function - то это объявление функции. С такой функцией нельзя ничего сразу же сделать (например, вызвать), кроме того, у нее должно быть имя.
function (a) { console.log(a) } (5) // Ошибка
Поэтому такую функцию во что-нибудь оборачивают:
+function (a) { console.log(a) } (5) // 5 !function (a) { console.log(a) } (5) // 5 ~function (a) { console.log(a) } (5) // 5 (function (a) { console.log(a) }) (5) // 5 (function (a) { console.log(a) } (5)) // 5
Если же слово function стоит не в начале строки - то ничего делать и не надо, все будет прекрасно работать:
var a = function (a) { return 5 } (5)

Неизвестная ошибка при создании собственной функции

Писал свою функцию для присвоения свойств к псевдоэлементам и заметил неведомую ошибку. Присваивание свойств идёт через добавления строк в styleSheet.
Когда в третьем случае вызываю функцию, почему то красится в синий первый элемент, хотя color для него я не ставил.
(function() { var setPseudoElement = function(parameters) { for (var element of parameters.elements.get()) { if (!element.pseudoElements) element.pseudoElements = { styleSheet: null, before: { index: null, properties: null }, after: { index: null, properties: null } }; var selector = (function() { if (element.id) { return '#' + element.id + '::' + parameters.pseudoElement; } else { var parentsList = $(element).parents().map(function() { return this.tagName.toLowerCase(); }).get().reverse().join(' > ') + ' > ' + element.tagName.toLowerCase(); var elementClass = element.classList.length ? '.' + $(element.classList).get().join('.') : ''; var elementAttributes = element.hasAttributes() ? $(element.attributes).get().map(function(className) { return className.nodeName !== 'class' ? className.nodeValue ? '[' + className.nodeName + '="' + className.nodeValue + '"]' : '[' + className.nodeName + '"]' : ''; }).join('') : ''; var elementNthChild = ':nth-child(' + ($(element).index() + 1) + ')'; return parentsList + elementClass + elementAttributes + elementNthChild + '::' + parameters.pseudoElement; }; })(); if (!element.pseudoElements.styleSheet) { if (document.styleSheets[0]) { element.pseudoElements.styleSheet = document.styleSheets[0]; } else { var styleSheet = document.createElement('style'); document.head.appendChild(styleSheet); element.pseudoElements.styleSheet = styleSheet.sheet; }; }; if (element.pseudoElements[parameters.pseudoElement].properties !== null && element.pseudoElements[parameters.pseudoElement].index !== null) { element.pseudoElements.styleSheet.deleteRule(element.pseudoElements[parameters.pseudoElement].index); }; if (typeof parameters.argument === 'object') { if (!element.pseudoElements[parameters.pseudoElement].properties && !element.pseudoElements[parameters.pseudoElement].index) { var newIndex = element.pseudoElements.styleSheet.rules.length || element.pseudoElements.styleSheet.cssRules.length || element.pseudoElements.styleSheet.length; element.pseudoElements[parameters.pseudoElement].index = newIndex; element.pseudoElements[parameters.pseudoElement].properties = parameters.argument; }; var properties = ''; for (var property in parameters.argument) { element.pseudoElements[parameters.pseudoElement].properties[property] = parameters.argument[property]; }; for (var property in element.pseudoElements[parameters.pseudoElement].properties) { properties += property + ': ' + element.pseudoElements[parameters.pseudoElement].properties[property] + ' !important; '; }; element.pseudoElements.styleSheet.addRule(selector, properties, element.pseudoElements[parameters.pseudoElement].index); } else if (parameters.argument !== undefined && parameters.property !== undefined) { } else if (parameters.argument !== undefined && parameters.property === undefined) { } else { console.error('Invalid values!'); return false; }; }; }; $.fn.cssBefore = function(argument, property) { setPseudoElement({ elements: this, pseudoElement: 'before', argument: argument, property: property }); }; })(); $(function() { // Случай 1 $('.el0').cssBefore({ 'content': '"Новый \'before\'"', 'color': 'green' }); // Случай 2 $('.el1').cssBefore({ 'content': '"Новый \'before\' №2"', 'color': 'blue' }); // Случай 3 $('.el0').cssBefore({ 'content': '"Новый \'before\' №3"' }); }); .element { width: 480px; margin: 0 auto; border: 2px solid red; } .element:before { content: "Старый 'before'"; color: orange; }


Почему в третьем случае красится в синий первый элемент? Как это исправить?

UPDATA:
Если выводить в консоль значения элементов после каждого присваивания, то выходят очень странные значения:
(function () { var i = 1; var setPseudoElement = function (parameters) { for (var element of parameters.elements.get()) { if (!element.pseudoElements) element.pseudoElements = {styleSheet: null, before: {index: null, properties: null}, after: {index: null, properties: null}}; var selector = (function () { if (element.id) { return '#' + element.id + '::' + parameters.pseudoElement; } else { var parentsList = $(element).parents().map(function () { return this.tagName.toLowerCase(); }).get().reverse().join(' > ') + ' > ' + element.tagName.toLowerCase(); var elementClass = element.classList.length ? '.' + $(element.classList).get().join('.') : ''; var elementAttributes = element.hasAttributes() ? $(element.attributes).get().map(function (className) { return className.nodeName !== 'class' ? className.nodeValue ? '[' + className.nodeName + '="' + className.nodeValue + '"]' : '[' + className.nodeName + '"]' : ''; }).join('') : ''; var elementNthChild = ':nth-child(' + ($(element).index() + 1) + ')'; return parentsList + elementClass + elementAttributes + elementNthChild + '::' + parameters.pseudoElement; }; })(); if (!element.pseudoElements.styleSheet) { if (document.styleSheets[0]) { element.pseudoElements.styleSheet = document.styleSheets[0]; } else { var styleSheet = document.createElement('style'); document.head.appendChild(styleSheet); element.pseudoElements.styleSheet = styleSheet.sheet; }; }; if (element.pseudoElements[parameters.pseudoElement].properties !== null && element.pseudoElements[parameters.pseudoElement].index !== null) { element.pseudoElements.styleSheet.deleteRule(element.pseudoElements[parameters.pseudoElement].index); }; if (typeof parameters.argument === 'object') { if (!element.pseudoElements[parameters.pseudoElement].properties && !element.pseudoElements[parameters.pseudoElement].index) { var newIndex = element.pseudoElements.styleSheet.rules.length || element.pseudoElements.styleSheet.cssRules.length || element.pseudoElements.styleSheet.length; element.pseudoElements[parameters.pseudoElement].index = newIndex; element.pseudoElements[parameters.pseudoElement].properties = parameters.argument; }; var properties = ''; for (var property in parameters.argument) { element.pseudoElements[parameters.pseudoElement].properties[property] = parameters.argument[property]; }; for (var property in element.pseudoElements[parameters.pseudoElement].properties) { properties += property + ': ' + element.pseudoElements[parameters.pseudoElement].properties[property] + ' !important; '; }; element.pseudoElements.styleSheet.addRule(selector, properties, element.pseudoElements[parameters.pseudoElement].index); console.log('Номер запуска: ' + Math.round(i / 2) + '; Номер присваивания элементу: ' + i); console.log({ 'Элемент 1': $('.el0:not(.el1)').get(0).pseudoElements, 'Элемент 2': $('.el0.el1').get(0).pseudoElements, 'Элемент 3': $('.el1:not(.el0)').get(0).pseudoElements }); i++; } else if (parameters.argument !== undefined && parameters.property !== undefined) { } else if (parameters.argument !== undefined && parameters.property === undefined) { } else { console.error('Invalid values!'); return false; }; }; }; $.fn.cssBefore = function (argument, property) { setPseudoElement ({ elements: this, pseudoElement: 'before', argument: argument, property: property }); }; })(); $(function() { // Случай 1 $('.el0').cssBefore({ 'content': '"Новый \'before\'"', 'color': 'green' }); // Случай 2 $('.el1').cssBefore({ 'content': '"Новый \'before\' №2"', 'color': 'blue' }); // Случай 3 $('.el0').cssBefore({ 'content': '"Новый \'before\' №3"' }); }); .element { width: 480px; margin: 0 auto; border: 2px solid red; } .element:before { content: "Старый 'before'"; color: orange; }

Если смотреть в консоль, то уже при первом вызове функции, элемент №1 имеет синий цвет и содержимое №3


Ответ

Думаю что я нашел проблему:
element.pseudoElements[parameters.pseudoElement].properties = parameters.argument;
где parameters.argument — это объект. Когда мы делаем первый проход, мы задаем его для первого и второго элемента. Когда на втором проходе мы меняем его для второго случая, он меняется и для первого тоже.
И вот пруф и решение
element.pseudoElements[parameters.pseudoElement].properties = Object.assign({}, parameters.argument);

Как работает код счетчика метрики?

Стало интересно как работает код счетчика метрики, но в JavaScript я не очень силен, знакомился с ним буквально по верхам.
(function(d, w, c) { (w[c] = w[c] || []).push(function() { try { w.yaCounterCOUNTER_ID = new Ya.Metrika({ id: COUNTER_ID, clickmap: true, trackLinks: true, accurateTrackBounce: true, webvisor: true }); } catch (e) {} }); var n = d.getElementsByTagName("script")[0], s = d.createElement("script"), f = function() { n.parentNode.insertBefore(s, n); }; s.type = "text/javascript"; s.async = true; s.src = "https://mc.yandex.ru/metrika/watch.js"; if (w.opera == "[object Opera]") { d.addEventListener("DOMContentLoaded", f, false); } else { f(); } })(document, window, "yandex_metrika_callbacks");
Не очень ясна конструкция в самом начале функции. Каким образом будет создан новый объект Ya.Metrika, если его фактически в коде нет, а сам скрипт watch.js подгружается в коде позже?
И как здесь все-таки работает добавление самого скрипта watch.js? Ведь если посмотреть код страницы с установленным счетчиком, тег script с параметрами и путем к watch.js не будет виден в коде страницы.
Заранее спасибо за объяснения!


Ответ

Отличный вопрос! Давайте по-порядку:
1. Объявление и вызов главной функции
(function(d, w, c) { ... })(document, window, "yandex_metrika_callbacks");
Здесь вы объявляете некую функцию, и сразу после объявления - ее же и вызываете с параметрами document, window и строковым ключом Яндекс.Метрики. Эти параметры используются внутри функции.
2. Сохранение конструктора метрики
w[c] = w[c] || []
w - это ваше окно браузера. В нем вы можете хранить функции или данные, и они будут доступны глобально в других скриптах. По сути, здесь вы обращаетесь к w["yandex_metrika_callbacks"], и там либо уже будут какие-то значения (например, с других счетчиков Яндекс.Метрики), либо объявленный вами пустой массив.
.push(function() { ... );
И далее в этот массив (уже существующий или только что созданный) вы добавляете элемент - функцию, которая попытается создать объект счетчика метрики.
w.yaCounterCOUNTER_ID = new Ya.Metrika({ .. });
Создаете объект снова у окна w, чтобы он был доступен в любых других скриптах.
3. Асинхронная загрузка скрипта метрики
n = d.getElementsByTagName("script")[0]
Здесь вы находите первый попавшийся у вас на сайте тег Documentation

Как проверить тип объекта во время выполнения программы на C#?

Как проверить тип объекта во время выполнения программы на C#?


Ответ

Оператор is языка C# проверяет является ли объект экземпляром типа или производного от него типа.
if (obj is MyObject) { }
Справка из MSDN: оператор is

Получение модуля числа без операции сравнения

Берем простой код: void main() { int x = abs(-1); } Собираем и дизассемблируем его: $ gcc sample.c -o sample && objdump -d ./sample Получаем листинг, где нет условной команды: 80483a1: e8 ee ff ff ff call 8048394 80483a6: 89 c2 mov %eax,%edx 80483a8: c1 fa 1f sar $0x1f,%edx 80483ab: 31 d0 xor %edx,%eax 80483ad: 29 d0 sub %edx,%eax Как на C/C++ получить абсолютное значение целого числа без операции сравнения?


Ответ

ассемблерная операция sar это обычный сдвиг вправо. Вот ваш код: int myabs(int x) { //mov %eax,%edx //sar $0x1f,%edx int minus_flag = x>>0x1F;//0x1F = 31
//xor %edx,%eax int y = minus_flag ^ x;
//sub %edx,%eax y -=minus_flag; return y; }

Как ведет себя static метод в многопоточном приложении?

Например тут: public class Singleton{
private static Cat cat = new Cat();
public static Cat getInstance(){
return cat; } } Почему такой вариант хуже (если хуже), чем использование не статического метода getInstance()? P.S. Цель вопроса выяснить, есть ли разница между использованием статического метода getInstance() и не статического, в ситуации когда к нему могут обращаться много потоков одновременно.


Ответ

Приведённый вариант лучше, чем вариант с нестатическим getInstance потому, что иначе никак. Если метод нестатический, то придётся создавать класс Singleton каждый раз. Кроме того, очевидно, что вы неправильно реализовали синглтон. Получается, что вы можете получать экземпляр класса Cat через Singleton, а можете просто создавать через new Cat сколько угодно, что будет неверно и вы никак не сможете от этого защититься. Поэтому надо делать public class Cat {
private static final Cat cat = new Cat();
public static Cat getInstance(){ return cat; } } С точки зрения многопоточности нет разницы между статическим и нестатическим методом, если он не помечен как synchronized. Приведённый выше вариант, как уже говорилось, имеет недостаток: создание экземпляра при подгрузке класса (часто при старте приложения). Чтобы избежать этой проблемы, можно использовать паттерн Initialization on Demand Holder idiom. public class Cat{ private Cat() { }
private static class LazyHolder { private static final Cat INSTANCE = new Cat(); }
public static final Cat getInstance() { return LazyHolder.INSTANCE; } } При таком раскладе достигается эффективная потокобезопасность и получена ленивая инициализация (lazy-load singleton). Однако, в большинстве случаев нет необходимости делать такую сложную конструкцию, а достаточно реализовать первым способом.

Что почитать по Java Spring? [закрыт]

Подскажите, что почитать по Spring Framework? Интересует именно ПРАКТИЧЕСКОЕ руководство со множеством примеров, которые можно набрать и прощупать (язык русский/английский).


Ответ

"Spring in Action", 2 ed. - по второму спрингу, достаточно известная и хорошая книга. 3-е издание, посвященное 3-й версии, на мой взгляд, не особо - объем полезного текста уменьшился. Ревьюеры на амазоне отмечают то же самое. Поэтому в свое время заказал "Spring Recipes: A Problem-Solution Approach" - очень большая, много примеров (собственно, в этом и суть книги). Понравилась (хотя лично для меня были минусом примеры интеграции Spring Web Flow с JSF 1.2, когда уже 2.0 в ходу).

Вывод числа double (10^18)+1

Увидев этот код #include #include using namespace std; int main() { double d = 1000000000000000001; cout.setf(ios::fixed); cout.precision(0); //0 - число символов после точки cout << d << endl; printf("%.0lf
",d); return 0; } Неожиданно увидел в результате (http://ideone.com/1SEHpO) 1000000000000000000 1000000000000000000 Куда делась 1? Из за чего так происходит? Особенности записи типов с плавающей точкой?


Ответ

У типа double ограниченная точность, поэтому в нём невозможно различить 1000000000000000000 и 1000000000000000001. Если вы объявите double d1 = 1000000000000000001; double d2 = 1000000000000000000; -- то d1 и d2 будут одним и тем же числом. Пруф: http://ideone.com/WqQSAd Проблема в том, что числа с плавающей точкой не бесконечно точны. Для типа double, например, выделяется 52 бита под значащие цифры (и ещё 11 бит под показатель степени), число внутри хранится как бы закодированным в виде CCCCCCC * 2^PPPP (C -- значащие цифры, P -- степень). А значит, числа, которые можно представить в виде double, расположены с некоторым шагом (который зависит от величины порядка): числа, расположенные "между" представимыми числами выразить точно с помощью double вообще нельзя, и они автоматически округляются до ближайшего представимого числа. Пример такого числа: 0.1: оно не выражается (двоичной) дробью, и константа 0.1 внутри хранится как приблизительно 0.1000000000000000055511151231257827021181583404541015625 Максимальное значение, которое можно прибавить к единице так, чтобы она не изменилась, называется машинным эпсилоном. Для типа double машинный эпсилон равен, очевидно, 2^-53, то есть около 1.11e-16 Почему очевидно? Потому что для единицы значащие биты такие: 10000000...000, а значит, следующее по величине число, которое можно выразить типом double, должно иметь значащие цифры 10000000...001. (На самом деле чуть-чуть сложнее: ведущая единица не хранится, а подразумевается.) Отсюда выплывает, что 1 + 1e-16 для типа double неотличимо от 1. Поскольку для бóльших чисел увеличивается порядок, при увеличении первого слагаемого машинный эпсилон приблизительно пропорционально увеличивается. Соответственно, 1e16 + 1 будет равно 1e16. В вашем же случае вы на два порядка выше предела: вы прибавляете к 1e18. Давайте ещё проэкспериментируем: http://ideone.com/4XJxFj 1 + 1.110223024625156e-16 == 1 но уже 1 + 1.110223024625157e-16 != 1 Это потому, что 1.110223024625156e-16 -- приближение к 2^-53. Ещё немного информации о числах с плавающей точкой: Хорошая статья на Хабре Классическая статья с теоретическими выкладками, но на английском. Если вам нужно представлять числа с высокой точностью, даже типа long double может не хватить. В этом случае, возможно, придётся применять числа бесконечной точности. Такие числа являются встроенными в некоторых языках (например, Java и C#), а для C и C++ есть хорошие библиотеки, предоставляющие такие числа. Я бы порекомендовал GMP

Запрос SQL на удаление дубликатов из таблицы по одному полю

Есть таблица с дубликатами в MySQL: (по полю name) id | name | surname -------------------- 1 | niko | surname 2 | niko | surname 3 | jane | surname 4 | jane | surname 5 | ivan | surname Необходимо получить таблицу такого вида id | name | surname -------------------- 1 | niko | surname 3 | jane | surname 5 | ivan | surname


Ответ

Запрос для результирующей таблицы: SELECT min(id), name, surname FROM `table` GROUP BY name, surname Для удаления дубликатов подойдет такой прием: CREATE TEMPORARY TABLE `t_temp` as ( SELECT min(id) as id FROM `table` GROUP BY name, surname );
DELETE from `table` WHERE `table`.id not in ( SELECT id FROM t_temp ); Есть конечно нюансы...

Чем class отличается от struct?

Чем class отличается от struct? Когда использовать одно, а когда другое?


Ответ

Отличия
В С++ классом называются типы объявленные с помощью class, struct или union
Это означает что в С++ есть только классы, и все правила для class и struct одинаковы, за исключением случаев где отличия указаны явно.
Отличий class от struct всего два
Member access control [class.access] Члены класса, определенного с помощью ключевого слова class, по умолчанию являются private. Члены класса, определенного с помощью ключевого слова struct или union, по умолчанию являются public Accessibility of base classes and base class members [class.access.base] При отсутствии спецификатора доступа (т.е. private/protected/public) у базового класса, базовый класс будет public если класс определен с помощью struct и private если класс определен с помощью class
(Хотя union и является классом, он имеет много других отличий от class и struct, что выходит за рамки этого вопроса.)
Использование
Есть популярное мнение, что для "расово правильных ООП классов" надо использовать только class, а для структур данных - только struct, и еще у struct не должно быть методов. Это не более чем вкусовщина, и подобные вещи должны быть закреплены в руководствах по стилю кодирования, как например это сделано в Google C++ Style Guide
В коротких примерах кода, предпочтительнее использовать struct, и не использовать private/public, если они не относятся к сути проблемы.

CharSequence или String?

Подскажите, в чем принципиальное отличие между этими объектами? В каких случаях оптимально использовать CharSequence?


Ответ

CharSequence это интерфейс со всеми вытекающими. Под капотом может быть CharBuffer, Segment, String, StringBuffer, StringBuilder. Или собственная реализация.
Чтобы было понимание приведу следующий пример:
public class Main {
public static void main(String[] args) { String str = new String("Hello from String"); soutString(str); }
public static void soutString(String str) { System.out.println(str.getClass()); System.out.println(str); } }
Метод SoutString выводит класс и содержимое строки:
class java.lang.String Hello from String
Если мы захотим использовать StringBuilder, то для того что бы воспользоваться методом SoutString мы должны использовать преобразование. Так как он ожидает String
StringBuilder sb = new StringBuilder("Hello from StringBuilder"); soutString(sb.toString());
Добавляем эти строки и смотрим результат:
class java.lang.String Hello from String class java.lang.String Hello from StringBuilder
Мы так же знаем, что String и StringBuilder реализуют интерфейс 'CharSequence' и это позволяет нам написать следующее:
public class Main {
public static void main(String[] args) { CharSequence str = new String("Hello from String"); soutCharSequence(str); CharSequence sb = new StringBuilder("Hello from StringBuilder"); soutCharSequence(sb); }
public static void soutCharSequence(CharSequence ch) { System.out.println(ch.getClass()); System.out.println(ch); } }
Вывод будет следующим:
class java.lang.String Hello from String class java.lang.StringBuilder Hello from StringBuilder
Отметим тот факт, что во втором случае в метод был передан StringBuilder
Мы можем передавать в наш метод любые классы, которые реализуют интерфейс. Внутри метода можно использовать методы интерфейса, например length();
А еще мы можем внутри метода безопасно выполнить специфические для объекта действия:
if (ch instanceof String) { System.out.println(((String) ch).toUpperCase()); }
Я не знаток Android, но думаю, что @Barmaley хотел сказать что если передается в качестве CharSequence объект String, то будет выводится просто текст. А если объект дополнительно реализует Spannable, то его еще можно и раскрасить.

Как сделать запрет на повтор?

Проблема такая, если занесли запись через запрос 'INSERT INTO' в таблицу, и второй раз допустим случайно с таким же названиям, то данные не добавляются и это хорошо, НО сам 'id' увеличивается в значении, каждой раз на одиницю, если совпадают названия , что в моем случаи мне не подходит , возможно ли как-то это решить ?
Параметры таблицы
CREATE TABLE "content" ( "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE, "title" TEXT NOT NULL, "category" INTEGER NOT NULL, "directians" TEXT NOT NULL, "time" INTEGER, "img" TEXT, "autor" TEXT, "datetime" DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE ("title") ON CONFLICT REPLACE)


Ответ

Если значение ID увеличивается на единицу, то значит что данные, на самом деле, добавляются, а если быть точнее, то вновь добавляемые данные заменяют предыдущие значения. Об этом поведении говорит строка: UNIQUE ("title") ON CONFLICT REPLACE
А для того, чтобы запретить добавление одинаковых данных и соответственно увеличения ID на единицу, нужно просто заменить поведение при конфликтных случаях с этого:
UNIQUE ("title") ON CONFLICT REPLACE
на вот это:
UNIQUE ("title") ON CONFLICT IGNORE
Таким образом, вновь добавляемые данные будут игнорироваться и добавление не сработает.

Java. Конструктор, который использует сеттер - когда это нужно?

Встретил такую конструкцию в обучающем примере.
public class Vehicle { private String color;
//Constructor Vehicle(String c) { this.setColor(c); }
// Setter public void setColor(String c) { this.color = c; } }
Насколько я понимаю, сеттер используют чтобы задать значение приватной переменной, на что способен и конструктор. Зачем использовать конструктор, который использует сеттер, который присвоит значение переменной, если можно обойтись конструктором? Бывают случаи когда это необходимо, или это просто теоритический пример что так можно?


Ответ

Сеттер не всегда просто присваивает значение переменной, чаще всего он ещё выполняет какие-то действия(нормализует данные, например), поэтому чтобы не дублировать код из сеттера в конструкторе - можно просто вызывать сеттер из конструктора.

Как узнать о поддержке браузером CSS свойства?

Хочу сделать сайт, который будет корректно выглядеть в большинстве браузеров. Но на пути к созданию столкнулся с проблемой кроссбраузерности. То есть, один браузер поддерживает данное CSS, а другой — нет.
Как я могу знать, поддерживает ли данный браузер указанное CSS свойство? Можно ли это узнать на одном CSS?


Ответ

С помощью одного CSS
Узнать, поддерживает ли данный браузер указанное CSS свойство, можно через CSS директиву под названием @supports
Эта директива работает так же, как и @media.
/* Узнаём, поддерживает ли браузер display: flex; */ @supports (display: flex) { /* Стили */ }
Так же можно установить свойства при условии, если браузер не поддерживает указанное CSS свойство
/* Узнаём, поддерживает ли браузер display: flex; */ @supports not (display: flex) { /* Стили */ }
Ещё можно проверить несколько свойств сразу, используя оператор and
/* Узнаём, поддерживает ли браузер display: flex; и flex-wrap: wrap; */ @supports (display: flex) and (flex-wrap: wrap) { /* Стили */ }
А если нам нужно хотя бы одно рабочее свойство, можно использовать оператор or
/* Узнаём, поддерживает ли браузер display: flex; */ @supports (display: flex) or (display: -webkit-flex) { /* Стили */ }
Но нужно учесть, что данная директива новая и в IE вообще не работает.
Так же, для обеспечения, какой никакой, кроссбраузерности, можете использовать вендорные префиксы

С помощью JS
Данную задачу, с помощью JS, я знаю, как решить двумя способами:
Использовать аналог CSS @Supports только на JS — функцию CSS.supports()
// Узнаём, поддерживает ли браузер display: flex; CSS.supports("display", "flex"); // true/false
Так же, как и в CSS, можно указать несколько свойств.
// Узнаём, поддерживает ли браузер display: flex; и flex-wrap: wrap; CSS.supports("( display: flex ) and ( flex-wrap: wrap )"); // true/false
Но так же, как и в CSS, этот метод является новым и не будет работать в IE вообще. Проверить с помощью применения стилей через JS.
Суть этого метода в том, что браузер не может установить свойству элемента значение, которое не поддерживает. Таким образом, если, после применения нового значения свойству через JavaScript, оно не изменилось, то браузер не поддерживает данное значение.
В итоге у нас выходит следующая функция:
var SupportsCSS = function (property, value) { try { // Создаём новый элемент var element = document.createElement('span'); // Проверяем, есть ли такое свойство в браузере if (element.style[property] !== undefined) element.style[property] = value; // Если есть, то присваиваем else return false; // Если нет, то false
// Если браузер поддерживает данное значение для указанного свойства, то значения будут равны return element.style[property] === value; } catch (e) { // В случае со старым IE, при присваивании значения, которое не поддерживается, вылетает ошибка return false; } };
И вот так это работает:
var SupportsCSS = function (property, value) { try { var element = document.createElement('span'); if (element.style[property] !== undefined) element.style[property] = value; else return false; return element.style[property] === value; } catch (e) { return false; } }; // Проверяем console.log( SupportsCSS('display', 'flex') ); console.log( SupportsCSS('display', '-webkit-box') ); console.log( SupportsCSS('display', 'Lol :)') ); console.log( SupportsCSS('flex-wrap', 'wrap') ); console.log( SupportsCSS('-webkit-flex-wrap', 'nowrap') );
Примечание: Если вы проверяете поддержку свойства в старом браузере, через эмулятор современного браузера, то данный метод будем показывать true на значениях, которые не поддерживаются.
Преимущество этого метода в том, что он будет работать во всех браузерах.
Пример запуска скрипта в Safari 5.17:

Специальные сервисы
Чтобы не заморачиваться, поддержу можно посмотреть на специальных сайтах. К примеру, один из самых популярных сайтов — http://caniuse.com/

Подробнее можно прочитать здесь: https://habrahabr.ru/post/336466/

Фабричный метод и абстрактная фабрика

Помогите разобраться.
Чем отличаются данные шаблоны? Когда лучше применять первый, а когда второй?


Ответ

Фабричный метод: есть некий класс, который выполняет свою специфическую функцию. Часть своей функциональности он делегирует внешнему интерфейсу, который инстанцируется через виртуальный метод этого класса. Наследники этого класса, перекрыв этот метод, могут вернуть другие реализации интерфейса, используемого основным алгоритмом класса. Абстрактная фабрика: класс / интерфейс, не содержащий собственной логики. Все его методы возвращают экземпляры других интерфейсов и вызываются внешними компонентами. Этот паттерн позволяет, подменив реализацию одного интерфейса, подменить набор реализаций ограниченного множества интерфейсов. Абстрактная фабрика применяется, когда требуется создать семейство интерфейсов, реализация которых должна подменяться совместно. Например, при доступе к данным есть стандартный интерфейс, отвечающий за подключение, - IDbConnection, и мой интерфейс, ответственный за преобразование объектной модели запроса в текст запроса, соответствующий стандарту определённой СУБД. Оба этих интерфейса инстанцируются одной фабрикой. В то же время, интерфейс IDbConnection объявляет метод CreateCommand, который возвращает реализацию IDbCommand для соответствующего типа подключения. Это - фабричный метод.

Интерфейс, не содержащий ни одного члена

Возможен ли интерфейс, не содержащий ни одного члена, и если да, какой практический смысл от такого интерфейса?


Ответ

Да, возможен. Такие интерфейсы называют маркерными. Они нужны для индикации чего-либо JVM, компилятору или какой-либо библиотеке. Пустые они потому, что позволяют добавить некоторый признак/маркер/индикацию к типам, не меняя контракты этих типов.
В Джаве такими интерфейсами являются, например, Serializable и Cloneable. Существование Serializable позволяет сделать проверку "можно ли сериализовать этот объект" более типизированным образом, сведя ее к проверке "имплементирует ли этот объект интерфейс Serializable".
Заменой маркерным интерфейсам также могут служить аннотации (например, @ThreadSafe).
Интерфейс-маркер на Википедии.

Окружность с градиентом

Как создать такую окружность, как на рисунке? На рисунке есть ещё задний фон. Можно нарисовать круг с градиентом, и с помощью :before закрыть внутреннюю часть по периметру, но как тогда показать задний фон через :before?


Ответ

Используя пример ответа @Максим Ленский, сгенерированный генератором, можно сделать читабельный и понятный вариант:

Случайные числа

Как на языке Java получить случайное число?


Ответ

import java.util.Random;
// Инициализируем генератор Random rnd = new Random(System.currentTimeMillis()); // Получаем случайное число в диапазоне от min до max (включительно) int number = min + rnd.nextInt(max - min + 1); Функция rnd.nextInt(limit) возвращает число от нуля (включительно) до limit (не включая limit).

Многоязычность Интернет страницы/сайта

Стало интересно как можно реализовать многоязычность Интернет страницы/сайта, "погуглил" некоторое время, но на толковое разъяснение что да как не наткнулся... Не могли бы Вы товарищи ткнуть носом в строну куда надо копать?


Ответ

Нужно сделать файл, содержащий объявление констант, в которых будут строки для вывода в разных местах сайта. Например (приводил уже где то)... Главный файл: //объявляем константу содержащую путь до файлов языков define('LANGAGE_DIR', $_SERVER['DOCUMENT_ROOT']."/language/", false); //тоже, путь до шаблона вывода define('TEMPLATE_DIR', $_SERVER['DOCUMENT_ROOT']."/template/", false);
//получаем переменную языка $language = $_GET['lang']; //не обязательно получать переменную гет-ом //можно брать ее откуда угодно, например - из базы данных, или из сессии
//загружаем файл перевода include_once(LANGUAGE_DIR . $language . '.php');
//загружаем файл шаблона, начинаем вывод include_once(TEMPLATE_DIR . 'default.php');
?> Файл русского языка: Файл английского языка: Файл шаблона: <?=LANG_TITLE?>

Просто нужно поместить в $language имя файла языка, для удобства без расширения. Следует еще предусмотреть вывод страницы на дефолтном языке, если в $language ничего не присвоено. Вот, такова идея. Если что не ясно, пишите! Удачного дня :)

Как правильно использовать исключения

Преимущественно всегда думал, что бывает не лишним на каждый тип исключения выводить соответствующее сообщение об ошибке. Речь идет о ситуациях, когда ничего кроме сообщения в блоке catch делать не зачем, т.е. можно было бы просто использовать общий вариант:
catch (Exception ex) { // <сообщение> }
а не
catch (DivideByZeroException) { // <сообщение про одно> } catch (FormatException) { // <сообщение про другое> } catch (ArithmeticException) { // <сообщение про третье> } catch (Exception ex) { // <сообщение> }
Но как-то несколько раз попадались на глаза утверждения типа "когда нет особо критичных целей, то отлавливать много исключений без нужды это плохой тон, безосновательное занятие и все в этом духе". Вроде как это "антипаттерн". Пользователю не важно, что там за ошибка, главное вывести сообщение, что, грубо говоря, функция не выполнилась, а по какой причине - его не касается.
В статьях с противоположным мнением наоборот утверждали, что пользователь должен знать, что случилось, по какой причине что-то пошло не так.
Так как поступать с исключениями в таких ситуациях? Определять "на глаз" в каком месте обязательно нужно уведомлять о возможных причинах ошибки, а в каком достаточно общего сообщения? Или есть какие-то уже сформулированные критерии по этому поводу? Или по сути вообще может без разницы, и все эти рассуждения не имеют значения?


Ответ

Вопрос конечно очень холиварный =) но тем не менее, поделюсь своими представлениями, ни в коей мере не претендуя на абсолютную истину.
Любая программа, работающая в реальных условиях и окружении с участием пользователя или без, способна генерировать массу исключений по разным причинам. Исключение составляют учебно-олимпиадные программы, которые работают в "идеальных" условиях, т.е. входные данные жестко регламентированы и ошибка пользователя исключена условиями задачи.
У каждого исключения может быть несколько причин для появления:
Ошибка пользователя при вводе данных тем или иным способом. Исключения возникшие по этой причине ловить необходимо, чтобы сообщить пользователю о его ошибке и дать возможность повторить ввод данных или некоторый набор действий для продолжения работы программы. Ошибка возникшая по вине среды окружения, например операционной системы или другой программы или библиотеки с которой вам приходится взаимодействовать. Такие исключения, в среднем, ловить противопоказано, т.к. единственное что можно сделать в таком случае, это попытаться корректно завершить работу, однако даже это может привести к непредсказуемым последствиям и порче данных пользователя, что вряд ли обрадует последнего. Однако, если вы уверены что ошибка, вызвавшая исключение, безвредна для данных или само исключение несет сугубо информативный характер, как, например, исключения при попытке установить сетевое соединение или при работе с файлами, то такое исключение может быть поймано и обработано. Ошибка возникшая по вине самой программы или ее части, например "любимый" всеми NullReferenceException. Исключения подобного рода необходимы на этапе отладки. Ловить их в коде никакого смысла нет, т.к. в процессе отладки, в идеале, все места кода, где могут возникнуть исключения по вине программы, должны быть исправлены. Как временная мера, можно и поймать, но тут есть большой риск что эта временная мера так и останется навсегда костылем в коде.
В целом, исключение генерируется тогда, когда исполняемый код не знает что делать в возникшей ошибкой.
Я для себя вывел 3 простых правила по обработке исключений:
Если можно исправить код так, чтобы исключение не возникало - исправляем код. Если не знаешь что делать с ошибкой которая стала причиной исключения, не лови его и дай программе упасть. Если уверен что знаешь что делать с ошибкой, ловим, заносим в логи, исправляем ошибку и бежим дальше либо падаем, тут уж по обстоятельствам.

Зачем нужен фабричный метод?

Допустим есть вот такая реализация фабричного метода:
abstract class Creator { public abstract Product FactoryMethod(); }
class ConcreteCreatorA : Creator { public override Product FactoryMethod() { return new ConcreteProductA(); } }
abstract class Product {}
class ConcreteProductA : Product {}
Какая выгода нам от создания объекта через Creator, если точно так же можно его создать через new? Когда нужно использовать именно фабричный метод, и какое преимущество нам это может дать?


Ответ

Выгод может быть много. Некоторые:
Вы можете дать имя вашему конструктору. Например:
Point PointCreator.FromPolar(double r, double phi)
PointCreator.FromPolar читается намного лучше, чем new Point(1, 0) Раз уж вы даёте имя, вы можете иметь несколько конструкторов с одинаковыми сигнатурами:
Point PointCreator.FromPolar(double r, double phi) { ... } Point PointCreator.FromCartesian(double x, double y) { ... }
или например
DateTime DateTime.FromSeconds(double seconds) { ... } DateTime DateTime.FromMilliseconds(double ms) { ... } Вы можете создавать объекты не данного типа, а любого производного, причём конкретный тип может быть скрыт внутри фабрики (так что у вашего остального кода не будет зависимости от этого конкретного типа). Вы можете сделать дополнительные действия после окончательного построения объекта. Например, вы можете зарегистрировать объект в списке всех активных объектов. С конструктором такое не очень удобно, т. к. вам придётся делать это либо в конструкторе базового класса, и выкладывать ссылку на недоконструированный объект (что может привести к понятным проблемам, если кто-то в этот момент обратится к объекту), либо дублировать код во всех потомках (что не всегда возможно, и непроверяемо, так что провоцирует баги).
Или вы можете сделать дополнительную инициализацию свойств объекта, если вам это нужно:
WebRequest InitWebRequest(string uri) { var request = WebRequest.Create(uri); request.Credentials = new NetworkCredential(Settings.Login, Settings.Password); return request; } Вы не можете сделать конструктор асинхронным, а фабричный метод — можете. В самом фабричном методе вы можете вызвать конструктор и async-метод для инициализации.
async SerialDevice Create(PortInfo portInfo) { var device = new SerialDevice(portInfo); await device.Connect(); return device; }

Что раньше инициализируется поля класса или конструктор?

Читая книгу Эккеля, натолкнулся на один момент, который не могу понять. Представлен следующий код:
import static net.mindview.util.Print.*;
class Insect { private int i = 9; protected int j; Insect() { print("i = " + i + ", j = " + j); j = 39; } private static int x1 = printInit("static Insect.x1 initialized"); static int printInit(String s) { print(s); return 47; } }
public class Beetle extends Insect { private int k = printInit("Beetle.k initialized"); public Beetle() { print("k = " + k); print("j = " + j); } private static int x2 = printInit("static Beetle.x2 initialized"); public static void main(String[] args) { print("Beetle constructor"); Beetle b = new Beetle(); } }
OUTPUT:
static Insect.x1 initialized static Beetle.x2 initialized Beetle constructor i = 9, j = 0 Beetle.k initialized k = 47 j = 39
Всегда думал, что перед вызовом конструктора, должны проиницилизоваться поля класса, чтобы в случае обращения к неициализирвоанной переменной в конструкторе не получить исключение. Следуя этой логике вывод на экран надписи "Beetle.k initialized" должен был быть после вывода "Beetle constructor". Прощу помочь разобраться. Спасибо.


Ответ

Порядок инициализации таков:
Статические элементы родителя Статические элементы наследника Глобальные переменные родителя Конструктор родителя Глобальные переменные наследника Конструктор наследника
Пример
class Insect { private int i = 9; [9] protected int j; [10] Insect() { [8] print("i = " + i + ", j = " + j); [11] j = 39; [12] } private static int x1 = printInit("static Insect.x1 initialized"); [2] static int printInit(String s) { [3] print(s); return 47; } }
public class Beetle extends Insect { private int k = printInit("Beetle.k initialized"); [13] public Beetle() { [7] print("k = " + k); [14] print("j = " + j); [15] } private static int x2 = printInit("static Beetle.x2 initialized"); [4] public static void main(String[] args) { [1] print("Beetle constructor"); [5] Beetle b = new Beetle(); [6] } }

Реализация своего ArrayList

Здравствуйте,есть задача написать свою коллекцию,но не понимаю как подойти к этому,как создать динамический массив в котором будут храниться все данные?


Ответ

Основные методы и логика масштабирования внутреннего массива в обе стороны:
public class MyArrayList { private final int INIT_SIZE = 16; private final int CUT_RATE = 4; private Object[] array = new Object[INIT_SIZE]; private int pointer = 0;
/* Добавляет новый элемент в список. При достижении размера внутреннего массива происходит его увеличение в два раза. */ public void add(T item) { if(pointer == array.length-1) resize(array.length*2); // увеличу в 2 раза, если достигли границ array[pointer++] = item; }
/* Возвращает элемент списка по индексу. */ public T get(int index) { return (T) array[index]; }
/* Удаляет элемент списка по индексу. Все элементы справа от удаляемого перемещаются на шаг налево. Если после удаления элемента количество элементов стало в CUT_RATE раз меньше чем размер внутреннего массива, то внутренний массив уменьшается в два раза, для экономии занимаемого места. */ public void remove(int index) { for (int i = index; i INIT_SIZE && pointer < array.length / CUT_RATE) resize(array.length/2); // если элементов в CUT_RATE раз меньше чем // длина массива, то уменьшу в два раза } /*Возвращает количество элементов в списке*/ public int size() { return pointer; }
/*Вспомогательный метод для масштабирования.*/ private void resize(int newLength) { Object[] newArray = new Object[newLength]; System.arraycopy(array, 0, newArray, 0, pointer); array = newArray; } }

Почему NaN не равняется NaN?

console.log( null == null, undefined == undefined, NaN == NaN ); // true, true, false Почему?


Ответ

Попробуем взглянуть на проблему с точки зрения математики. Как известно, NaN - это типичный результат для действий вроде деления бесконечности на бесконечность или ноля на ноль и прочих операций, результат которых с математической точки зрения не определен или не имеет смысла. Например, из математики известно, что логарифм отрицательного числа не определен. То есть следующая операция будет иметь результат NaN: Math.log(-5) // NaN При этом если вы попробуете выполнить такую операцию: 0/0 то ее результатом тоже будет NaN. В таком случае напрашивается вывод, что Math.log(-5) и 0/0 равны (в обоих случаях мы получим NaN). Очевидно, что это не так. Поэтому Принято допущение, что NaN не равен даже самому себе. (более того, будь NaN равен самому себе, то помощью нехитрых преобразований можно было бы прийти к выводу, что 2 == 1) Иными словами, NaN - это не какое-то конкретное значение, а просто некая достаточно удобная абстракция, под которой могут скрываться самые разные значения, совершенно не равные друг другу. У этого парадокса есть любопытное следствие: функцию IsNAN легко реализовать таким образом: return arg !== arg;

Перенести коммит из одной ветки в другую

Каким образом в Git перенести отдельный коммит из одной ветки А в ветку Б? При этом коммит содержит файлы, которые были изменены в ветке Б.


Ответ

В Git есть специальная команда cherry-pick, которая позволяет вставлять в текущую ветку изменения из любого коммита. Работает она так:
git cherry-pick test
Пример выше применяет последний коммит из ветки test в текущую ветку.
При желании, можно перенести более одного коммита за один раз. Например:
git cherry-pick 8fe1498 mega_fix~3 v1.0.1
Из примера выше видно, что на коммит можно сослаться сразу несколькими способами:
Используя SHA хэш коммита (или его сокращенный вариант). Используя имя ветки (можно использовать синтаксис ^ и ~). Используя тэг, которым помечен коммит.
Более подробная информация о том, как сослаться на коммит есть в документации к Git
Стоит отметить, что в отличии от слияния (merge) при cherry-pick переносятся только изменения, а не сам коммит полностью. При этом, в целевой ветке создается новый коммит (коммиты) содержащий необходимые изменения.

Употребление фигурных скобок компилятором

Любая конструкция if может быть записана с фигурными скобками или без них. К примеру:
bool j = true; if(j==true) MessageBox.Show("That's true")
Или же так:
bool j = true; if(j==true) { MessageBox.Show("That's true") }
Разговор идет только конструкции if с единственным действием. Отсюда несколько вопросов:
Игнорирует ли компилятор эти скобки? Если нет, обращает ли внимание программа на них? Оказывают ли влияние эти скобки на быстродействие программы (хоть самую незначительную)?


Ответ

Если обратиться к спецификации
Для if statement
if_statement: | 'if' '(' boolean_expression ')' embedded_statement | 'if' '(' boolean_expression ')' embedded_statement 'else' embedded_statement ;
Для циклов. например while:
while_statement: | 'while' '(' boolean_expression ')' embedded_statement ;
Как можно заметить на уровне спецификации никаких скобочек нет.
В свою очередь embedded_statement раскрывается так:
embedded_statement: | block | empty_statement | expression_statement | selection_statement | iteration_statement | jump_statement | try_statement | checked_statement | unchecked_statement | lock_statement | using_statement | yield_statement | embedded_statement_unsafe ;
И скобочки в данном случае являются частью block
block: | '{' statement_list? '}' ;
Таким образом, можно сказать, что:
Компилятор скобки не игнорирует, так как они являются частью синтаксической конструкции сама программа на них не может обращать внимания, но отличие в использовании все-таки есть. Например: внутри блока можно определять переменные, без скобок - нет. Так как это чисто синтаксическая конструкция на быстродействие скобки никакого влияния не оказывают.

Объединение строк в C#

Как из массива строк получить одну строку? Было: string[] many = { "ab", "bc", "cd", "de" }; Стало: string one = "abbccdde";


Ответ

Метод String.Join сцепляет элементы указанного массива или элементы коллекции, помещая между ними заданный разделитель. string one = string.Join(null, many);

Как перебрать массив элементов, не зная его размеров?

char peremen_t[] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
Мне нужно вывести все элементы массива. Я понимаю, что для этого нужен цикл:
for (int i = 0; i < 10; i++) { qDebug() <<"peremen_t[i] " << peremen_t[i]; }
А что если добавить несколько элементов, скажем так:
char peremen_t[] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 101, 102, 103};
То как перебирать все эти элементы, постоянно менять условие i < ...? Вот собственно вопрос: как перебирать массив элементов, не зная сколько там элементов? :)


Ответ

Имеется несколько подходов. Во первых размер массива можно вычислить по формуле sizeof( массива ) / sizeof( элемента массива ). Например
for ( size_t i = 0; i < sizeof( peremen_t ) / sizeof( *peremen_t ); i++ ) { qDebug() <<"peremen_t[i] " << peremen_t[i]; }
Во-вторых, вы можете использовать цикл for на основе диапазона. Если вам при этом нужен индекс элемента, то вы можете определить его до цикла. Например,
size_t i = 0; for ( auto x : peremen_t ) { qDebug() <<"peremen_t[" << i << "] " << x; ++i; }
Также вы можете использовать цикл с итераторами. Например,
#include
// ...
size_t i = 0; for ( auto it = std::begin( peremen_t ); it != std::end( peremen_t ); ++it, ++i ) { qDebug() <<"peremen_t[" << i << "] " << *it; }
И, наконец, вы можете написать шаблонную функцию, которая выполняет требуемую задачу. Например,
template inline void f( const T ( &peremen_t )[N] ) { for ( size_t i = 0; i < N; i++ ) { qDebug() <<"peremen_t[i] " << peremen_t[i]; } }
Кроме того вы можете использовать какое-нибудь граничное значение в массиве. Например, для символьных массивов это может быть '\0' при условии, что действительные элементы массива не могут содержать этот символ, или какое-нибудь другое уникальное значение. Например,
char peremen_t[] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 0 }; // ^^^ for ( size_t i = 0; permen_t[i] != '\0'; i++ ) { qDebug() <<"peremen_t[i] " << peremen_t[i]; }

Подключение сторонней библиотеки в проект Android Studio

Какие шаги нужно выполнить, чтобы добавить чужой проект (библиотеку) к своему в Android Studio? Нужно, чтобы я мог обратиться из своего проекта к классам из чужого проекта. В build.gradle я уже прописал.


Ответ

Во-первых, если библиотека достаточно выского качества, то автор библиотеки, как правило, дает инструкции о том, как ее подключить в свой проект - им надо следовать в первую очередь.
Сама Android Studio позволяет подключить три типа библиотек в свой проект:
из репозитория Maven библиотеку в виде собранного .jar файла библиотеку в виде исходных кодов
Для выполнения этой работы в Android Studio есть графический интерфейс, но олдскульные кодеры могут проделать ту же работу, прописывая необходимые команды в конфиги gradle вручную. Открываем окно структуры проекта (File -> Project Structure) и переходим к основному модулю проекта - слева секция Modules, кликнуть по названию модуля вашего приложения (на скриншоте это app). В открывшемся окне переходим к вкладке Dependencies. Здесь вы можете управлять подключенными зависимостями: добавить новые, удалить ненужные и перемещать их по иерархии.

Для того, чтобы добавить зависимость, нажимаем на плюсик справа и видим три пункта - рассмотрим их подробнее:
Library dependency — добавление библиотеки из внешнего репозитория
Этот пункт требует, как правило, наименьшего количества усилий. Обычно, по умолчанию, в конфиге gradle всего проекта в качестве внешнего репозитория используется JCenter и все уважающие себя разработчики складывают свои труды туда, но вы можете прописать в том конфиге и другие репозитории с библиотеками, если таковые вам требуются. При выборе пункта 1 появляется окно поиска, в котором вы можете набрать имя требуемой библиотеки и, если она присутствует в репозитории - вы ее увидите. Нажатие кнопки OK проделает всю черную работу по подключению библиотеки и после того, как gradle проведет необходимые манипуляции по скачиванию и импорту, она будет доступна в вашем проекте.

Если вы не доверяете инструментам Android Studio и желаете самостоятельно вручную добавить библиотеку из репозитория, вам необходимо прописать в секции dependencies{} конфига build.gradle вашего приложения ссылку на нужную библиотеку:
dependencies { compile 'com.mikepenz:materialdrawer:2.9.8' }
При внесении каких-либо изменений в конфиги gradle вверху появляется предупреждение о необходимости синхронизировать проект - когда все изменения будут сделаны, нажмите на ссылку Sync Now вверху справа, чтобы gradle применил ваши изменения.
File dependency — добавление библиотеки из локального скомпилированного .jar файла
Перед началом импорта локальной библиотеки в виде .jar файла необходимо скопировать сам файл библиотеки в папку /libs вашего проекта. При выборе пункта 2 появится стандартный диалог выбора файла, в котором необходимо указать, собственно, сам файл подключаемой библиотеки. При нажатии кнопки OK gradle проведет некоторые манипуляции по импорту, которые займут какое-то время, после чего библиотека будет доступна в вашем проекте.

Для того, чтобы вручную сделать то же самое — добавить библиотеку на основе .jar файла, в секции dependencies{} конфига build.gradle приложения необходимо прописать следующее:
dependencies { compile files('libs/realm.jar') }
Для того, чтобы подключить все библиотеки из папки /libs/ разом, нужно сделать так:
dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') }
Module dependency — добавление библиотеки из исходных кодов
Перед импортом библиотеки из исходных кодов необходимо скачать сами исходные коды и распаковать в какой-то каталог. Для наименьших проблем:
исходные коды должны быть gradle-проектом Android Studio/IntelliJ IDEA имена основного модуля и модуля подключаемой библиотеки не должны совпадать. подключаемый исходник является библиотекой, а не приложением (в build.gradle того, что вы подключаете указано apply plugin: 'com.android.library') — это можно исправить самостоятельно в конфиге gradle того, что вы подключаете. минимальные версии SDK вашего проекта и библиотеки должны совпадать — можно исправить самостоятельно в конфигах gradle проекта или библиотеки. версии BuildTools проекта и библиотеки должны совпадать (рекомендуется), либо обе версии должны быть установлены в вашем SDK (не рекомендуется). Лучшее решение — всегда использовать самую последнюю версию BuildTools
Для начала импортируем нужную библиотеку в свой проект в качестве модуля. Нажимаем File -> New -> Import Module, указываем путь до корневой папки с разархивированными исходниками и следуем другим указаниям мастера импорта.

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

Метод equals() в Java

Как правильно переопределить метод equals() в Java?


Ответ

Приведу пример, по которому все будет понятно, также не надо забывать, что при переопределении метода equals() необходимо переопределить метод hashCode(). Если метод equals() возвращает истину для двух объектов, то их хэш-код должен быть одинаковым. Обратное утверждение не верно. TestClass { private int id; public boolean equals(Object other) { if(!super.equals(other)) return false; if (this == other) return true; if (other == null) return false; if(this.getClass() != other.getClass()) return false; TestClass otherObj = (TestClass)other; return this.id == otherObj.id; } public int hashCode() { return 76+133*id; } }