2015-02-07 75 views
0

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

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

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

    } 
} 

这实际上是我尝试使用反射来改变筒仓实例状态值的地方。在此之下,请遵循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();   
    } 
} 

这里是筒仓类。

public class Silo { 

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

} 

除了找出我如何可以访问仓的状态变量,我会很感激,我怎么能组织我的工作做得更好任何反馈和/或建议,对任何错误,我可能已经取得。

回答

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

更重要的是,获得在构造函数的索引,并将其存储,这样你就不必每次都重新计算。

*当然,这仅仅是一个建议

+0

这当然比我的配置更好。我缺乏的是关于何时使用某种方法的理论知识。我一直在学习编程,而这种差异很难发现。任何想法在哪里我可以学习这样的基础知识? 顺便说一句,谢谢你的答案。它完全解决了我的问题,以及更多的问题! – SiGm4 2015-02-07 12:40:49

+0

哦,为什么使用私人领域和公共getters和setters更好的做法? :P – SiGm4 2015-02-07 12:45:39

+0

你应该看看一个很好的教程。当然,实际的课程总是更好,但在线也是可行的。 Oracle在这里有他们自己的一套教程:http://docs.oracle.com/javase/tutorial/至于为什么使用getters和setters更好:这是惯例。它提供了一种让其他使用你的代码的人看到他们应该访问/更改哪些字段,以及哪些字段是内部的,供你使用的方法。 – DennisW 2015-02-07 12:48:46

0

此:"silo"+label.split("")[1]将创建StringsiloS。 要从label变量尝试获得数:label.substring(1,2)

你也不必通过Frame fmyValveButton构造,可以按键直接在SimHandler使用this.add(but0)添加到框架。

0

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

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

无论如何 - 如果你真的需要去使用反射解决方案,我会推荐使用微小的PrivilegedAccessor框架。尽管建议仅在单元测试中使用,但对您的情况可能会有用。

+0

你的意思是SimHandler应该实施的ActionListener,然后一的actionPerformed在SimHandler应该做肮脏的工作? – SiGm4 2015-02-07 12:12:07

+0

是的 - 像WindowListener在SimHandler中作为匿名内部类一样实现。 – Sebastian 2015-02-08 16:35:25