Hi everyone i am trying to use the attributes in my Fish class which implements an an interface called Catchable , in my Fisher class , is this possible, or is there some part of interfaces that I am not understanding. Because i thought we were allowed to use the attributes in a class that has been implemented by an interface, in another class, however i keep errors saying:
Error: cannot find symbol
symbol: variable weight
location: variable item of type Catchable
Error: cannot find symbol
symbol: variable size
location: variable item of type Catchable
Error: cannot find symbol
symbol: variable weight
location: variable item of type Catchable .
Any help or advice on this is appreciated!
If needed, here is my Catchable interface:
public interface Catchable
{
public float getWeight();
public boolean isDesirableTo(Fisher f);
}
my Fish class which implements the Catchable interface
public abstract class Fish implements Catchable
{
// Any fish below this size must be thrown back into the lake
public static int THROW_BACK_SIZE = 18;
public static float WEIGHT_LIMIT = 10;
protected float weight;
protected int size;
public Fish(int aSize, float aWeight)
{
size = aSize;
weight = aWeight;
}
public boolean isDesirableTo(Fisher f)
{
if(canKeep() && f.numThingsCaught < f.LIMIT && this.weight + f.sumOfWeight < WEIGHT_LIMIT)
{
return true;
}
else
{
return false;
}
}
public abstract boolean canKeep();
public int getSize() { return size; }
public float getWeight() { return weight; }
public String toString ()
{
return ("A " + size + "cm " + weight + "kg " + this.getClass().getSimpleName());
}
}
and lastly my Fisher class
import java.util.*;
public class Fisher
{
private String name;
private Catchable [] thingCaught;
public int numThingsCaught;
private int keepSize;
public float sumOfWeight;
public static int LIMIT = 10;
public String getName()
{
return this.name;
}
public int getNumThingsCaught()
{
return this.numThingsCaught;
}
public int getKeepSize()
{
return this.keepSize;
}
public Fisher(String n, int k)
{
name = n;
keepSize = k;
}
public String toString()
{
return(this.name + " with " + this.numThingsCaught + " fish");
}
private ArrayList<Catchable> thingsCaught = new ArrayList<Catchable>();
public void keep(Catchable item)
{
if(this.numThingsCaught < LIMIT)
{
thingsCaught.add(item);
numThingsCaught++;
sumOfWeight += item.weight;
}
}
public boolean likes(Catchable item)
{
if(item.size >= this.keepSize)
{
return true;
}
else
{
return false;
}
}
public void listThingsCaught()
{
System.out.println(this.toString());
for(Catchable item : thingsCaught)
{
System.out.println(item.toString());
}
}
public void goFishingIn(Lake lake)
{
Catchable item = lake.catchSomething();
if(likes(item))
{
this.keep(item);
}
else
{
lake.add(item);
}
}
public void giveAwayFish(Fisher fisher, Lake lake)
{
for(Catchable item : thingsCaught)
{
if(fisher.likes(item))
{
fisher.keep(item);
}
else
{
lake.add(item);
}
sumOfWeight -= item.weight;
}
thingsCaught.clear();
this.numThingsCaught = 0;
}
}
The problem are the following lines:
keep():
sumOfWeight += item.weight;
likes():
if(item.size >= this.keepSize)
giveAwayFish():
sumOfWeight -= item.weight;
In every case, item is of type Catchable, and Catchable doesn't have size or weightfields. What you have to do is call item.getWeight() instead of item.weight and add a getSize() method to Catchable, and call item.getSize() instead of item.size:
Catchable:
public interface Catchable
{
public float getWeight();
public int getSize();
public boolean isDesirableTo(Fisher f);
}
keep():
sumOfWeight += item.getWeight();
likes():
if(item.getSize() >= this.keepSize)
giveAwayFish():
sumOfWeight -= item.getWeight();
You don't have to modify Fish, as it already implements getSize().
And you should really use an IDE like Eclipse, because it can show you where your errors are in real time.
Not every Catchable is a Fish, so, for example
public boolean likes(Catchable item)
{
if(item.size >= this.keepSize)
...
will fail, because Catchable doesn't have a size member (it also can't have member variables because it's an interface). item is Catchable here, it's not fish.
When you're using an interface, you should only interact with the instance through the methods defined in the interface (or in interfaces that it extends).
In Java we usually call them "fields" not "attributes".
Anyways, there are a couple of issue. First, you declare weight (for example) as protected in Fish. This is the right thing to do here, but it means that weight is not accessible outside of Fish. So you would have to do this from a class outside of Fish:
void example (Fish fish) {
// System.out.println(fish.weight); // <- not allowed, weight is protected
System.out.println(fish.getWeight()); // <- ok, getWeight() is public
}
That's the point of providing a public getter like getWeight() in the Catchable interface in the first place (that and the fact that interfaces can't have non-static non-final member fields). The underlying implementation is hidden -- an object that implements Catchable might not have a weight field at all and might calculate a return value based on some completely different set of rules. But it doesn't matter, because you access it through getWeight().
Secondly, the above doesn't make sense for a general Catchable anyways even if Fish.weight was public; Catchable does not have a field named weight. Fish does. So if you are accessing it through a reference of type Catchable, there's no weight anyways.
You do provide Catchable.getWeight(), however. That method is present in all Catchable types. So you would have to use that to access weight. So in your Fisher you could do:
void example (Catchable catchable) {
// System.out.println(catchable.weight); // <- not allowed, Catchable has no weight
System.out.println(catchable.getWeight()); // <- ok, getWeight() is public and is in Catchable
}
I highly suggest working through the official Interfaces and Inheritance tutorial. It may familiarize you with a few of the concepts you are asking about.
Added:
It seems like you have a background in C# or another language with a similar concept of "attributes" - where you provide a getter/setter but syntactically you still refer to it directly by the attribute name (e.g. fish.weight = 3 calls fish.setWeight(3) automatically).
This construct does not exist in Java. You can write getters/setters as member methods, and you call them, and that's all you get. There is no automatic calling of getters/setters on direct field access. You can have this:
class Example {
public int field;
public void setSomething (int x) { ... }
public int getSomething () { ... }
}
And that's what you get. From that you can do this:
Example x = ...;
x.field = ...;
... = x.field;
x.setSomething(...);
... = x.getSomething();
But you cannot automatically do anything like this:
x.setField(...);
... = x.getField();
x.something = ...;
... = x.something;
So if you have a background in a language like that, that could be the source of your confusion. You will need to adjust. In Java you have to explicit; the language is noteworthy for its low amount of ambiguity and redundancy.
I see this dotted about in your code:
sumOfWeight += item.weight;
Slow down a moment here - you're not using a concrete instance of a class; you're referring to the interface instead. You'll observe that the interface doesn't have a field for weight, hence your compilation failure.
If you want to adhere to using the interface, then you need to change a few things.
Add a method getWeight() to your interface.
public float getWeight();
Remove the abstract declaration from your Fish class (that will only serve to hurt and confuse you).
Then, when you want to perform that summation operation, you can:
sumOfWeight += item.getWeight();
Related
I am trying to make a simulation that simulates simple creatures and carnivorous creatures.
I have a class called creature and a subclass called carnCreature. I have a method in creature called eat, that takes in a one type of object, but I need the eat method in the carnCreature class to take in a list of creatures. I tried naming the method the same as it is named in the creature class, but when I try to call it, java doesn't accept the updated parameters.
package simulationObjects;
import java.awt.Color;
import java.util.List;
import java.util.Random;
import java.lang.Math.*;
public class Creature {
public int x;
public int y;
public int maxTilesX;
public int maxTilesY;
public Color color;
public float health = 50;
public int life = 0;
public Creature (int x, int y, Color color, int maxTilesX, int maxTilesY) {
this.x = x;
this.y = y;
this.color = color;
this.maxTilesX = maxTilesX;
this.maxTilesY = maxTilesY;
}
public void update(Tile tile) {
eat(tile);
life++;
health-=1;
}
public void eat(Tile currentTile) {
if (currentTile.color == this.color) {
health += 3;
currentTile.color = Color.GRAY;
}
}
public boolean isCarnivore() {
return false;
}
}
package simulationObjects;
import java.awt.Color;
import java.util.List;
public class CarnCreature extends Creature{
private static final boolean CANABOLIC = false;
public CarnCreature(int x, int y, Color color, int maxTilesX, int maxTilesY) {
super(x, y, color, maxTilesX, maxTilesY);
// TODO Auto-generated constructor stub
}
public void update(List<Creature> creatures) {
eat(creatures);
life++;
health-=1;
}
public void eat(List<Creature> creatures) {
for (Creature creature : creatures) {
if (CANABOLIC) {
if (creature.color == this.color) {
health += 3;
creature.health = 0;
}
} else {
if (creature.color == this.color && creature.isCarnivore() == false) {
health += 3;
creature.health = 0;
}
}
}
}
public boolean isCarnivore() {
return true;
}
}
The eat function is being called later like this:
for (Creature creature : creatures) {
if (creature.isCarnivore()) {
creature.upadte(creatures);
} else {
creature.update(tiles.get(creature.x).get(creature.y));
}
}
I am trying to store the creatures and the carnCreatures in the same list, "creatures." Is this the problem, and do I need to store them in separate lists?
Thanks
You have a two options:
Once you know if the creature is carnivore cast it and access the method
Create a method with the same "signature", that is, same name AND arguments.
The second option is the more elegant. Using the "magic" of polymorphism each class will have its method called and you won't need to check the class with the isCarnivore() method. But you will need to get the list of creatures from the tile.
The isCarnivore() test will not spare you to cast to the subclass type as you manipulate as declared type the Creature the base class :
for (Creature creature : creatures) {
if (creature.isCarnivore()) {
((CarnCreature)creature).update(creatures);
} else {
creature.update(tiles.get(creature.x).get(creature.y));
}
}
So the isCarnivore() appear helpless as if (instanceof CarnCreature) would have the same effect and consequences.
Is this the problem, and do I need to store them in separate lists?
It would be better as you don't want manipulate them in an uniform way.
Using the base class to group them in a unique List make your task harder.
But in fact you have a deeper issue. Here eat() is not a overrided method but an overloaded method in the subclass. Same thing for update().
It means that in both cases the two methods are defined in the subclass.
Such a design will not allow to benefit from a polymorphism feature because you want to invoke the first method on the base class instance and invoke the overloaded method on the subclass instance.
In terms of concept, a carnivore creature IS not a creature. Their type of behavior is very different : one consumes a thing (a tile) and the other consumes a very different thing (a list of creature).
To benefit from polymorphism you should re-design the base class and the subclass to override the methods and not overload them. But as you pass really different types in the parameters, you are stuck.
So in your case I think that I would not even create a inheritancy relation between theses classes.
public class Flight{
private int flying = 0;
public boolean fly() {
flying = 1;
return isFlying();
}
private isFlying(){
return flying > 0;
}
}
public class CargoFlight extends Flight{
public boolean startFlight(int passengers)
if (passengers <= 0){
return false;
}
return fly(); // Want to be able to do this
}
}
public class Airport{
public static void main(){
CargoFlight f1 = new CargoFlight();
f1.fly(); // Don't want to be able to do this
}
}
f1 has the property fly(), is there any way to restrict it such that the method fly() can be called inside the body of the classes extending Flight (like CargoFlight here), but cannot be called using the instances of the subclasses (like f1)? I have added comments to the code to make it clear.
The nearest access specifier to what you want is protected. However, protected members are still always accessible to other classes in the same package, so it won't prevent access from your Airport class.
If you really need the subclass to block access to the method except to the subclass, then you can override it in the subclass to always throw an exception, then use super to invoke the original method:
public class Flight {
private int flying = 0;
protected boolean fly() {
flying = 1;
return isFlying();
}
private boolean isFlying() {
return flying > 0;
}
}
public class CargoFlight extends Flight {
#Override
protected boolean fly() {
throw new IllegalAccessError();
}
public boolean startFlight(int passengers) {
if (passengers <= 0) {
throw new IllegalArgumentException();
}
return super.fly();
}
}
The flaw with any solution though, is that it violates the Liskov substitution principle. A CargoFlight is no longer a proper instance of Flight because it doesn't have the normal fly method that other Flights have. If you intend fly only to be called by subclasses and never directly, then it's okay (although you should document that rule in the method Javadoc), but it still leaves you without the nicety of having a polymorphic method to call to tell generic Flights to fly.
A nicer solution, if it can fit with your design, would be to have fly and startFlight be the same method (that means same name and same arguments, and the same return type or a subtype), so then the subclass method could simply override the base implementation. The only method outside callers would see is fly. That means that your passengers argument either needs to be part of the base method Flight.fly too, or, remove it from both method implementations and make it into a separate property setPassengers for those subclasses that need it:
public class CargoFlight extends Flight {
private int passengers = 0;
public void setPassengers(int p) {
passengers = p;
}
#Override
public boolean fly() {
if (passengers <= 0) {
throw new IllegalStateException(); // or whichever
}
return super.fly();
}
}
For an assignment, I have an ArrayList of type "Reference". Reference is a parent class to the "Book" class and "Journal" class. If I am allowed to add objects of type "Book" and "Journal" to the Arraylist, why would I be getting an error if I want to access methods of Book and Journal via the following code?
ArrayList.get([someindex]).someBookorJournalMethod()
The arraylist itself is of the parent class, and the methods I want to access are only defined for either book or either journal.
EDIT: Here is some code
public class Books extends Reference{
private String Authors;
private String Publishers;
public Books(String CallNum, String Author, String Title, String Publisher, int year,String type)
{
super(CallNum,Title,year,type);
Authors= Author;
Publishers=Publisher;
}
public String getAuthor()
{
return Authors;
}
public class LibrarySearch {
private ArrayList<Reference> Library;
public LibrarySearch()
{
Library = new ArrayList<Reference>(100);
}
public outputLibrary(){
for (int i = 0 ; i < Library.size(); i+++)
{
if (Library.get(i).getType().equals("Book"))
{
System.out.println("Type:book\n" + "Call Number:" + Library.get(i).getCallNumber() +"\n" + "Authors:" + Library.get(i).getAuthors();)
}
}
}
IntelliJ is having issues with the line Library.get(i).getAuthors() because it is a method specific to Books. How would I resolve this?
Because when you specify the type of a variable, you can only invoke methods that are defined for this type. For example, if you have
public class A {
public void methodA() {
System.out.println("A");
}
}
public class B extends A {
public void methodB() {
System.out.println("B");
}
}
public class Main {
public static void main(String[] args) {
A ab = new B();
ab.methodB();
}
}
This will not compile, since the type defined for the variable ab is A and the only visible methods are those that are defined in A.
In your case you can simply add a blank method in Reference(if you don't want to make the class abstract):
public void someBookorJournalMethod() {}
Or you can explicitly cast the object you're trying to invoke the method for.
However, it is important to note that both approaches are usually bad practices and should be avoided. If it does not make sense to instantiate Reference objects, than make the class abstract and define someBookorJournalMethod as an abstract method. In your code you're most probably using inheritance in a wrong way.
You can't access the method of a subclass from the superclass. So you'll need to cast to a Book or a Journal.
Reference r =ArrayList.get([someindex]);
if (r instanceof Book) {
((Book) r).someBookMethod();
} else if (r instanceof Journal) {
((Journal) r).someJournalMethod();
}
After reading through the Generics info I am attempting a simple sample and encountering the following error.
MyClass.java:32: error: cannot find symbol
System.out.println("X = " + temp.x);
^
symbol: variable x
location: variable temp of type T
where T is a type-variable:
T extends Object declared in method tryThis(T)
1 error
Without the reference to "temp.x" it compiles which leads me to believe the definition is correct but possibly the way the variable is referenced is the issue. Or it could be the actual implementation is wrong. Not sure.
The main class has a method which can be called by either of the 2 inner classes. When called, the method attempts to access the variable specific to the inner class that called it.
public class MyClass {
public class InnerClass1 {
int x = 100;
public void runThis() {
tryThis(this);
return;
}
}
public class InnerClass2 {
int x = 200;
public void runThis() {
tryThis(this);
return;
}
}
public static void main(String[] args) {
MyClass x = new MyClass();
}
private <T> void tryThis(T temp) {
System.out.println("X = " + temp.x);
}
}
symbol: variable x
location: variable temp of type T
where T is a type-variable:
T extends Object declared in method tryThis(T)
^^^^^^^^^^^^^^^^
Without further specification, e.g. <T extends InnerClass1>, the only thing that is known about T within that method is that it extends Object, and for Object, the attribute x is not defined.
Maybe you should define a common super-class for those two classes, and declare x in that super-class.
In order to get the value x from each class dynamically, you can define a common interface or abstract class for InnerClass1 and InnerClass2 to implement or extend. This allows the inheritance of methods and variables. Seeing that both holds a value of type T, let us create an interface called ValueHolder<T>:
interface ValueHolder<T> {
public T getValue();
}
Both the InnerClass1 and InnerClass2 will need to implement this interface:
public class InnerClass1 implements ValueHolder<Integer> {
private int x = 100;
#Override
public Integer getValue() {
return this.x;
}
}
public class InnerClass2 implements ValueHolder<String> {
public String x = "200";
#Override
public String getValue() {
return this.x;
}
}
As you can see, InnerClass1 implements ValueHolder<Integer>, meaning the inherited getValue methods return type will be Integer. The same goes for InnerClass2, which implements ValueHolder<String>.
Change your tryThis as follows:
private <T> void tryThis(ValueHolder<T> temp) {
System.out.println("Value = " + temp.getValue());
}
Now each value can be printed like this:
Generics g = new Generics();
g.tryThis(new InnerClass1());
g.tryThis(new InnerClass2());
Output:
X = 100
X = 200
T in
private <T> void tryThis(T temp)</code>
is just a placeholder for any class. The compiler knows nothing more about it, so it knows nothing about the symbol x as well.
To accomplish what you are trying to do, you would need something like this:
public class Generics {
abstract class MyClass {
int x;
}
public class InnerClass1 extends MyClass {
InnerClass1() {
super.x = 100;
}
public void runThis() {
tryThis(this);
return;
}
}
public class InnerClass2 extends MyClass {
InnerClass2() {
super.x = 200;
}
public void runThis() {
tryThis(this);
return;
}
}
public static void main(String[] args) {
Generics x = new Generics();
x.new InnerClass1().runThis();
x.new InnerClass2().runThis();
}
private <T extends MyClass> void tryThis(T temp) {
System.out.println("X = " + temp.x);
}
}
However, you would not need Generics for this specific case:
private void tryThis2(MyClass temp) {
System.out.println("X = " + temp.x);
}
would accomplish the same.
Generics are very complex, although they look easy to use.
I am experience some problems in understanding how the OO pattern works, My lecturer gave me the following question but I cannot solve it after thinking whole day
Scenario for my problems.
There is a class named "ShapeManager" which manages the Shape object. A class named "Shape" has two subclasses named "Circle" and "Rectangle"
The implementation of Shape class as follow
abstract public class Shape {
private String id;
private double length;
public Shape() {
}
public Shape(String id , double length) {
this.id = id;
this.length = length;
}
public void setID(String id) {
this.id = id;
}
public String getID() {
return id;
}
public void setLength(double length) {
this.length = length;
}
public double getLength() {
return length;
}
public abstract String getDetails();
}
The subclass Square as follow
public class Square extends Shape{
public Square() {
super();
}
public Square(String id , double side) {
super(id, side);
}
#Override
public String getDetails() {
return "Square => Id : "+getID() +", Side : "+ getLength() + ",Area : "+(getLength() * getLength());
}
}
The subclass Circle as follow
public class Circle extends Shape{
public Circle(){
super();
}
public Circle (String id, double radius) {
super(id, radius);
}
#Override
public String details() {
return "Circle => Id : "+getID() + ", Radius : "+ getLength() + ",Area: "+(3.14*(getLength() * getLength()));
}
}
The ShapeManager class as follow, this is not a completed class
public class ShapeManager {
public Shape createShape() {
}
public void updateLength(String id ){
}
public void deleteShape(String id) {
}
public void listShapes() {
}
}
ShapeManager have an association with Shape
ShapeManager --1------0..*--> Shape
The design of this package (All the classes above) can not be changed, implementation must be following OCP (Open-Closed Principle).
My question is: How am I suppose to complete createShape method? Without parameter, it is seemingly impossible to create an object either a Rectangle or Circle.
ShapeManager cannot create a shape if not knowing what this shape is (Square, Circle or something else). And it really doesn't know because you say the method createShare has no parameters. Either you misunderstood the question or the lecturer didn't explain it well. You should ask him/her for clarifications. If you look at the libraries of Java or any other OO language, I am pretty sure you won't find such scenario and implementation pattern as the one you gave in your example.
#croraf
You should find some other reading I think e.g. the classic book http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612. The main idea of a factory is that it returns something whose type the caller doesn't know, and doesn't care about. For example, if you have a method createSocket() in some SocketFactory, this method is usually defined to return an interface or an abstract class Socket. But actually it returns new SocketImpl1() and new SocketImpl2() which are concrete classes. What the factory returns may depend on many things - a system property, the underlying OS, anything you can think of. The main idea is that the factory centralizes the creation of Socket objects at one single place. This way, if you need to make a change, you can make it just in the factory. I think this book also has some decent Java counterparts too, you may look around. Other free good sources are referenced here.
Real world examples of Factory Method pattern
I think you should have something like this, similar to how BorderFactory from java API works.
public class ShapeManager {
public Shape createCircle() {
...
return Circle;
}
public Shape createSquare() {
....
return Square;
}
...
public void updateLength(String id ){
}
public void deleteShape(String id) {
}
public void listShapes() {
}
}
You can't create shape without knowing type which shape would You like to create. You can define enumeration for types and pass the type value to the createShape(). And there You can switch between types and create the concrette shape You want.
For me, Its classic Factory pattern.
public class ShapeFactory {
public abstract Shape getShape(int shapeId);
}
public interface Const {
public static final int SHAPE_CIRCLE =1;
public static final int SHAPE_SQUARE =2;
}
public class SimpleShapeFactory extends ShapeFactory throws BadShapeException {
public Shape getShape(int shapeTypeId){
Shape shape = null;
if(shapeTypeId == Const.SHAPE_CIRCLE) {
//in future can reuse or cache objects.
shape = new Circle();
}
else if(shapeTypeId == Const.SHAPE_SQUARE) {
//in future can reuse or cache objects
shape = new Square();
}
else throw new BadShapeException("ShapeTypeId="+ shapeTypeId);
return shape;
}
}
Calling:
ShapeFactory factory = new SimpleShapeFactory();
//returns a Shape but whether it is a Circle or a
//Square is not known to the caller.
Shape s = factory.getShape(1);
s.getDetails(); // circle details called
//returns a Shape but whether it is a Circle or a
//Square is not known to the caller.
s = factory.getShape(2);
s.getDetails(); //Square details called
References:
The Open Close Principle states that the design and writing of the code should be done in a way that new functionality should be added with minimum changes in the existing code. The design should be done in a way to allow the adding of new functionality as new classes, keeping as much as possible existing code unchanged.