Accessing Instance Variables from Another Class - java

If you want to get straight to the problem, skip this paragraph. As practice, I am trying to write a Java program that simulates an economy, and to that end wrote a company class. The idea was to have, say, a dozen of them, wrap their earnings into a normalvariate function, and that would be the economy.
I wrote a separate class to graph the companies' outputs using JFreeChart. However, I can't access the ArrayList that I write the amount of money for each year to from the graphing class. I understand the best way to do this is probably with getters, but it didn't seem to work, so if that is your advice, could you please provide an example? Thanks!
The company:
public class ServiceProvider implements Company {
//Variables
public ArrayList getRecords(){
return records;
}
public ServiceProvider(){
money = 10000;
yearID = 0;
goodYears = 0;badYears = 0;
records = new ArrayList();
id++;
}
public void year() {
yearID++;
if(!getBankrupt()){
spend();
}
writeRecords();
}
public void spend() {
...
}
public void printRecords() {
for(int i=0;i<records.size();i++){
String[] tmp = (String[]) records.get(i);
for(String a:tmp){
System.out.print(a+" ");
}
System.out.print("\n");
}
}
public void writeRecords(){
String[] toWrite = new String[2];
toWrite[0] = String.valueOf(yearID);
toWrite[1] = String.valueOf(money);
records.add(toWrite);
}
public void writeRecords(String toWrite){
String temp = "\n"+yearID+" "+toWrite;
records.add(temp);
}
public boolean getBankrupt(){
boolean result = (money < 0) ? true : false;
return result;
}
}
What I am trying to access it from:
public class grapher extends JFrame {
ArrayList records = s.getRecords();
public grapher(){
super("ServiceProvider");
final XYDataset dataset = getCompanyData();
}
private XYDataset getCompanyData(){
XYSeries series;
for(int i=0;i<s.getRecords().length;i++){ //S cannot be resolved, it's instantiated in the main class.
}
}
}
The main class:
public class start {
public static void main(String[] args) {
ServiceProvider s = new ServiceProvider();
for(int i=0;i<10;i++){
s.year();
}
s.printRecords();
}
}
P.S. Don't tell me what a mess Records are. I know.

