Когда вы объявляете ссылочную переменную (т. е. объект), вы действительно создаете указатель на объект. Рассмотрим следующий код, в котором вы объявляете переменную примитивного типа int
:
int x;
x = 10;
В этом примере переменная x является int
, и Java инициализирует ее для 0. Когда вы назначаете его 10 во второй строке, ваше значение 10 записывается в ячейку памяти, на которую указывает x.
Но когда вы пытаетесь объявить ссылочный тип, произойдет что-то другое. Возьмите следующий код:
Integer num;
num = new Integer(10);
Первая строка объявляет переменную с именем num
, но она не содержит примитивного значения. Вместо этого он содержит указатель (потому что тип Integer
является ссылочным типом). Поскольку вы еще не указали, что указать на Java, он устанавливает значение null, что означает «Я ничего не указываю».
Во второй строке ключевое слово new
используется для создания экземпляра (или создания ) объекту типа Integer и переменной указателя num
присваивается этот объект. Теперь вы можете ссылаться на объект, используя оператор разыменования .
(точка).
Exception
, о котором вы просили, возникает, когда вы объявляете переменную, но не создавали объект. Если вы попытаетесь разыменовать num
. Перед созданием объекта вы получите NullPointerException
. В самых тривиальных случаях компилятор поймает проблему и сообщит вам, что «num не может быть инициализирован», но иногда вы пишете код, который непосредственно не создает объект.
Например, вы можете имеют следующий метод:
public void doSomething(SomeObject obj) {
//do something to obj
}
В этом случае вы не создаете объект obj
, скорее предполагая, что он был создан до вызова метода doSomething
. К сожалению, этот метод можно вызвать следующим образом:
doSomething(null);
В этом случае obj
имеет значение null. Если метод предназначен для того, чтобы что-то сделать для переданного объекта, целесообразно бросить NullPointerException
, потому что это ошибка программиста, и программисту понадобится эта информация для целей отладки.
Альтернативно, там могут быть случаи, когда цель метода заключается не только в том, чтобы работать с переданным в объекте, и поэтому нулевой параметр может быть приемлемым. В этом случае вам нужно будет проверить нулевой параметр и вести себя по-другому. Вы также должны объяснить это в документации. Например, doSomething
может быть записано как:
/**
* @param obj An optional foo for ____. May be null, in which case
* the result will be ____.
*/
public void doSomething(SomeObject obj) {
if(obj != null) {
//do something
} else {
//do something else
}
}
Наконец, Как определить исключение & amp; причина использования Трассировки стека
Я использовал Вложенные Наборы много, и я часто сталкивался с той же проблемой. То, что я делаю, и что я рекомендовал бы, не должно просто сортировать объекты в базе данных. Вместо этого отсортируйте их в пользовательском интерфейсе. После получения по запросу всех узлов от DB, вероятно, необходимо преобразовать их в некоторую иерархическую структуру данных, так или иначе. В той структуре, вид все массивы, содержащие детей узла.
, Например, если Ваш frontend является приложением Flex и детьми узла, хранятся в ICollectionView, можно использовать свойство вида, чтобы сделать, чтобы они отобразили способ, которым Вы хотите.
Другой пример, если Ваш frontend является некоторым выводом из Сценария PHP, Вы могли бы иметь детей каждого узла в массиве и использовать функции сортировки массива PHP для выполнения сортировки.
, Конечно, это только работает, если Вы не нуждаетесь в фактических записях дб, которые будут отсортированы, но делаете Вас?
Я только что закончил писать следующее, которое работает на меня в сортировке всего вложенного дерева набора.
вид (идеально) требует представления, которое перечисляет текущий уровень каждого узла в дереве и процедуре свопинга двух узлов - оба включены ниже, одноуровневый код подкачки появляется от Joe Celkos 'Дерево & книга Иерархий, которую я настоятельно рекомендую любому использующему вложенные наборы.
вид может быть изменен в операторе 'INSERT INTO @t', здесь это - простой алфавитно-цифровой вид на 'Имени'
, Это может быть плохим способом сделать его особенно использование курсора для основанного на наборе кода, но поскольку я говорю, что он работает на меня, надежда, которой он помогает.
ОБНОВЛЕНИЕ:
Код ниже теперь показывает версию, не используя курсор. Я занимаюсь 10x улучшения скорости
CREATE VIEW dbo.tree_view
AS
SELECT t2.NodeID,t2.lft,t2.rgt ,t2.Name, COUNT(t1.NodeID) AS level
FROM dbo.tree t1,dbo.tree t2
WHERE t2.lft BETWEEN t1.lft AND t1.rgt
GROUP BY t2.NodeID,t2.lft,t2.rgt,t2.Name
GO
----------------------------------------------
DECLARE @CurrentNodeID int
DECLARE @CurrentActualOrder int
DECLARE @CurrentRequiredOrder int
DECLARE @DestinationNodeID int
DECLARE @i0 int
DECLARE @i1 int
DECLARE @i2 int
DECLARE @i3 int
DECLARE @t TABLE (TopLft int,NodeID int NOT NULL,lft int NOT NULL,rgt int NOT NULL,Name varchar(50),RequiredOrder int NOT NULL,ActualOrder int NOT NULL)
INSERT INTO @t (toplft,NodeID,lft,rgt,Name,RequiredOrder,ActualOrder)
SELECT tv2.lft,tv1.NodeID,tv1.lft,tv1.rgt,tv1.Name,ROW_NUMBER() OVER(PARTITION BY tv2.lft ORDER BY tv1.ColumnToSort),ROW_NUMBER() OVER(PARTITION BY tv2.lft ORDER BY tv1.lft ASC)
FROM dbo.tree_view tv1
LEFT OUTER JOIN dbo.tree_view tv2 ON tv1.lft > tv2.lft and tv1.lft < tv2.rgt and tv1.level = tv2.level+1
WHERE tv2.rgt > tv2.lft+1
DELETE FROM @t where ActualOrder = RequiredOrder
WHILE EXISTS(SELECT * FROM @t WHERE ActualOrder <> RequiredOrder)
BEGIN
SELECT Top 1 @CurrentNodeID = NodeID,@CurrentActualOrder = ActualOrder,@CurrentRequiredOrder = RequiredOrder
FROM @t
WHERE ActualOrder <> RequiredOrder
ORDER BY toplft,requiredorder
SELECT @DestinationNodeID = NodeID
FROM @t WHERE ActualOrder = @CurrentRequiredOrder AND TopLft = (SELECT TopLft FROM @t WHERE NodeID = @CurrentNodeID)
SELECT @i0 = CASE WHEN c.lft < d.lft THEN c.lft ELSE d.lft END,
@i1 = CASE WHEN c.lft < d.lft THEN c.rgt ELSE d.rgt END,
@i2 = CASE WHEN c.lft < d.lft THEN d.lft ELSE c.lft END,
@i3 = CASE WHEN c.lft < d.lft THEN d.rgt ELSE c.rgt END
FROM dbo.tree c
CROSS JOIN dbo.tree d
WHERE c.NodeID = @CurrentNodeID AND d.NodeID = @DestinationNodeID
UPDATE dbo.tree
SET lft = CASE WHEN lft BETWEEN @i0 AND @i1 THEN @i3 + lft - @i1
WHEN lft BETWEEN @i2 AND @i3 THEN @i0 + lft - @i2
ELSE @i0 + @i3 + lft - @i1 - @i2
END,
rgt = CASE WHEN rgt BETWEEN @i0 AND @i1 THEN @i3 + rgt - @i1
WHEN rgt BETWEEN @i2 AND @i3 THEN @i0 + rgt - @i2
ELSE @i0 + @i3 + rgt - @i1 - @i2
END
WHERE lft BETWEEN @i0 AND @i3
AND @i0 < @i1
AND @i1 < @i2
AND @i2 < @i3
UPDATE @t SET actualorder = @CurrentRequiredOrder where NodeID = @CurrentNodeID
UPDATE @t SET actualorder = @CurrentActualOrder where NodeID = @DestinationNodeID
DELETE FROM @t where ActualOrder = RequiredOrder
END
Да это - ограничение вложенной модели набора, так как вложенные наборы являются предварительно заказанным представлением иерархии. Это делать предзаказ является причиной, что это настолько быстро для чтений. Модель смежности, также описанная на странице, с которой Вы связываетесь, предусматривает самую гибкую сортировку и фильтрацию, но со значительным влиянием производительности.
Мой предпочтительный подход для вставок и перемещения во вложенном наборе должны обработать затронутое ответвление как в модели смежности: Получите список новых одноуровневых элементов; найдите правильное место в списке для нового узла; и создайте необходимые операторы обновления (что, будучи битом, где действительно необходимо быть осторожными). Что касается изменения Ваших критериев упорядочивания: это - то от пакетного задания, таким образом, можно позволить себе унести некоторую RAM и ЦП на ней, самый гибкий ответ должен был бы разломать вложенное представление набора на представление смежности и восстановить вложенный набор от смежности на основе новых критериев.
Я думаю, что это - действительно ограничение вложенной модели набора. Вы не можете легко отсортировать дочерние узлы в их соответствующем родительском узле, потому что упорядочивание набора результатов важно для восстановления древовидной структуры.
я думаю, что это - вероятно, лучший подход для хранения дерева отсортированным при вставке, обновлении или удалении узлов. Это даже делает запросы очень быстро, который является одной из главных целей этой структуры данных. При реализации хранимых процедур для всех операций это очень просто в использовании.
можно также инвертировать порядок сортировки предварительно отсортированного дерева. Просто необходимо использовать ORDER BY node.rgt DESC
вместо ORDER BY node.lft ASC
.
, Если действительно необходимо поддерживать другого критерии сортировки, Вы могли возможная реализация это путем добавления секунды lft
и rgt
индекс к каждому узлу и сохранять отсортированным по другим критериям на каждом вставляемые/обновлять/удалять.
Я считаю, что в вашем случае, когда узлы, которые вы хотите поменять местами, не имеют потомков, вы можете просто поменять местами значения lft и rgt. Рассмотрим это дерево:
A
/ \
B C
/ \
D E
Это может превратиться в эту группу вложенных наборов:
1 A 10
2 B 3
4 C 9
5 D 6
7 E 8
Теперь представьте, что вы хотите поменять местами D и E. Следующие вложенные наборы действительны, и D и E поменяны местами:
1 A 10
2 B 3
4 C 9
7 D 8
5 E 6
Обмен узлов, которые имеют поддеревья, конечно, не могут быть выполнены таким образом, потому что вам также нужно будет обновить дочерние значения lft и rgt.