Исключение StackOverflow в Java - PullRequest
       1

Исключение StackOverflow в Java

2 голосов
/ 24 августа 2011

У меня есть приложение, написанное на Java. У меня есть 3 класса mysql_query, tablesetup, table_action. Теперь внутри класса каждого из классов я создал объект других классов, что приводит к вызову рекурсивного объекта. Какие альтернативы я могу использовать для решения этой проблемы?

Например:

В mysql_query.java у меня есть

public class mysql_query{  
   tablesetup tablesetup = new tablesetup();  
   table_action table_action = new table_action();   
}

В tablesetup.java у меня есть

public class tablesetup{  
   mysql_query mysql_query= new mysql_query();  
   table_action table_action = new table_action();   
}

Аналогично в table_action.java у меня есть

public class table_action{  
   mysql_query mysql_query= new mysql_query();  
   tablesetup tablesetup= new tablesetup();   
}

- EDIT-- передача одного объекта класса в конструктор другого не будет работать в моем случае, так как у меня много таких зависимых классов Так обычно, как программисты устраивают эти классы? Могу ли я использовать interface? Уместно ли использовать в этом случае?

Ответы [ 4 ]

7 голосов
/ 24 августа 2011
  • в tablesetup вы создаете table_action
  • в table_action вы создаете tablesetup

Я думаю, вы видите цикл -первый создает новый экземпляр второго, который создает новый экземпляр первого, который создает новый экземпляр второго и т. д., пока ваш стек (удерживающий вызовы метода и конструктора) не будет заполнен.

Aнемного больше пояснений - когда вы создаете экземпляр объекта через его конструктор, все его поля инициализируются.Поэтому, когда вы создаете экземпляр table_action, new tablesetup() вызывается для инициализации переменной tablesetuptablesetup.

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

Кроме того, вы не используете правильное именование Java.Вы не должны использовать строчные классы и подчеркивания.Собственные имена TableSetup, TableAction и MySQLQuery.То же самое относится и к именам переменных, кроме заглавных.Они должны быть mysqlQuery, tableSetup и т. Д.

3 голосов
/ 24 августа 2011

Божо показал, почему это не удается, но для решения есть различные варианты:

  • Разбить циклические ссылки;почему каждому классу нужна ссылка на другой?
  • Сделайте один класс "основным" и сделайте так, чтобы его конструктор передал this в конструктор для другого класса:

    class Foo
    {
        private final Bar bar;
    
        public Foo()
        {
            bar = new Bar(this);
        }
    }
    
    class Bar
    {
        private final Foo foo;
    
        public Bar(Foo foo)
        {
            this.foo = foo;
        }
    }
    

    Недостатки этого:

    • Зависимости все еще довольно тесные
    • Вы позволяете this убежать из конструктора Foo;обычно объект не должен публиковать свое существование до тех пор, пока он не закончил конструирование.
  • Сделайте ваши классы изменяемыми и используйте отдельный метод, который создает все из них без их зависимости, затем устанавливает зависимости потом

2 голосов
/ 24 августа 2011

Вы можете создать только один экземпляр, а затем передать его другим, например:

public class mysql_query{  
   tablesetup tablesetup;  
   table_action table_action;   
   public void mysql_query() {
     tablesetup tablesetup = new tablesetup(this);  
     table_action table_action = new table_action(this);   
   }
}

public class tablesetup{  
   mysql_query mysql_query;  
   table_action table_action;   
   public void tablesetup(mysql_query query) {
     mysql_query = query;
     table_action = new table_action(this);
   }
}

public class table_action{  
   mysql_query mysql_query;  
   tablesetup tablesetup; 
   public void  table_action(mysql_query query, tablesetup setup) {
         mysql_query = query;
         tablesetup = setup;
   }
}
2 голосов
/ 24 августа 2011

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

public class table_action{  
   // Never access members directly:
   private mysql_query mysql_query;  
   private tablesetup tablesetup;   

   // Only access getters
   mysql_query get_mysql_query() {
     if (mysql_query == null) {
       mysql_query = new mysql_query();
     }
     return mysql_query;
   }

   tablesetup get_tablesetup() {
     if (tablesetup == null) {
       tablesetup = new tablesetup();
     }
     return tablesetup;
   }
}

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

ОБНОВЛЕНИЕ : после вашего редактирования моего ответа будет недостаточно для вашего варианта использования.Возможно, вы захотите управлять жизненным циклом ваших объектов извне на выделенной фабрике.См. Базовое объяснение фабричного шаблона здесь: http://en.wikipedia.org/wiki/Factory_method_pattern.

Еще один способ обработки сложного жизненного цикла объектов модели - использование таких сред, как EMF: http://www.eclipse.org/modeling/emf/. EMF помогает правильно моделировать 1:1, 1:n и m:n отношения в Java, правильная обработка / поддержка двунаправленных ссылок.Я не знаю, будет ли это излишним для вас, хотя ...

...