Link to home
Start Free TrialLog in
Avatar of dazedandconfused69
dazedandconfused69

asked on

accessing private variables from a class within a class

This is a HW assignment.  I am not looking for the answers directly.  This class like most builds on the earlier assignment so if I don't get these concepts down, I am doomed.  

InventorySet. java:

package shop.data;

import VideoObj;
import shop.data.Record;

import java.util.Map;
import java.util.HashMap;
import java.util.Comparator;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

/**
* Implementation of Inventory interface.
* @see Data
*/
final class InventorySet implements Inventory {
 // Chose to use Map of Record, rather than RecordObj, because of
 // Java's broken generic types.  The story is too sad to retell, but
 // involves the fact that Iterable<? extends Record> is not a valid
 // type, and that Iterator<RecordObj> is not a subtype of
 // Iterator<Record>.
 //
 // Seems like the best approach for Java generics is to use the
 // external representation internally and downcast when necessary.
 private final Map<Video,Record> _data;

 InventorySet() {
   _data = new HashMap<Video,Record>();
 }

 public int size() {
   // TODO
   return _data.size();
 }

 public Record get(Video v) {
   // TODO
      Record r = _data.get(v);
          if (r == null)
              return null;
          return r;
 }

 public Iterator<Record> iterator() {
   return Collections.unmodifiableCollection(_data.values()).iterator();
 }

 public Iterator<Record> iterator(Comparator<Record> comparator) {
   // TODO
   return null;
 }

 /**
  * Add or remove copies of a video from the inventory.
  * If a video record is not already present (and change is
  * positive), a record is created.
  * If a record is already present, <code>numOwned</code> is
  * modified using <code>change</code>.
  * If <code>change</code> brings the number of copies to be zero,
  * the record is removed from the inventory.
  * @param video the video to be added.
  * @param change the number of copies to add (or remove if negative).
  * @throws IllegalArgumentException if video null, change is zero, if attempting to remove more copies than are owned, or if attempting to remove copies that are checked out.
  */
 void addNumOwned(Video video, int change) {
   // TODO
        if (video == null || change == 0)
              throw new IllegalArgumentException();
            
            Record r = _data.get(video);
            if (r == null && change < 1) {
              throw new IllegalArgumentException();
            } else if (r == null) {
              _data.put(video, new Record(video, change, 0, 0));
            } else if (r.numOwned+change < r.numOut) {
              throw new IllegalArgumentException();
            } else if (r.numOwned+change < 1) {
              _data.remove(video);
            } else {
              r.numOwned += change;
            }
          }
 

