Подтвердить что ты не робот

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

Скажем, я определяю класс, у которого в качестве члена есть переменная того же типа, что и сама.

public class abc {
    private abc p;
}

Это действительно работает, к моему удивлению.

Почему я не думаю, что это должно: создать экземпляр abc, он содержит переменную типа abc, которая содержит переменную типа abc, которая содержит переменную типа abc, которая.....

Очевидно, я ошибаюсь, может кто-то просветить меня о том, как?

4b9b3361

Ответ 1

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

public class Abc {
   private Abc p = new Abc(); // have fun!

   public static void main(String[] args) {
      new Abc();
   }
}

Кстати, если вы не создаете его в классе, а скорее принимаете ссылку на него в методе getter или в параметре конструктора, ваш код будет работать нормально. Вот как работают некоторые связанные списки.

Ответ 2

Разница заключается в проверке времени компиляции и времени выполнения.

В первом случае (время компиляции) вы объявляете, что в этом случае у вас будет ссылка на значение типа abc. Компилятор будет знать об этом, когда он проверяет правильную семантику, и поскольку он знает тип во время компиляции, он не видит проблем с этим.

Во втором случае (время выполнения) вы фактически создадите значение для этой ссылки для ссылки. Здесь вы можете столкнуться с проблемами. Например, если вы сказали следующее:

public class abc {
    private abc p;

    public abc() {
        p = new abc();
    }
}

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

Однако вы все равно можете сделать что-то подобное этому и избежать бесконечной рекурсии. Избегая создания значения во время строительства, вы откладываете его до тех пор, пока не будет вызван метод. На самом деле, это один из распространенных способов реализовать шаблон singleton в Java. Например:

public class abc {
    private abc p;

    private abc() {  // Private construction. Use singleton method
    }

    public static synchronized abc getInstance() {
        if (p == null)
            p = new abc();

        return p;
    }
}

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

Ответ 3

Если вы хотите смоделировать некоторые реальные сценарии, вам, возможно, придется использовать это понятие. Например, подумайте о ветке дерева. У ветки дерева может быть n количество ветвей на ней. Или из истории компьютерных наук подумайте о связанном списке Node. A node будет иметь ссылку на node рядом с ним. В конце следующего будет содержать нуль для указания конца списка.

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

Ответ 4

Подводя итог некоторым из ответов здесь.

В классе содержится ссылка на один из его собственных. Лучшая аналогия в реальном мире будет представлять собой охоту за сокровищами. Ключевое место имеет некоторые данные и подсказку в нем, что приводит к другому ключевому месту, которое снова вы знаете, повторяется.

Это не говорит о том, что в ключевом месте есть другое ключевое место в нем, о чем вы, кажется, делаете вывод.

Ответ 5

Как гласит выбранный ответ, все в порядке, потому что переменная не создается, а принимает ссылку из метода set или аргумента конструктора. Итак, вы видите, это просто ссылка, просто адрес.

Однако, есть способ создать его экземпляр, не вызывая ночной кошмар, и объявить его статическим. Этот вид изгибает правило рекурсии, поскольку статический член находится не на уровне объекта, а на уровне класса.

Так...

public class abc
{
    public static abc p = new abc ();
}

Работает просто отлично, потому что на переменную 'p' в действительности не влияет создание экземпляра класса abc. Это почти эквивалентно созданию объекта 'p' в другом классе.

Помните, что я могу сделать это...

 public class abc
 {
     public static abc p = new abc ();

     public static void main(String [] args)
     {
         abc.p;
     }
 }

Без создания нового объекта abc в основном методе. То, как работают статики, на них практически не влияет создание объектов, и в случае вашего вопроса они являются исключением из правила рекурсии.

Ответ 6

Основным использованием этого может быть связанный список в структуре данных. Это основная концепция в связанном списке, ссылка с одного узла на другой. Класс Node состоит из базового элемента для связанного списка.

class Node{
    private int value;
    private Node next; //reference, as a pointer to another node, →

    Node(){
        this.value=0;
        this.next=null;
    }
    Node(int value){
        this.value=value;
        this.next=null;
    }
    Node(int value,Node next){
        this.value=value;
        this.next=next;
    }
    public int getValue() {
        return this.value;
    }
    public void setValue(int value) {
        this.value=value;
    }
    public Node getNext() {
        return this.next;
    }
    public void setNext(Node next) {
        this.next=next;
    }
}

И мы можем соединить эти узлы, используя ссылку.

class Linkedlist{
    Node head = new Node();
    Node one = new Node();
    Node two = new Node();

    // Assign data values 
    one.value = 1;
    two.value = 2;

    // Connect nodes 
    one.next = two;
    two.next = NULL;

    //Save address of first node in head
    head = one;
}

Head → 1 next → 2 next → NULL

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

Ответ 7

В то время как мы говорим о "рекурсии", "выполнение" кода - это точка, которую мы рассматриваем. Да, это "динамический", если происходит "рекурсия".

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

В программе статические данные должны быть "конечными" (у вас нет "бесконечного" пространства памяти). Исполнение кода может быть "бесконечным". Но есть исключение. Просто изображение круга цепи.