简体   繁体   中英

How to use the object initialized in a constructor in other methods of the class

Programming Newbie here. I'm creating a simple login app using Swing, JDBC(Oracle). It works as expected for the most part. The app has 3 classes - Logic, UI and DBConnection.

Please refer to the whole code here : Full Code

1. LoginLogic.java

    public class LoginLogic {

    LoginUI lu;

    public LoginLogic() {
        lu = new LoginUI();

    }

    public LoginLogic(ResultSet rs) {
        process(rs);
    }

    private void process(ResultSet rs) {
        try {
            if (rs.next()) {
                lu.loginSuccess();

            } else {
                lu.loginFailed();
            }
        } catch (SQLException e) {
            // TODO: handle exception
        }
    }

    public static void main(String[] args) {

        new LoginLogic();

    }


 }

Initially, I had displayed a JOptionPane directly in place of the loginSuccess() and loginFailed() methods and it worked as expected. But I wanted to delegate all the UI functionality to the UI class so I created these 2 methods in the UI class

void loginSuccess() {
        JOptionPane.showMessageDialog(null, "Login Successful!");
}

void loginFailed() {
    JOptionPane.showMessageDialog(null, "Login Failed!");
} 

But these methods are not being called using the UI object that I created in the constructor. There's no error, but there's no JOptionPane either.

How I can use the UI object reference lu in the process() method to call the methods of the UI class?

Your main method calls the no-arg constructor. This no-arg constructor is implemented as

lu = new LoginUI();

So it creates the LoginUI object, but does nothing more. In particular, it never calls the process() method, which is the one displaying the JOptionPane.

The other constructor, that you never call, does call the process() method. But it doesn't initialize the LoginUI object.

I also don't see how you could call the process() method, since there is nothing in the code that creates the ResultSet that this method needs as argument.

As JB Nizet explained there are some changes to be done in your code. Try the following code (It worked for me).

public class LoginLogic {

LoginUI lu;

public LoginLogic() {
    lu = new LoginUI();

}

public LoginLogic(ResultSet rs) {
    lu = new LoginUI();
    process(rs);
}

private void process(ResultSet rs) {
    try {
        if (rs.next()) {
            lu.loginSuccess();

        } else {
            lu.loginFailed();
        }
    } catch (SQLException e) {
        // TODO: handle exception
    }
}

public static void main(String[] args) {

    /*/ Here you shld get your result rs first 

            con is your Connection object
            Statement stmt = con.createStatement(
            ResultSet.TYPE_SCROLL_INSENSITIVE,
            ResultSet.CONCUR_UPDATABLE);

            ResultSet rs = stmt.executeQuery("SELECT yourColumn FROM yourTable");
    //*/

    new LoginLogic(rs);
}
}

EDITED

As per our comments, the problem is that you are creating a new object in your:

 private void getConn(String uname, String pwd) {
    ...
        // 4. Process the result set
        new LoginLogic(rs);

    ...

}

This means that you are not calling the right object in your if() statement. Your new object was constructed with the parameterized constructor which does not initialize lu or update it.

EDITED2

I think you have to change a little bit your design. I think the following will work for you but you have to handle the exceptions.

public class LoginLogic {

LoginUI lu;

public LoginLogic() {
    lu = new LoginUI();

}


public void process() {
    try {
        if (lu.getRs().next()) {
            lu.loginSuccess();

        } else {
            lu.loginFailed();
        }
    } catch (SQLException e) {
        // TODO: handle exception
    }
}

public static void main(String[] args) {

    LoginLogic loginLogic = new LoginLogic();
    loginLogic.process();
 }
 }

The loginUI will change to:

public class LoginUI {

      ...
       ResultSet rs;

       public ResultSet getRs() {
          return rs;
       }
       ...
      btnLogin.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {

            try {
                String uname = tfUname.getText().trim();
                String pwd = tfPwd.getText().trim();

                LoginDbConn loginDbConn = new LoginDbConn(uname, pwd);// startDB after user presses     
                rs = loginDbConn.getConn();

            } catch (Exception ex) {
                // TODO: handle exception
            }

        }
    });

    ....
 }