 /**
  * Check out a video.
  * @param video the video to be checked out.
  * @throws IllegalArgumentException if video has no record or numOut
  * equals numOwned.
  */
 void checkOut(Video video) {
   // TODO
        Record r = _data.get(video);
        if (r == null || r.numOut == r.numOwned)
          throw new IllegalArgumentException();
        r.numOut++;
        r.numRentals++;
      }
 
 
 /**
  * Check in a video.
  * @param video the video to be checked in.
  * @throws IllegalArgumentException if video has no record or numOut
  * non-positive.
  */
 void checkIn(Video video) {
   // TODO
      public void checkIn(VideoObj video) {
            Record r = _data.get(video);
            if (r == null || r.numOut == 0)
              throw new IllegalArgumentException();
            r.numOut--;
          }
 
 
 /**
  * Remove all records from the inventory.
  */
 void clear() {
   // TODO
        _data.clear();
      }

 public String toString() {
   StringBuilder buffer = new StringBuilder();
   buffer.append("Database:\n");
   for (Record r : _data.values()) {
     buffer.append("  ");
     buffer.append(r);
     buffer.append("\n");
   }
   return buffer.toString();
 }


 /**
  * Implementation of Record interface.
  *
  * <p>This is a utility class for Inventory.  Fields are mutable and
  * package-private.</p>
  *
  * <p><b>Class Invariant:</b> No two instances may reference the same Video.</p>
  *
  * @see Record
  */
 private static final class RecordObj implements Record {
   Video video; // the video
   int numOwned;   // copies owned
   int numOut;     // copies currently rented
   int numRentals; // total times video has been rented
   
   RecordObj(Video video, int numOwned, int numOut, int numRentals) {
     this.video = video;
     this.numOwned = numOwned;
     this.numOut = numOut;
     this.numRentals = numRentals;
   }
   public Video video() {
     return video;
   }
   public int numOwned() {
     return numOwned;
   }
   public int numOut() {
     return numOut;
   }
   public int numRentals() {
     return numRentals;
   }
   public String toString() {
     StringBuilder buffer = new StringBuilder();
     buffer.append(video);
     buffer.append(" [");
     buffer.append(numOwned);
     buffer.append(",");
     buffer.append(numOut);
     buffer.append(",");
     buffer.append(numRentals);
     buffer.append("]");
     return buffer.toString();
   }
 }
}

Open in new window


I am getting several errors in my IDE regarding variables in the Record utility class (which is within InventorySet.java.  It doesn't seem to be able to access any of those variables (yes, I realize they are private) but I assumed (obviously incorrectly) that they could be accessed since they were in the same class.  In particular, the ones I cannot access are:

numOut
numRentals
numOwned

It is also telling me I cannot instantiate a new Record object.  I have pasted the Record class below as well for reference:

package shop.data;

/**
* <p>Public view of an inventory record.</p>
*
* <p>Records are mutable, but cannot be changed outside the package.</p>
*
* <p>This interface should not be implemented outside the package.</p>
*
* <p><code>equals</code> and <code>hashCode</code> delegate to the
* underlying Video object.</p>
* @see Data
*/
public interface Record {
 /**
  * Returns the video.
  * <p><b>Invariant:</b> <code>video() != null</code>.</p>
  */
 public Video video();
 /**
  * Returns the number of copies of the video that are in the inventory.
  * <p><b>Invariant:</b> <code>numOwned() > 0</code>.</p>
  */
 public int numOwned();
 /**
  * Returns the number of copies of the video that are currently checked out.
  * <p><b>Invariant:</b> <code>numOut() <= numOwned()</code>.</p>
  */
 public int numOut();
 /**
  * Returns the total number of times this video has ever been checked out.
  * <p><b>Invariant:</b> <code>numRentals() >= numOut()</code>.</p>
  */
 public int numRentals();
 /**
  *  Return a string representation of the object in the following format:
  * <code>"video [numOwned,numOut,numRentals]"</code>.
  */
 public String toString();
}

Open in new window

Avatar of krakatoa
krakatoa
Flag of United Kingdom of Great Britain and Northern Ireland image

When you get errors or exceptions, it makes things easier here if you post them.
Avatar of dazedandconfused69
dazedandconfused69

ASKER

For each of the variables:
numOut
numRentals
numOwned

 , the error is "<variable> cannot be resolved or is not a field.

For the instantiation issue, the error is "Cannot instantiate the type Record"
By which I meant the stack trace or the compiler errors.
I do not have a stack trace because it will not compile with these current errors and warnings.  My previous comment does include the errors and warnings I am seeing in the IDE. If you're looking for something else I am not sure what you mean.
If it won't compile, then cut and paste the errors.
Description    Resource    Path    Location    Type
numRentals cannot be resolved or is not a field    InventorySet.java    /hw-02/src/shop/data    line 99    Java Problem
numOwned cannot be resolved or is not a field    InventorySet.java    /hw-02/src/shop/data    line 96    Java Problem
numOut cannot be resolved or is not a field    InventorySet.java    /hw-02/src/shop/data    line 98    Java Problem
numOwned cannot be resolved or is not a field    InventorySet.java    /hw-02/src/shop/data    line 82    Java Problem
numOut cannot be resolved or is not a field    InventorySet.java    /hw-02/src/shop/data    line 96    Java Problem
numOut cannot be resolved or is not a field    InventorySet.java    /hw-02/src/shop/data    line 77    Java Problem
numOwned cannot be resolved or is not a field    InventorySet.java    /hw-02/src/shop/data    line 79    Java Problem
Cannot instantiate the type Record    InventorySet.java    /hw-02/src/shop/data    line 76    Java Problem
numOwned cannot be resolved or is not a field    InventorySet.java    /hw-02/src/shop/data    line 77    Java Problem
numOut cannot be resolved or is not a field    InventorySet.java    /hw-02/src/shop/data    line 115    Java Problem
numOut cannot be resolved or is not a field    InventorySet.java    /hw-02/src/shop/data    line 113    Java Problem
So at line 76, shouldn't you be instantiating a RecordObj?
That resolves the error:

"Cannot instantiate the type Record    InventorySet.java    /hw-02/src/shop/data    line 76    Java Problem"

But to honestly answer your question, I believe you are correct but I do not know for sure.  It makes sense to instantiate an object rather than the object's interface so I would say yes?

That still leaves the other errors.
As per the class definition Record is an interface.
In class InventorySet, inside method addNumOwned(Video video, int change) - line no 72, you are trying to instantiate Record interface, which is not correct.

Line no 72:
_data.put(video, new Record(video, change, 0, 0));

It should be
_data.put(video, new RecordObj(video, change, 0, 0));

Because of this you are getting below error:
Cannot instantiate the type Record    InventorySet.java    /hw-02/src/shop/data    line 76    Java Problem

Always keep in mind: you cannot instantiate interface. Interface reference can hold java object reference.

It will be helpful if you can post the Video interface, VideoObj class and Inventory Interface.
If I change line 72 to RecordObj that gets rid of the variable cannot be resolved errors but it creates a new error:

Type mismatch: cannot convert from Record to InventorySet.RecordObj    InventorySet.java    /hw-02/src/shop/data    line 72    Java Problem
No; you want to retrieve the Record object, using the Video as a key. That doesn't appear to be wrong; but line 76 should be a RecordObj, which implements the Record interface.
In the code you are trying hold RecordObj object in Record interface reference.
you can always do that, but it will restrict you to use the the variable and methods declare in Record interface. since the variable numOut, numRentals, numOwned are not present inRecord interface, you can not access those varible through Record interface reference.

try the below example, I think it will help you:
HelloWorld interface:
public interface HelloWorld {
      final int a = 0;
      void abc();

}

HelloWorldImpl class
public class HelloWorldImpl implements HelloWorld{

      int b;
      
      @Override
      public void abc() {
            // TODO Auto-generated method stub
            
      }

      public static void main(String[] args) {
            HelloWorld h = new HelloWorldImpl();
            System.out.println("h.a : "+h.a);
            System.out.println("h.b : "+h.b);
      }
}

Here you will get error saying "h.b cannot be resolved or is not a field"
since variable "b" is not declare in Interface, but you can always access variable "a" through interface reference "h".
Yats:
You say "since the variable numOut, numRentals, numOwned are not present inRecord interface, you can not access those varible through Record interface reference."  In the Record interface (pasted below) the variables are present.  

package shop.data;

/**
 * <p>Public view of an inventory record.</p>
 *
 * <p>Records are mutable, but cannot be changed outside the package.</p>
 * 
 * <p>This interface should not be implemented outside the package.</p>
 * 
 * <p><code>equals</code> and <code>hashCode</code> delegate to the
 * underlying Video object.</p>
 * @see Data
 */
public interface Record {
  /**
   * Returns the video.
   * <p><b>Invariant:</b> <code>video() != null</code>.</p>
   */
  public Video video();
  /**
   * Returns the number of copies of the video that are in the inventory.
   * <p><b>Invariant:</b> <code>numOwned() > 0</code>.</p>
   */
  public int numOwned();
  /**
   * Returns the number of copies of the video that are currently checked out.
   * <p><b>Invariant:</b> <code>numOut() <= numOwned()</code>.</p>
   */
  public int numOut();
  /**
   * Returns the total number of times this video has ever been checked out.
   * <p><b>Invariant:</b> <code>numRentals() >= numOut()</code>.</p>
   */
  public int numRentals();
  /**
   *  Return a string representation of the object in the following format:
   * <code>"video [numOwned,numOut,numRentals]"</code>.
   */
  public String toString();
}

Open in new window

To take a snippet of InventorySet class

  void addNumOwned(Video video, int change) {
    // TODO
	    if (video == null || change == 0)
		      throw new IllegalArgumentException();
		    
		    Record r = _data.get(video);
		    if (r == null && change < 1) {
		      throw new IllegalArgumentException();
		    } else if (r == null) {
		      _data.put(video, new RecordObj(video, change, 0, 0));
		    } else if (r.numOwned+change < r.numOut) {
		      throw new IllegalArgumentException();
		    } else if (r.numOwned+change < 1) {
		      _data.remove(video);
		    } else {
		      r.numOwned += change;
		    }
		  }

Open in new window


I have modified Record to RecordObj but I am still confused why it will not resolve numOwned or numOut.  Is it as simple as importing the Record interface? Or is that implied in the first line (149) of the RecordObj class:

"private static final class RecordObj implements Record {"
You are defining the methods in the Record interface not the variables.
Change the code from
r.numOwned+change < r.numOut

to
r.numOwned()+change < r.numOut()
you will again face problem while updating the variable. To resolve this you can create the setter method's in Record interface as well as in the RecordObj class and instead of assigning the value you can update the variable value using setter method

You can add the below four methods to Record interface:
 public Video setVideo(Video video);
 public int setNumOwned(int numOwned);
 public int setNumOut(int numOut);
 public int setNumRentals(int numRentals);
 
and the below four methods to RecordObj class:
public Video setVideo(Video video){
      this.video = video;
}
public int setNumOwned(int numOwned){
      this.numOwned = numOwned;
}
public int setNumOut(int numOut){
      this.numOut = numOut;
}
public int setNumRentals(int numRentals){
      this.numRentals = numRentals;
}
 

Replace your method addNumOwned with the below method:
void addNumOwned(Video video, int change) {
      // TODO
     if (video == null || change == 0)
      throw new IllegalArgumentException();
   
    Record r = _data.get(video);
    if (r == null && change < 1) {
      throw new IllegalArgumentException();
    } else if (r == null) {
      _data.put(video, new RecordObj(video, change, 0, 0));
    } else if (r.numOwned()+change < r.numOut()) {
      throw new IllegalArgumentException();
    } else if (r.numOwned()+change < 1) {
      _data.remove(video);
    } else {
      r.setNumOwned(r.numOwned() +change);
    }
}
I am not looking for the answers directly.

!
But as far as I understand the assignment, I am only to modify the sections marked "TODO".  The record interface has none of those sections so I wonder if adding setters to that class is expected.

By adding ( ) to numOut, numOwned and numRentals, what is happening conceptually?  Does that ( ) act as a getter to these variables inside the private class RecordObj?  

Are setters required to get the ( ) solution to work?

What is the conceptual difference between the following two code snippets:

Snippet A:

    Record r = _data.get(video);
    if (r == null && change < 1) {
      throw new IllegalArgumentException();
    } else if (r == null) {
      _data.put(video, new RecordObj(video, change, 0, 0));
    } else if (r.numOwned()+change < r.numOut()) {
      throw new IllegalArgumentException();
    } else if (r.numOwned()+change < 1) {
      _data.remove(video);
    } else {
      r.setNumOwned(r.numOwned() +change);
    }
}

Open in new window


Snippet B:

  void addNumOwned(Video video, int change) {
    // TODO
	    if (video == null || change == 0)
		      throw new IllegalArgumentException();
		    
		    RecordObj r = _data.get(video);
		    if (r == null && change < 1) {
		      throw new IllegalArgumentException();
		    } else if (r == null) {
		      _data.put(video, new RecordObj(video, change, 0, 0));
		    } else if (r.numOwned+change < r.numOut) {
		      throw new IllegalArgumentException();
		    } else if (r.numOwned+change < 1) {
		      _data.remove(video);
		    } else {
		      r.numOwned += change;
		    }
		  }

Open in new window


In snippet B , I am getting the following error:


Description      Resource      Path      Location      Type
Type mismatch: cannot convert from Record to InventorySet.RecordObj      InventorySet.java      /hw-02/src/shop/data      line 72      Java Problem

I do not know if I should be splitting these follow-up questions into a different question(s).  I am happy to do so - I want to follow proper protocol.
SOLUTION
Avatar of krakatoa
krakatoa
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial