Confusion with Java inner private classes and toString() - java

I have a project where I must use inner classes to declare types of food (created as 'Item' objects); for example, Pancake:
private class Pancake {
Item pan = new Item(5.50);
public String toString() {
}
}
As shown above the assignment given to me says each private inner class must override toString to return the name and price of the object. But, the test cases read what is returned from the toString method in the Item class (a different public class), which I currently have coded as:
#Override public String toString() {
return "" + " ($" + this.price + ")";
}
I do not know how to pass this toString method the name of the food type (i.e, Pancake). Item objects are created with a constructor that asssigns them a price, and that is all that is allowed. So I cannot use this.name or something like that to access the name of the food. How can I give this toString() method the name of the food (the private inner class, in a different class entirely)? No constructors are allowed to be implemented in the private classes. I've tried using this.getClass() but all that does is return a class type of Item, not the specific food class. Any help would be appreciated.

Related

How can I access subclass attribute through passing its superclass as parameter of a method

I am having trouble with a method that accepts two classes Pokemon as its parameters because it could be whatever pokemon battling, but if I try to catch the name of the subclass, such as Totodile, the superclass's name attribute is printed
in Pokemon.java:
abstract public class Pokemon {
private String name="POKEMON";
public String getName() {
return name;
}
}
in Totodile.java :
public class Totodile extends Pokemon {
String name = "Totodile";
}
in Geodude.java :
public class Totodile extends Pokemon {
String name = "Geodude";
}
in Battle.java :
public class Battle {
public void initiateBattle(Pokemon pokemon1,Pokemon pokemon2){
System.out.println(pokemon1.getName()+ " is battling against " + pokemon2.getName());
}
}
in App.java:
public class App {
public static void main(String[] args) throws Exception {
Geodude geodude = new Geodude();
Totodile totodile = new Totodile();
Battle battle = new Battle();
battle.initiateBattle(totodile, geodude);
}
}
The output is "POKEMON is battling against POKEMON"
, but how could I get "Totodile is battling against Geodude"
You can't "override" a field. When you write:
class Foo {
String name;
}
you are always declaring a new field. If your superclass also has a field with the same name, okay. Now your Totodile class has 2 fields, both named name, one of which has value POKEMON, the other has value Totodile.
Which one do you get when you write myPokemon.name? Depends on the compile-time type of myPokemon (the variable, not the object it is pointing at!) - and given that it is Pokemon in your code, you get the Pokemon version of the name field.
This notion that you have 2 fields with identical names is called 'shadowing'.
Shadowing is a mistake; do not do it unless you really, really know what you are doing.
The solution is therefore quite simple: Don't define a field named name in the Totodile class. Instead, set the value of the name field (which you inherited, so the Totodile class has that name field already, no need to make a second field with the same name and confuse things):
class Totodile {
{ name = "Totodile"; }
}
This somewhat weird syntax creates an instance initializer, as you need to stuff your code somewhere (you can't just start putting statements straight into a class, you need to brace em up). This is a tad odd, the more usual design is instead something like this:
abstract class Pokemon {
private final String name;
public Pokemon(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class Totodile extends Pokemon {
public Totodile() {
super("Totodile");
}
}
This is what most java programmers do:
It forces subclasses of Pokemon to actually set the name properly. That default 'POKEMON' value is weird and no longer needed in the above strategy.
It avoids exotic code constructs to make it work. Constructors and abstract classes tend to be a lot more familiar to your average java coder than instance initializers.
Adds final in the appropriate places.

Is it possible to receive subclass's name in compile time in Java?

I'm trying to create a snacks machine implementation in java.
I have created an abstract class named Product that will give the basic design for each of the offered products.
I mean we have the abstract class Product and then other classes like Nachos, Cake, etc.. that inherita from Product.
Product class does not contain too much, it just contains the name , the price and the available amount of the product (these are the fields in the class).
It also has get methods for the fields that just return the value for each one.
The problem is that I want to set the name of the product as a static final because if a product's name is Nachos, it won't be changed. I mean it'll be possible to create more Nachos objects but the name of their class is still going to be Nachos.
So there is no reason to NOT to do that static final.
The issue with that is that i'm not sure how to set it correctly.
public abstract class Product {
private static final String productName = getClass().getSimpleName();
private int price;
private int amount;
....
Constructor..
Get methods..
I thought about getClass().getName() or getSimpleName() but it gives me an IDE error which indicates that the only way for me to also use that field as static final and also to use getClass is by writing Product.class.getName();.
The problem is that if i'll do that, the name that will be returned is Product and not Cake or Nachos or other sub classes.
If your Class has some attribute that describes that Class (e.g a product name), that's an attribute of that Class. You shouldn't write code that uses the name of the class itself with getClass().getName(), that's tying your business logic to implementation details, and there's no reason (or very few good reasons), why your code would need to know the name of the class itself.
Instead, add an attribute like productName to your class:
public class Product{
private String productName;
public Product(String name){
this.productName = name;
}
public String getProductName(){
return this.productName;
}
}
You should just use "final" and drop the "static". By declaring the variable as final you can assign the value of "getClass" that use "this" for reference. "this" doesn't work for static.
abstract class Product {
private final String productName = this.getClass().getSimpleName();
public String getProductName() {
return productName;
}
}
The "this" can be omitted in "this.getClass().getSimpleName()", leaving only "getClass().getSimpleName().
It doesn't make sense to use "static" because you would access the attribute directly via the class reference. But this would not work because to get the "getClass" you would need to be within some scope (constructor...) because the attribute is static, it is impossible to assign the value of the attribute at the time of its creation, making it impossible to use the " Final".
A static member belongs to the class in which it is defined. Declaring productName as static on the class Product means that every concrete implementation would have the same value. This is not what you want.
I think the solution that is closest to what you describe is not to have a member at all. Instead, declare an accessor as follows.
public abstract class Product {
public final String getProductName() {
return getClass().getSimpleName();
}
}
Thus, every instance of a given subclass (e.g. Taco) references the same Class object for its type. We never duplicate the value because we are accessing the singular value in our memory space. We declare this method to be final so that subclasses cannot override it. This enforces that the productName will always be the simpleName of the concrete implementation.

Sports team model - constructor in class cannot be applied to given types

You are writing a computer program to model sports teams (could be baseball, football, kickball, ultimate, anything!). Your awesome coworker has already written the following classes:
The Team class contains the following methods:
// Constructs a Team object based on the supplied Roster object.
public Team(Roster r)
// Simulates this Team playing a single game, returning a String describing the results of the game.
public String play(Game g)
The Roster class contains the following method (other methods not shown):
// Returns a String containing the names of players on this Roster
public String toString()
The Game class contains methods, but none are shown here.
Design a new class TeamWithStats that inherits from Team, but also keeps track of the team's statistics ("stats"). You should provide the same methods as the superclass, as well as the following new behavior:
// Constructs a TeamWithStats object using information in the Roster object r.
public TeamWithStats(Roster r)
// Returns the information described below
public String getStats();
The getStats method returns a single String containing (in this order): the Roster (in String form, as returned by Roster’s toString method), a "newline" character (\n), the results returned from the first call to play, a "newline" character (\n), the results returned from the second call to play, a "newline" character (\n), the results returned from the third call to play, and so on, through the very last call to play that has been made so far. If play has not yet been called, getStats just returns the Roster (in String form).
Assume all classes other than TeamWithStats were written by your awesome coworker and cannot be changed. In your class, you should include the following:
Any private field(s) you need to add to TeamWithStats
Implementation of the TeamWithStats constructor
Implementation of any methods you need to override.
Implementation of getStats
As always, your methods should call into the superclass as appropriate.
Code:
public class TeamWithStats extends Team
{
private Roster r;
public TeamWithStats(Roster r) {
super(r);
this.r = r;
}
public String getStats() {
return r.toString() + "\n" + super.play(new Game()) + "\n";
}
}
Error message
Error on line 12: constructor Game in class Game cannot be applied to given types;
return r.toString() + "\n" + super.play(new Game()) + "\n";
^
required: java.lang.String
found: no arguments
reason: actual and formal argument lists differ in length
Explanation
Your error message is pretty straightforward, carefully read it:
Error on line 12: constructor Game in class Game cannot be applied to given types;
return r.toString() + "\n" + super.play(new Game()) + "\n";
^
required: java.lang.String found: no arguments
reason: actual and formal argument lists differ in length
So you are calling new Game(), without any arguments. But the constructor in that class requires you to call it with a String, like new Game("foo").
If you lookup the code for the class Game, you will see something like:
public class Game {
...
// Constructor that requires a String as argument
public Game(String foo) {
...
}
...
}
Check out the class to see what exactly the purpose of that String is.
Example
To give you a better feeling for what you did wrong, let me show you another example. Suppose you have a class Person and you want that each person has a String name and an int age. You can achieve this by letting the constructor require both. For example:
public class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public String getAge() { return age; }
}
Now you can create instance of this class by calling the constructor and providing both, a name and an age:
Person person = new Person("John", 20);
But what you are trying to do is just calling it like new Person(), without supplying any name or age, despite the constructor requiring it.

Calling a Constructor without parameters

I am trying to build a class with a constructor, mutators and accessors. Reading through books and online, I am made to learn that you can call a constructor with or without parameters. However, my case below seems not to work. I am not even able to compile without errors. It works when I use student jane = new student(""). What am I doing wrong?
Devolution.java:6: cannot find symbol
symbol : constructor student()
location: class Governor
student jane = new student();
^
public class designers {
public static void main(String[] args) {
student jane = new student();
student smith = new student("jane", "36365355", "Nairobi", "Male");
System.out.println("Janes's Properties: "+jane.name() + " " + jane.nationalID() + " " + jane.county()+" "+jane.gender());
System.out.println("Smith's Properties: "+smith.name() + " " + smith.nationalID() + " " + smith.county()+" "+smith.gender());
}
}
other code is below
public class student {
//Private fields
private String name;
private String nationalID;
private String county;
private String gender;
//Constructor method
public student(String name, String nationalID, String county, String gender)
{
this.name = name;
this.nationalID = nationalID;
this.county = county;
this.gender = gender;
}
//Accessor for name
public String name()
{
return name;
}
//Accessor for nationalID
public String nationalID()
{
return nationalID;
}
//Accessor for county
public String county()
{
return county;
}
//Accessor for gender
public String gender()
{
return gender;
}
}
A constructor is a way of creating an instance of a class:
Student s = new Student(...);
will create a new instance of the Student class and enable you to access it using s.
Often, when you create an instance of a class, you need to specify certain information that's used in building the instance. In the case of a student, that might be the name, the age, and so on. You'd have a constructor that looks like this:
public Student(String name, int age) {
//...
}
But in some contexts, you can build an instance of a class without needing (at least initially) to specify anything. So you might, for instance, have a constructor like this
public Student() {
//...
}
which leaves the name and age fields blank or zeroed out, until you later set them with another method of the class.
The critical point for what you're doing is that you've made a constructor that requires various parameters, but you haven't specified one like this second example that doesn't require any. As things stand, you can write
Student s = new Student("Bob", "ABC12345", "Surrey", "Male");
because you've got a constructor that takes four Strings as arguments. But you can't write
Student s = new Student();
because you didn't create a constructor that takes no arguments.
The slight wrinkle in this is that if you don't specify any constructors in your class, then Java will automatically create one for you that takes no arguments and doesn't do anything special. So if you don't write any constructors, you'll get one for free that looks like this:
public Student() {
}
But that's only if you don't write any of your own. Since you've specified one that does take parameters, Java won't give you a no-argument one for free. You have to put it in yourself if you want to be able to create instances without any arguments.
You've only written one constructor - the one with four parameters. You don't have a constructor without parameters, so you can't write new student().
Note that if you don't write any constructors at all, the compiler will automatically make a constructor for you, without parameters, but as soon as you write one constructor, this doesn't happen.
By the way, most people use capital letters for class names (so Student, not student). This makes it easy to distinguish them from the names of other identifiers. It would be good for you to get into the habit of doing the same.
You don't have a constuctor without parameters in the student class. Such a constructor is generated by the compiler only if you haven't defined any other constructors, which you have.
Just add the constructor :
public student()
{
this.name = null;
this.nationalID = null;
this.county = null;
this.gender = null;
}
You need to make another constructor as follow:
public Student(){
//do things here
}
Explanation:
When no constructors are defined in a class then there is a default constructor(without
any parameters) already. In which case you don't need to define it. But if you have any constructor with some parameters, then you need to define the constructor without parameters as well.
Its called overloading the constructor. In your class, declare a constructor again without parameter requirements. See this post for more info
You don't have a constructor without parameters. That would only be the case when you had not write an own one. When you want to have the possibility to make an object of the class with or without parameters, you need two different constructors in your code.

Decide at runtime which class to invoke

Interface :
public interface Person {
public String name = "";
}
I have two classes:
public class Male implements Person {
public String name = "Male1";
}
Another class being
public class Female implements Person {
public String name = "Female";
}
I want to instantiate a class at runtime depending on who the user is. Something like :
Person p = getPerson("M");
System.out.println("P = " + p.name);
private static Person getPerson(String gender) {
if (gender.equals("M"))
return new Male();
else if (gender.equals("F"))
return new Female();
else
return null;
}
I am expecting the output to be: Male1
How can I achieve this ? What is the best design pattern to achieve this functionality ?
lookup and use Class.forName()
You don't put attributes in an interface.
Your interface should include a String getName(); method signature. Then you implement this method in all inherited classes. That way, you can call getName() on your Person object to retrieve the person's name regardless of the implementation class.
To instantiate, take a look at the Factory pattern.
There are several options, but you could use Abstract Factory:
Create a PersonFactory interface with just a createPerson method. Then make two implementations:
MaleFactory which returns a new Male
FemaleFactory which returns a new Female
Then keep a Map<String, PersonFactory> where the key is the gender and the value is an instance of the factory that will create the appropriate Person instances.
Getting a new Person given the gender becomes as simple as
map.get(gender).createPerson()
EDIT:
I see you have edited your question so that it now includes a question about using variables in interfaces.
Basically, you don't want to put the variable in the interface, because that will mean it's static (the static keyword is implied in this case since interfaces can't have non-static variables), and I guess you don't want all persons to have the same name.
So you'll have to declare a getName() method in the interface. If the behaviour should be the same for all genders (I don't see why not) then you can just put both the name variable and the getName() method in an abstract base class (e.g. AbstractPerson) which both Male and Female extend.

Categories