Pass the instance of ServiceProvider as an argument to the grapher constructor and then it can pass it as an argument to getCompanyData().
Since the instance is created outside of the grapher class, there is no way for grapher to have the instance of ServiceProvider to work with unless you hand that instance to grapher.
BTW, make sure that whatever you do with that ArrayList in grapher that you don't change it. If you do, you'll be changing it in the ServiceProvider (since it's all just references to the same underlying ArrayList). That's probably not what you want to do. If you do need to change it, make a copy and work with the copy.

Your grapher class is trying to use a variable from the start class(you are making calls to variable s which exists in the start class), without having a reference to the variable. In order for grapher to access that instance, you'll have to pass it in to the grapher class as a paramater in the constructor:
public grapher(ServiceProvider serviceProvider) {
records = serviceProvider.getRecords();
}
In the getCompanyData method, use your class variable records instead of s.

Your grapher class should be as follows
public class grapher extends JFrame {
public grapher(ServiceProvider s){
super("ServiceProvider");
final XYDataset dataset = getCompanyData(s);
}
private XYDataset getCompanyData(ServiceProvider s){
XYSeries series;
for(int i=0;i<s.getRecords().length;i++){
// Do Process of business logic.
}
}
}

Related

Cannot find Symbol error in Java - why?

I am having a hard time understanding the object oriented world. I am working on a homework assignment and I can't understand why I am getting an error here. The issue I am having is in the add method. I am using the Netbeans IDE (per professor requirement) and the problem I am getting is in the add method. There are two errors that both say "Cannot find Symbol"; one is in reference to the variable customers while the other is in reference to the variable numCustomer. I am trying to understand what I am doing wrong, not just how to fix it.
What I have so far:
package homework6;
/**
*
* #author christian
*/
public class Homework6 {
// Declare variables
private int numCustomers = 0;
private Customer customer;
// Constructor
public Homework6() {
Customer[] customers = new Customer[50];
}
/**
* #param args the command line arguments
*/
public void main(String[] args) {
System.out.println("Christian Beckman N00963294");
System.out.println("Homework 6");
System.out.println(); // Prints a blank line
// Create and instance of Homework6
Homework6 homework6 = new Homework6();
homework6.execute(args);
}
private void add(Customer customer) {
int i = 0;
customers[i] = customer;
i++;
numCustomer++;
}
private void displayCustomers() {
}
private void execute(String[] args) {
}
private int getTotal() {
}
private void readFile(String filename) {
}
}
Your variable is numCustomers with an 's' but your method refers to numCustomer++; without an 's'.
It should be:
numCustomers++;
For
private Customer customer;
it should probably be:
private Customer[] customers;
Be very careful in your code where you refer to customer and customers. It looks like you are using the convention "customer" for just one and "customers" for the array. If that is too subtle for you then consider changing to something like oneCustomer and allCustomers.
You create an array of Customer objects in the constructor, then the array is immediately destroyed. Try declaring it like this:
public class Homework6 {
// Declare variables
private int numCustomers = 0;
private int i = 0;
private Customer customer;
private Customer[] customers;
// Constructor
public Homework6() {
customers = new Customer[50];
}
...
The reason for this, is any variables declared inside a method (in this case, the constructor) has something called local scope which means it can ONLY be accessed inside that method. The variables you declare outside the methods have something called global scope, which means that variable can be accessed across all the methods in a class.
For the same reason as above, i will keep resetting to 0 each time you call the add function. To fix that, declare private int i = 0 above the constructor with the other variables. Then write the method like so:
private void add(Customer customer) {
customers[i] = customer;
i++;
numCustomers++;
}
Also, whenever you do numCustomer++ in the add method, you should put numCustomers++ like above because you declared numCustomers with an 's' at the end. Has to match EXACTLY.

Quick ask : function that prints array of cells - should it be inside my cell class definition?

public class cell{
String name ;
float value ;
public cell(){.....}
public float getValue(){......}
public String getName(){........}
public void printCell(){
// print name/value bla bla.....
}
}
public class Cell_test{
public void print_array_cells(cell[][]toprint){
for(int i = 0 ; i < toprint.length; i++){
printcell(toprint) // just code
}
}
public static void main....{
cell monkey_dna = new cell() ;
cell man_dna = new cell() ;
cell hen_dna = new cell() ;
cell []humanoids = {monkey_dna,man_dna, hen_dna} ;
print_array_cells(humanoids) ;
}
}
i want to have a function that does printing of array of cells.
Question:
should i put it into class cell def-n?
can i put it there? or must it be inside my test class?
if yes, what if i need it outside of test class?
logically, it is better to have all functions who deal with cell data be made / defined inside cell class?
logically, it is better to have all functions who deal with cell data
be made / defined inside cell class?
Generally, yes. You don't want to expose the members of a class, even via getters etc. If you do, do it in a fashion that allows you to change the implementation without having to change the API.
For your particular question, I would add the method to render your cell class within the class. However I would perhaps write it to take an OutputStream or Writer such that it can write to a generic destination, rather than specifically to stdout or stderr.
e.g.
cell.outputTo(outputstream);
I would then follow this pattern through to your Cell array. I would perhaps have a class representing this Cell array (call it a Culture, perhaps?) and that would be responsible for maintaining the underlying array (or whatever you choose your underlying collection to be implemented as), asserting the structure, contents etc. Otherwise you'll have a collection within your solution that can't assert such things centrally.
Creat a CellManagement class which contains your print function and the array and functions like addCell(), removeCell(). In your test class you can creat a instance of your CellManagement and you didnt need any instance of a cell there. So your Cell is the DataAccess Layer, your CellManagement is the Buisiness Layer and the class where you get an instance of CellManagement is your Controller. You should only have one instance of CellManagement, but if you need a function of this class anywhere else you can creat another instance.
Example:
public class Cell{
private String name ;
private float value ;
public Cell(){.....}
public float getValue(){......}
public String getName(){........}
//if possible only getters and setter here
}
}
public class CellManagement{
//hold the array here and access it via getter
private Cell[] humanoids;
public CellManagement() {
Cell monkey_dna = new Cell();
Cell man_dna = new Cell();
Cell hen_dna = new Cell();
humanoids = {monkey_dna,man_dna, hen_dna}
}
public void print_array_cells(){
for(int i = 0 ; i < humanoids.length; i++){
printcell(humanoids) // just code
}
}
//add and remove functions..
}
public static void main....{
CellManagement cm = new CellManagement();
cm.print_array_cells() ;
}
}
Usually you put methods dealing with an object's internal state inside its class definition.
If you have a utility method for dealing with related stuff and you don't know where to put it, you can make it a static method inside the class.
You should make service class and put all the functions that perform some task or calculation... cell class should only contain getter and setter method only
logically, it is better to have all functions who deal with cell data be made / defined inside cell class?
Sometimes, but sometimes it's better to split data and logic. For example, in java we don't have Integer#print(PrintWriter p) or even Integer#max(Integer otherInt). When you split your class to Data and Logic/Functions you can add new logic/functions without changing the existing classes, you really just "add" new code.
There is a nice way to separate Data from Functions - the Visitor pattern. The following is an example for your case:
define a class Row which contains array of Cell
define CellVisitor interface
define RowVisitor interface, which extends CellVisitor
implement RowVisitor by RowPrinter class
public interface CellVisitor {
void onCell(Cell cell);
}
public interface RowVisitor extends CellVisitor {
void onRowStarted(Row row);
void onRowFinished(Row row);
}
public class Cell {
private String name;
private float value;
public void visit(CellVisitor visitor) {
visitor.onCell(this);
}
public String getName() {
return name;
}
public float getValue() {
return value;
}
}
public class Row {
private Cell[] cells;
public void visit(RowVisitor visitor) {
visitor.onRowStarted(this);
for (Cell c : cells) {
c.visit(visitor);
}
visitor.onRowFinished(this);
}
}
And now the printer:
public class RowPrinter implements RowVisitor {
private final StringBuilder text = new StringBuilder();
private int cellCnt;
#Override
public void onRowStarted(Row row) {
cellCnt = 0;
text.setLength(0);
text.append('[');
}
#Override
public void onCell(Cell cell) {
if (cellCnt > 0) {
text.append(',');
}
text.append(cell.getName())
.append(':')
.append(cell.getValue());
cellCnt++;
}
#Override
public void onRowFinished(Row row) {
text.append(']');
System.out.println(text.toString());
}
}
Or any other useful visitor/function (CSV printer to file, sum of values, total count of cells, etc.)
Row row = ...
row.visit(new RowPrinter()); // print the row
Also, note, even if you distribute such API in binaries, any client will be able to add his own function in very gracefully way.

