2015-02-07 78 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

相關問題