在Java中访问另一个类的数据成员字段

时间:2015-02-07 11:39:05

标签: java reflection

因此,我希望通过反射从一个其他类中访问一个类的数据成员字段。我无法弄清楚,在通过反射得到数据成员之后,我可以改变字段的值。我不知道如何更好地表达它,所以我会让代码为我说话。

下面是调用按钮的处理程序类。以下是其他课程,我将在旅途中解释其功能。

import java.awt.*;
import java.awt.event.*;

public class SimHandler extends Frame{

    public myValveButton but0,but1,but2,but3,but4,but5,but6,but7;
    public SimHandler(){    
        super("Liquer Plant Control Panel");
        this.setLayout(null);
        this.setFont(new Font("Helvetica", Font.PLAIN, 14));
        this.setBackground(Color.black);

        but0 = new myValveButton("S1a",100,40,this);
        but1 = new myValveButton("S1b",100,140,this);
        but2 = new myValveButton("S2a",200,40,this);
        but3 = new myValveButton("S2b",200,140,this);
        but4 = new myValveButton("S3a",100,240,this);
        but5 = new myValveButton("S3b",100,340,this);
        but6 = new myValveButton("S4a",200,240,this);
        but7 = new myValveButton("S4b",200,340,this);

        this.setSize(335,410);
        this.setLocation(100,100);
        this.setVisible(true);
        this.toFront();            
        this.setResizable(false);  
        this.addWindowListener(new WindowAdapter(){
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

    }
}

这实际上是我尝试使用反射来改变Silo实例状态的值的地方。下面是LiqPlantSim和Silo课程。正如您所看到的,状态变量无法以这种方式解决,经过一些谷歌搜索,我无法弄清楚如何使其工作。

import java.awt.Button;
import java.awt.Frame;
import java.awt.event.*;
import java.lang.reflect.Field;

public class myValveButton extends Button{
    String label;
    public myValveButton(String label,int x,int y,Frame f){
        super(label);
        this.label = label;
        this.addActionListener(new myValveButtonHandler(label));
        f.add(this);
        this.setBounds(x, y, 35, 30);
        }
}

class myValveButtonHandler implements ActionListener{
    Field f;
    String label;
    public myValveButtonHandler(String label){
        this.label = label;
    }

    public void actionPerformed(ActionEvent pushButton){
        try {
            f = LiqPlantSim.class.getDeclaredField("silo"+label.split("")[1]);
            System.out.println(f);
            //f.state = "full"   //Eclipse says 'state cannot be resolved to a type or is not a field'
        } catch (NoSuchFieldException e) {
        } catch (SecurityException e) {
        }
        System.out.println(label.split("")[2]);
    }
}

这是LiqPlantSim类。

import java.util.HashMap;
import java.util.Map;

public class LiqPlantSim{   

    public Silo silo1,silo2,silo3,silo4;
    public Pipe pipe;

    public LiqPlantSim(){       
        silo1 = new Silo(false,false);
        silo2 = new Silo(false,true);
        silo3 = new Silo(true,false);
        silo4 = new Silo(true,true);
        pipe = new Pipe();          
    }
}

这是Silo Class。

public class Silo {

    public boolean mixer,resistance;
    public String state,mixerState,resState;
    public Silo(boolean mix,boolean res){
        mixer = mix;
        resistance = res;
        state = "empty";
    }

}

除了了解如何访问孤岛状态变量之外,我非常感谢有关如何更好地构建我的工作的任何反馈和/或建议,以及我可能犯的任何错误。

3 个答案:

答案 0 :(得分:1)

首先,Class#getDeclaredField(String)会返回Field个对象,而不是该字段的实际值。要获取该值,必须使用Field#get(Object),其中参数是您尝试访问字段的类的实例。在您的代码中,这将是:

LiqPlantSim sim = doSomethingToGetInstance();
f = LiqPlantSim.class.getDeclaredField("siloX");
Silo silo = (Silo) f.get(sim);

这让我想到了下一点:为什么要使用反射?您的答案可能与使用标签获取正确的Silo有关。您应该*重组LiqPlantSim以使用数组或List来解决此问题:

import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;

public class LiqPlantSim{   

    private List<Silo> silos;
    public Pipe pipe;

    public LiqPlantSim(){
        silos = new ArrayList<>();
        silos.add(new Silo(false,false));
        silos.add(new Silo(false,true));
        silos.add(new Silo(true,false));
        silos.add(new Silo(true,true));
        pipe = new Pipe();          
    }

    public Silo getSilo(int index) {
        return silos.get(index);
    }

    //Possibly other methods to access silos
}

(编辑:你应该对SimHandler中的按钮做同样的事情)

然后,在处理程序中,您可以像这样访问Silo

 public void actionPerformed(ActionEvent pushButton){
    try {
        int labelLength = label.length();
        int index = Integer.parseInt(label.substring(labelLength - 1, labelLength));
        Silo silo = doSomethingToGetLiqPlantSimInstance().getSilo(index);
        silo.state = "full" //Note that it is good practice to use private fields and public getters and setters
    } catch (NoSuchFieldException e) {
    } catch (SecurityException e) {
    }
    System.out.println(label.split("")[2]);
}

更好的是,在构造函数中获取索引并存储它,这样您就不必每次都重新计算它。

*当然,这只是一个建议

答案 1 :(得分:0)

这:"silo"+label.split("")[1]将创建String siloS。 要从label变量中获取数字,请尝试:label.substring(1,2)

此外,您无需将Frame f传递给myValveButton构造函数,您可以使用SimHandler直接在this.add(but0)中将按钮添加到框架中。< / p>

答案 2 :(得分:0)

为什么要在按钮类中实现动作侦听器? ValveButton不应该知道点击它时该怎么做。

相反,您应该在SimHandler类中实现您的动作侦听器。在实例化8个ValveButtons之后,您可以在循环中添加动作侦听器。

无论如何 - 如果你真的需要使用反射寻求解决方案,我会建议使用微小的PrivilegedAccessor框架。虽然建议仅在单元测试中使用它,但在您的情况下可能会有用。