Using the enhanced for loop with interfaces in Java?

I am trying to better my understanding Java interfaces and have the following problem with some very basic, code.
The following creates two classes which implement the same interface. I then create two ArrayLists to hold objects of these two classes. I then want to create a single enhanced-for loop which goes through each list and performs the method originally defined in the interface.
I thought that i could use a loop which instead of taking in a specific class type as its parameter could use an Interface type instead, This would then allow me to use any class which implements that interface, but it seems i have made mistake.
How would i go about creating a for loop which allowed only classes which implement an interface to be operated on?
interface Valueing{
double getValue();
}
class Coin implements Valueing
{
private double coinVal = 0.0;
Coin(double initVal){
coinVal = initVal;
}
public double getValue(){
return this.coinVal;
}
}
class Note implements Valueing
{
private int noteVal = 0;
Note(int initVal){
noteVal = initVal;
}
public double getValue(){
return (double)noteVal;
}
}
public class IFaceBasics{
public static void main(String[] args){
ArrayList<Coin> myChange = new ArrayList<Coin>();
myChange.add(new Coin(0.01));
double totalChange = sumValues(myChange);
ArrayList<Note> myNotes = new ArrayList<Note>();
myNotes.add(new Note(5));
double totalNotes = sumValues(myNotes);
}
public double sumValues(ArrayList<Valueing> a){
double totalSum = 0;
for(Valueing avg : a)
{
totalSum += avg.getAverage();
}
return totalSum;
}
}
Thanks for any feedback.
You've almost got it right, you'd just need to change
public double sumValues(ArrayList<Valueing> a){
to
public double sumValues(ArrayList<? extends Valueing> a){
<? extends Valueing> means "Valueing or any of its sub-types", so this would let the method accept an ArrayList<Coin> or ArrayList<Note> as well as ArrayList<Valueing>.

Get a variable from a different class

So I'm trying to cut back on some of the code that's been written. I created a separate class to try this. I have that class working correctly, however the old one uses variables that are now in the separate class. How do I access these variables? Unfortunately I can't share all the code for this, but I can give out small pieces that I think are necessary. Thanks for the help
This is from the old class that I am now trying to bring the variable to: I'm trying to bring "loader" over
// XComponentLoader loader = null;
fixture.execute(new OpenOfficeOpener());
component = loader.loadComponentFromURL("file:///"+System.getenv("BONDER_ROOT") + "/ControlledFiles/CommonFiles/"+spreadsheet, "_blank", 0, loadProps);
You can write getters for the members that you need to be visible outside. Example:
public class MyClass {
private int member1;
private String member2;
public int getMember1() {
return member1;
}
public String getMember2() {
return member2;
}
}
Now both member1 and member2 can be accessed from the outside.
There are a couple of solutions to your problem. What I would suggest is to add a method in your class to return the value to the new program, or pass it as a parameter.
An example of this on a higher level might look like this:
x = newClass.getValX()
It sounds like you're looking for a static field, though if is the case you almost certainly reconsider your current design.
public class YourClass {
private static XComponentLoader loader;
public YourClass() {
YourClass.loader = new XComponentLoader();
}
}
And to access it from another class:
public YourOtherClass {
public void yourMethod() {
YourClass.loader ...
}
}
If loader is static, than do something like:
component = TheOtherClass.loader.loadComponentFromURL( ...
Otherwise, your new class needs a reference to an instance of the other class. You could pass it with the constructor:
public class NewClass {
private OldClass oldClass = null;
public NewClass(OldClass oldClass) {
this.oldClass = oldClass;
}
// ...
fixture.execute(new OpenOfficeOpener());
// assuming, loader is a public field on OldClass.
// a getter (getLoader()) is preferred
component = oldClass.loader.loadComponentFromURL("file:///"+System.getenv("BONDER_ROOT") + "/ControlledFiles/CommonFiles/"+spreadsheet, "_blank", 0, loadProps);
// ...
}
I've you've split functionality into two classes, then you may want to have one class instantiate another.
If you've put your new code in Class B then it might look like this.
public class A {
// Class B instance
B b = new B();
public void doSomething() {
b.loadComponentFromURL("someurl");
}
}
Or if the loader is an instance itself, you could call it like this.
b.getLoader().loadComponentFromURL("someurl");

How to create Array of Objects for Class with Multiple Parameters and Access objects (and their values) in other classes?

My personal mini project was to learn arrays here, doing a slightly big jump by making an Array of Objects. What I wanted to do was a mini RPG system where I create a class called monster and give it a couple parameters, and create an array of objects of the Monster class. So far I believe I created that Monster class and the Object of Arrays inside the main method class (Exec_Monster) listed below.
It took me a while initially, but I finally got to a point where I can create the array of Monsters and access them inside the Main class. But is there a way for me to create this Array of Objects and access each object from another class (and their individual values)? For Example, I would create a "Battle" class and then I would pull the "Health" value from an object of Monster.
I'm new to Arrays but I have had some experience with classes for the past two weeks here.
Class:
public class Monster
{
public int hp;
public String n;
public Monster(String name,int health){
n=name;
hp=health;
}
public int returnHealth(){
return hp;
}
public String returnName(){
return n;
}
}
Exec_Monster:
public class Exec_Monster{
public static void main(String args[])
{//Define Monsters
Monster[] monsterid=new Monster[]{
new Monster("Goblin",10),
new Monster("Elf", 8),
new Monster("Ant", 3),
new Monster("Worm", 2),
new Monster("Black Widow",6)};
Random chooser;
int chosenmonster=(chooser.nextInt()*5);
//Start
//while (Battle.wonloss==true) {
// Battle.battle();
}
}
You'd need to pass the monsters into the Battle object somehow (or into another object that you pass into the Battle object). You could pass it as an argument to a method, but in an Object Oriented world, if the monsters really belong to a battle, you could pass them in the constructor and make them available in all the methods of the Battle class.
Example:
public class Battle {
private Monster[] monsters;
private boolean wonloss;
public Battle(Monster[] monsters) {
this.monsters = monsters;
}
public boolean isWonloss() {
return wonloss;
}
public void battle() {
// Do something with monsters,
// and then check if there is any life left in the monsters
int totalHp = 0;
for (Monster monster : monsters) {
totalHp += monster.hp;
}
if (totalHp == 0) {
wonloss = false;
}
}
}
The "battle" part of your main method would then look like:
// Start
Battle battle = new Battle(monsterid);
while (battle.isWonloss()) {
battle.battle();
}

Categories

Resources