And the LoginDbConn to this:

 public class LoginDbConn {

String uname;
String pwd;
ResultSet rs;
/*
 * public LoginDbConn() { // TODO Auto-generated constructor stub }
 */

public LoginDbConn(String uname, String pwd) {
    this.uname = uname;
    this.pwd = pwd;
}

public ResultSet getConn() {
    try {
        // 0. Register the JDBC drivers
        String driverClass = "oracle.jdbc.driver.OracleDriver";
        Class.forName(driverClass);
        // or DriverManager.registerDriver(new oracle.jdbc.OracleDriver());

        // 1. Get a connection to the Database
        String dbUrl = "jdbc:oracle:thin:@localhost:1521:xe";
        String dbuname = "scott";
        String dbpwd = "tiger";
        Connection conn = DriverManager.getConnection(dbUrl, dbuname, dbpwd);

        // 2. Create a statement
        // String sql = "SELECT * FROM users WHERE name = '"+uname+"' and
        // password = '"+pwd+"'";
        // Statement st = conn.createStatement();
        String sql = "select * from users where name = ? and password = ?";
        PreparedStatement pst = conn.prepareStatement(sql);

        pst.setString(1, uname);
        pst.setString(2, pwd);

        // 3. Execute SQL query
        rs = pst.executeQuery();

        // 5. Close Connection
        // conn.close();

        return rs;
    } catch (SQLException | ClassNotFoundException e) {

            // THIS EXCEPTION MUST ABSOLUTELY BE HANDLED
    }
    return rs;
}

}

Hope this will help (if so please vote for the answer).

Instead of using two constructor you can achieve this by one constructor :

public LoginLogic(ResultSet rs) {
    lu = new LoginUI();
    process(rs);
}

You just called this from where you want to call. You can call this by new LoginLogic(resultSet);

Thanks to +Guizmoo03 for pointing out the root of the problem.

As you can see in this code, the class has 2 constructors. The LoginUI object reference which starts out null is initialized first by the default constructor when the UI is created.

public class LoginLogic {

    LoginUI lu;

    public LoginLogic() {
        lu = new LoginUI();

    }
     .....

But an object of the Logic class is again created in DbConn class when it passes the ResultSet to be processed to the parameterized constructor. This instantiation dereferences the UI object variable lu . Hence, it can no longer be used to access the methods of the UI class in the process() method as I pointed out in my initial question.

...

LoginUI lu;

...

public LoginLogic(ResultSet rs) {
        process(rs);
    }

    private void process(ResultSet rs) {
        try {
            if (rs.next()) {
                lu.loginSuccess();

            } else {
                lu.loginFailed();
            }
        } catch (SQLException e) {
            // TODO: handle exception
        }
    }
...

DbConn Class snippet

// 4. Process the result set
   new LoginLogic(rs);

So the Solution: A possible workaround was to instantiate the UI object variable lu outside the constructor as such

...
LoginUI lu = new LoginUI();

public LoginLogic() {

}

public LoginLogic(ResultSet rs) {
    process(rs);
}

private void process(ResultSet rs) {
...

Though this solved the dereferencing problem, it caused the GUI to be re-initialsed when DbConn created a new object of the Logic Class.

public class LoginUI {

        // Container declarations
        ...

        // Component declarations
       ...

        public LoginUI() {
            createFrame();
        }

        private void createFrame() {
        ...

Another workaround which actually worked without much side-effects was to use static methods . But it ain't a good practice to use too many static elements in a OO code.

So I switched to the Singleton pattern with Eager initialization , which efficiently solved the problem.

LoginLogic

public class LoginLogic {

    static final LoginUI lu = LoginUI.getInstance(); // immutable singleton
                                                        // object reference

    public LoginLogic() {
        // TODO Auto-generated constructor stub
    }

    public LoginLogic(ResultSet rs) { // parameterized constructor
        process(rs);
    }

    void process(ResultSet rs) {...

LoginUI

public class LoginUI {

    // Container declarations

    // Component declarations

    private static final LoginUI lu = new LoginUI(); // immutable singleton
                                                        // object

    private LoginUI() { // prevent external instantiation
        initUI();
    }

    static LoginUI getInstance() { // getter for the singleton object
        return lu;
    }...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM