简体   繁体   English

如何在类的其他方法中使用在构造函数中初始化的对象

[英]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). 我正在使用Swing,JDBC(Oracle)创建一个简单的登录应用程序。 It works as expected for the most part. 它在大多数情况下都可以正常工作。 The app has 3 classes - Logic, UI and DBConnection. 该应用程序具有3类-逻辑,UI和DBConnection。

Please refer to the whole code here : Full Code 请在此处参考整个代码: 完整代码

1. LoginLogic.java 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. 最初,我直接显示了一个JOptionPane来代替loginSuccess()和loginFailed()方法,它按预期工作。 But I wanted to delegate all the UI functionality to the UI class so I created these 2 methods in the UI class 但是我想将所有UI功能都委托给UI类,因此我在UI类中创建了这两个方法

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. 但是不会使用我在构造函数中创建的UI对象调用这些方法。 There's no error, but there's no JOptionPane either. 没有错误,但是也没有JOptionPane。

How I can use the UI object reference lu in the process() method to call the methods of the UI class? 如何在process()方法中使用UI对象引用lu来调用UI类的方法?

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. 因此,它创建了LoginUI对象,但仅此而已。 In particular, it never calls the process() method, which is the one displaying the JOptionPane. 特别是,它永远不会调用process()方法,该方法显示JOptionPane。

The other constructor, that you never call, does call the process() method. 您从未调用过的另一个构造函数会调用process()方法。 But it doesn't initialize the LoginUI object. 但是它不会初始化LoginUI对象。

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. 我也看不到如何调用process()方法,因为在代码中没有任何东西创建该方法需要作为参数的ResultSet。

As JB Nizet explained there are some changes to be done in your code. 正如JB Nizet解释的那样,您的代码中需要进行一些更改。 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. 这意味着您没有在if()语句中调用正确的对象。 Your new object was constructed with the parameterized constructor which does not initialize lu or update it. 您的新对象是使用参数化构造函数构造的,该构造函数不会初始化lu或对其进行更新。

EDITED2 编辑2

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: loginUI将更改为:

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: 而LoginDbConn对此:

 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); 您可以通过new LoginLogic(resultSet);来调用它new LoginLogic(resultSet);

Thanks to +Guizmoo03 for pointing out the root of the problem. 感谢+ Guizmoo03指出了问题的根源。

As you can see in this code, the class has 2 constructors. 如您在此代码中看到的,该类具有2个构造函数。 The LoginUI object reference which starts out null is initialized first by the default constructor when the UI is created. 创建UI时,默认构造函数首先初始化从null开始的LoginUI对象引用。

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. 但是,当Logic类的对象传递要处理的ResultSet到参数化构造函数时,将再次在DbConn类中创建该对象。 This instantiation dereferences the UI object variable lu . 此实例取消引用UI对象变量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. 因此,正如我在最初的问题中指出的那样,它不再可以用来访问process()方法中的UI类的方法。

...

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 DbConn类片段

// 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 所以解决方案:可能的解决方法是像这样在构造函数外部实例化UI对象变量lu

...
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. 尽管这解决了解引用问题,但在DbConn创建逻辑类的新对象时,导致GUI重新初始化。

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. 但是在OO代码中使用太多静态元素不是一个好习惯。

So I switched to the Singleton pattern with Eager initialization , which efficiently solved the problem. 因此,我切换到具有Eager初始化Singleton模式 ,从而有效地解决了该问题。

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 登录UI

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Java - 如何允许类的所有方法访问在构造函数中初始化的数组? - Java - How to allow all methods of a class to access an array initialized in constructor? 在测试类的其他方法中使用对象 - Use an object in other methods of a test class 如何在Java中的其他方法中使用此构造函数中的变量? - How do I use variables from this constructor in other methods in Java? 用默认构造函数和configure方法在Java中编写一个类,该方法定义如何初始化该类的对象? - Writing a class in Java with a default constructor and configure method defining how an object of that class is initialized? 如何在不同类的构造函数中使用对象? - How to use an object in a constructor of a different class? 如何构建 class 和构造函数泛型以使用泛型方法? - How to build a class and constructor generic to use generic methods? 如何初始化单例类的对象? - How the object for singleton class is initialized? 如何将Java类放入对象并使用它的方法 - How to put a java class in a Object and use it methods 有没有一种优雅的方法可以根据用于创建该对象的构造函数来更改类的对象可以使用的方法/变量? - Is there an elegant way to change what methods/variables an object of a class can use based on the constructor used to create this object? 在其他方法中使用对象状态 - Use object state in other methods
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM