Deepak
Deepak

Reputation: 6802

StackOverflow Exception in Java

I have an application which is written in Java. I have 3 classes mysql_query, tablesetup, table_action. Now inside the class of each of the class I have created the object of other classes which results in recursive object invocation. What are the alternative that I can use to fix this problem ?

For Example:

In mysql_query.java i have

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

In tablesetup.java I have

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

Similarly in table_action.java I have

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

--EDIT-- passing one class object to the constructor of other will not workout in my case as I have many dependent classes like this. So usually how programmers arrange these classes ? Can I use interface ? Is it appropriate to use in this case ?

Upvotes: 2

Views: 1773

Answers (4)

Lukas Eder
Lukas Eder

Reputation: 220762

One solution to this sort of problem is called lazy initialisation. Correct initialisation of objects can be a very complex task. In general you should avoid initialising too many other objects in the constructor (or implicit constructor as in your case). Here's an example:

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;
   }
}

I can't tell you if the above is going to work correctly, but it will give you an idea about lazy initialisation.

UPDATE: After your edit, my answer won't be sufficient for your use case. You might want to manage the lifecycle of your objects externally in a dedicated factory. See a basic explanation on the factory pattern here: http://en.wikipedia.org/wiki/Factory_method_pattern.

Another way of handling the complex lifecycle of model objects is by using frameworks such as EMF: http://www.eclipse.org/modeling/emf/. EMF helps you correctly model 1:1, 1:n and m:n relationships in Java, correctly handling/maintaining bi-directional references. I don't know if that will be overkill for you, though...

Upvotes: 2

Caner
Caner

Reputation: 59158

You can create only one instance and then pass it on to others like this:

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;
   }
}

Upvotes: 2

Jon Skeet
Jon Skeet

Reputation: 1499860

Bozho has shown why it fails, but for a solution, there are various options:

  • Break the circular references; why does each class need a reference to the other?
  • Make one class the "master" and make its constructor pass this into the constructor for the other class:

    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;
        }
    }
    

    The downsides of this are:

    • The dependencies are still pretty tight
    • You're letting this escape from the Foo constructor; usually an object shouldn't publish its existence until it has finished being constructed.
  • Make your classes mutable, and have a separate method which creates all of them without their dependencies, then sets the dependencies afterwards

Upvotes: 3

Bozho
Bozho

Reputation: 597026

  • in tablesetup you are instantiating a table_action
  • in table_action you are instantiating a tablesetup

I guess you see the loop - the first creates a new instance of the second which creates a new instance of the first, which creates a new instance of the second, and so on until your stack (holding method and constructor calls) is filled.

A little more clarification - when you instantiate an object through its constructor, all of its fields are initialized. So when you instantiate table_action, new tablesetup() is invoked in order to initialize the tablesetuptablesetup variable.

Circular dependencies are not a good thing, but you can have them. You just need to pass a reference to an existing tablesetup when creating table_actions.

Apart from that - you are not using proper java naming. You should not use lowercase classes and underscores. The proper names are TableSetup, TableAction and MySQLQuery. Same goes for variable names, apart from the upper-case. They should by mysqlQuery, tableSetup, etc.

Upvotes: 7

Related Questions