java inheritance field setup vs constructor [duplicate] - java

This question already has answers here:
Java force fields inheritance
(4 answers)
why java polymorphism not work in my example
(3 answers)
Closed 8 years ago.
I'm new to Java. I've had following classes:
public abstract class Beverage {
String description = "Unknown beverage";
public String getDescription() {
return description;
}
public abstract double cost();
}
and:
public class DarkRoast extends Beverage {
String description = "Dark roast";
#Override
public double cost() {
return 0.99;
}
}
When I construct a new DarkRoast object:
Beverage beverage2 = new DarkRoast();
I expect it to have desctiption equal to "Dark roast":
assertEquals("Dark roast", beverage2.getDescription());
But actually it's "Unknown beverage". I know I should implement DarkRoast constructor that sets description, but I don't know why, I don't know how it works internally. Shouldn't the subclass field overwrite superclass field?

Shouldn't the subclass field overwrite superclass field?
No - the subclass field is actually an entirely new field. Since you mean to assign to the superclass field, you need to create a constructor like this:
public DarkRoast()
{
description = "Dark roast";
}
(This is unlike the method cost() - technically when you override a non-abstract method you still 'sort of' have the old method as well)

If the subclass must always provide a description, then you could make getDescription abstract, which would force the subclasses to implement and return a value. Just another technique.

Because the called getDescription method is the method of the class Beverage (DarkRoast doesn't have its own), so the method getDescription access to his description property, whose value is "Unknown beverage".

It is allowed for class to hide the members. When you declare a member for field in class and declare in the child class some with the same name you will hide it but not override.
If you want to provide unique name for each class that implement your abstract class you should declare an abstract method
public abstract String getDescription();
Or you can pass the value to the member.
BaseClass(String description) {
this.description = description;
}
then in child class you can use the super to access the constructor
ChildClass(String description) {
super(description);
}
The key word super allows you to access directly the members of parent class.
So in case of your class you could be able to do something like this
private void test() {
System.out.println(super.description); //This will refer to parent class
System.out.println(this.description); //This will refer to child class
}
So when you declare a field you create always a new reference point.

You do not override the .getDescription() method in subclasses; as a result, the method called is the one in Beverage, and the method in Beverage only knows about the description declared (and initialized, in this case) in Beverage itself.
You could have it display the value in all subclasses by using instead:
return this.description;
However, there is a much better way to solve this problem; and that is:
public abstract class Beverage
{
private final String description;
public abstract Beverage(final String description)
{
this.description = description;
}
public final String getDescription()
{
return description;
}
// etc
}
// Subclass
public class DarkRoast
extends Beverage
{
public DarkRoast()
{
super("Dark Roast");
}
}
You should note that it makes no sense at all to describe an "Unknown beverage" to start with. Beverage being abstract, it cannot be instantiated! The solution proposed here basically forbids anyone from creating a Beverage without a description, so it's a win-win ultimately.

The problem is there are 2 attributes called description, one in the super class 'Beverage' and one in the subclass 'DarkRoast', and since you are using Beverage as the the reference type you get the description attribute/instance variable of the reference class and that of the subclass is shadowed(not accessible at least to my humble knowledge in Java).
You don't need to define the attribute again in the subclass because it's already there, so basically if you remove the attribute description from the DarkRoast class you will find that it will print unknown description as well, because it is already there.
To make things more clear try this code to see how there are 2 different description instance variables.
public class DarkRoast extends Beverage {
String description = "Dark roast";
public String getDescription() {
return description;
}
public String getSuperDescription() {
return super.description;
}
#Override
public double cost() {
return 0.99;
}
public static void main(String[] args) {
DarkRoast b = new DarkRoast();
System.out.println(b.getDescription());
System.out.println(b.getSuperDescription());
}
}
To see the shadowing try to do the following:
public static void main(String[] args) {
Beverage b = new DarkRoast();
DarkRoast b2 = new DarkRoast();
System.out.println(b.description);
System.out.println(b2.description);
}

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.

Why subclasses inherit private fields?

I'm creating a new class which is vehicle. I'm expecting the only protected variables inherit to subclasses. But when I try to create Constructor with IDE, it is also using superclasses private variables? -Which is private String vehicleName- I'm not clearly understanding this situation. Shouldn't I use auto Concstructor?
public class Vehicle {
protected int capacityOfPassengers;
protected String mapOfRoute;
private String vehicleName;
public Vehicle(int capacityOfPassengers, String mapOfRoute,
String vehicleName) {
this.capacityOfPassengers = capacityOfPassengers;
this.mapOfRoute = mapOfRoute;
this.vehicleName = vehicleName;
}
}
public class LandVehicle extends Vehicle {
private String brand;
private int priceModel;
public LandVehicle(int capacityOfPassengers, String mapOfRoute,
String vehicleName, String brand, int priceModel) {
super(capacityOfPassengers, mapOfRoute, vehicleName);
this.brand = brand;
this.priceModel = priceModel;
}
}
Generally, a class has a default constructor, taking no arguments, IF no constructor has been provided by you.
When you subclass Vehicle with your LandVehicle, your LandVehicle is a type of Vehicle. This means that it inherits methods and field from its superclass, even if they are private. For the class LandVehicle these members are just not visible, but they are still present - otherwise it couldn't function properly. The private keyword is an access modifier, that changes visibility to the caller.
As a result, to instantiate a LandVehicle, you also must provide the required attributes of its superclass Vehicle (since there is no default, no-arg constructor in Vehicle). In your example, a LandVehicle without a name (from Vehicle) wouldn't make sense, since a LandVehicle is a Vehicle, which requires a name.
You cannot access vehicleName from LandVehicle. You just pass some string parameter to super constructor, and the super constructor sets the vehicleName. For example, you can't initialize this field inside LandVehicle class as this.vehicleName = vehicleName.

How do you make a generic abstract function that does not return any particular type?

At the moment, I have a superclass called Entity.
abstract class Entity {
private String name;
private Area area;
public Entity(String name, Area area) {
this.name = name;
this.area = area;
}
private static void entityWait() {
Time.sleep(Random.nextInt(50, 600));
}
private String getName() {
return name;
}
private Area getArea() {
return area;
}
abstract <T> T getNearest();
abstract boolean validate();
}
As far as I understand, this indicates that T is a generic and the return type can be set to anything.
abstract <T> T getNearest();
I then have my subclass in which I extend from Entity:
public class Mob extends Entity {
private String name;
private Area area;
public Mob(String name, Area area) {
super(name, area);
}
#Override
Npc getNearest() {
Npc npc = Npcs.getNearest(name);
return npc;
}
Eventually, I will have a SceneObject and Item class which refers to items in the game world which will require the same functions. So, eventually I'll have to do in the SceneObject class:
#Override
SceneObject getNearest() {
SceneObject object = SceneObjects.getNearest(name);
return object;
}
However, I'm getting an unchecked override warning - return type requires unchecked conversion. What does this mean and how do I do this the correct way?
You want to declare Entity itself as generic:
abstract class Entity<T> {
private String name;
...
abstract T getNearest();
...
}
Then your extending class uses the generic parameter:
public class Mob extends Entity<Npc> {
...
#Override
Npc getNearest() {
return Npcs.getNearest(name);
}
...
}
define your Entity class with generic parameters:
abstract class Entity<T> {
And remove the generic type declaration from your method:
abstract T getNearest();
And have your subclass extend Entity with a generic type:
public class Mob extends Entity<Npc> {
What you are trying breaks at least two rules of object oriented programming. You mix class and interface. You expect any subclass of Entity to fulfill an unknown contract to get nearest. If I invoke this method with a type argument of ArrayList<IllegalStateException> the subclass must return this type. How can this be known at compile time?
The second is breaking out of the instance' context of Mob by invoking a static method Npcs.getNearest(name) that does anything…like printing out a sheet of paper on a clerks desk on the other side of the world to get nearest Npc. That person scans in the result and returns it with a carrier pigeon. An optical character recognition tool then kills the pigeon to extract the characters and returns an Npc, or null or a Runtime Exception or OutOfMemoryError.
I assume you thought about a contract like expressed through an interface and the method getNearest returns something, that is determined by the realizer of the method. Thus you need interfaces instead of classes. And it is also unclear, whether there can be a superposition of two different getNearest in the same class.
Maybe it is absolutely sufficient to let SceneObject have a getNearest of its own as well as Mob and not force this through the Entity. Otherwise getNearest ought to return something that bears a distance to its source or even any source, so getNearest of SceneObject can be compared to getNearest of Mob – what your contract suggests. If this is never the case, drop all evil inheritance.

Extracting information from constructors

If I create an object with a constructor in one class, and the constructor gives the object a property like 'name', is there a way to access specifically the String 'name' from another class? As in, if I have a method that I pass the objects to, and that method needs to access just the String 'name' from the constructor, how do I get to it?
This is probably a bad question that already has an answer, but since I don't know the right terminology to search for it I'm a bit stuck...
You cannot read parameters passed to a constructor from outside the constructor definition, unless that parameter is stored in a field of the class. Of course, if you create an instance of a class like MyClass myObject = new MyClass("Some String");, you can access some string in the scope of the code that created the object.
The ways that a field of a class, say the field fieldName from an instance myObject an a class MyClass can be accessed by another class are:
If the field is public, access by myObject.fieldName
If the field is protected, access it by subclassing MyClass
If MyClass has a getter for the field: myObject.getFieldName()
If the field is private and does not have a getFieldName() method, then it cannot be accessed from outside of the class.
Here are a couple of classes that I think demonstrate what you are wanting to do.
I have a Person class that has a name field and a Friend class that has a method called sayHello and it accesses the name property of Person.
public class Main
{
private static class Friend
{
public void sayHello(Person person)
{
System.out.println("Hello " + person.getName());
}
}
private static class Person
{
private String name;
public Person(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
}
public static void main(String[] args)
{
Person person = new Person("John Smith");
Friend friend = new Friend();
friend.sayHello(person);
}
}

Inherited enum redefinition

It is more complex than it sounds, but I think I am obliged to try something like it. I want to make an abstract parent class with a prototyping of an enum (I want to declare the enum with only one value probably that will be the default unitialized one and also declaring a couple of methods that I will be using from the subclass), then I want to class that will extend the abstract parent to actually intialize the very same enum (I know that this practically hides the parent enum) so that the kid class will define a set of items inside the enum, but keep the methods probably.
I do not know much about this level of abstraction so I will now describe the nature of my problem, in case there is a more practical solution:
I have a bunch of files that contain classes that implement a lot of commands based on enums. (e.g. class1 implements Observer has an update method that uses an enum-based switch to decide what command was picked, same applies for the other classes) I now want to abstract this whole thing in a way that I have an enum variable with the exact same name in all classes (e.g. CommandSet) so that I can have a generic method inside the parent that will be able to print a help list to my system using the inside methods of the enum. Now I know I can rewrite the exact same method in every class, but I want to abstract it so that others can keep on extending the library I am making!
Hopefully I am not too confusing or too confused and somone can help me! :)
Edit: Here is an idea of the code (Probably not right):
public abstract class Commands{
enum CommandSet{
// empty command, placeholder
null_command ("command name", "command description");
// the Strings used for name and description
private final String name;
private final String description;
// constructor
CommandSet(String name, String description){
this.name=name;
this.description=description;
}
// get parameters
public String getName(){
return name;
}
public String getDescription(){
return description;
}
}
public void showHelp(){
for (CommandSet i : CommandSet.values()) {
printf(i.getName(),":",i.getDescription());
}
}
}
public class StandardCommads extends Commands implements Observer{
// I want to change the enum here, just changing the values so that null_command ("command name", "command description") will get removed and I will add a dozen other values, but keep the methods that the parent had
// update inherited from Observer
#Override
public void update(Observable observable, Object object) {
// I want the commands inside the switch cases defined inside this class's enum
switch(CommandSet.valueOf(String.valueOf(object)){
case command1: doStuff1();break;
case command2: doStuff2();break;
...
case commandN: doStuffN();break;
}
// other methods
void doStuff1(){
...
}
...
void doStuffN(){
...
}
}
public class NonStandardCommads extends Commands implements Observer{
// Another set of commands here for the enum keeping the same methods it had in the parent
// update inherited from Observer
#Override
public void update(Observable observable, Object object) {
// Other set of commands inside this class used in the switch statement
switch(CommandSet.valueOf(String.valueOf(object)){
case Zcommand1: doStuffz1();break;
case Zcommand2: doStuffz2();break;
...
case ZcommandN: doStuffzN();break;
}
// other methods
void doStuffz1(){
...
}
...
void doStuffzN(){
...
}
}
Impossible: Java enums can neither extend another class nor be extended themselves.
They can however implement interfaces. Perhaps you can use that to your advantage.
There is something else about enums that may help you: enums are not immutable. You could change field values of the enums, however that would change them for the whole JVM.
Another approach maybe to pass your subclass instances into a method of the enum and have the enum use your subclass as a call back to get different functionality out of an enum for a different user of the enum.
Nope, you can't do that.
Java Enums run out of gas very quickly & definitely, when you want to add/extend more definitions or instantiate the enum instances, at a later time. (eg load them from database, configure them in an instance method, not just statically.)
Behaviour/ or logic in Java enums is kinda limited too -- you can define & set properties, but only what's statically initializable, and logic seems basic (you end up mainly just comparing references or ordinals, with the other defined enum constants).
What you can do:
You can implement an ancestor Command or AbstractCommand class, with a integer Code, and then subclass it to define concrete values/ additional codes/ load or configure instances, etc.
For further benefit, you get efficient switch & despatch (by Code) plus the ability to define further details/properties, instantiate commands as-needed, etc.
Essentially, this is how you used to define an Enum before Java supported them. Though you may be using them as value objects, rather than strictly static.
My expertise:
I've done extensive compiler & type-system work, tried enums for file-types and associated data/behaviour.. explored the outer limits, and reached the definite boundaries.
I also like being able to instantiate & return a new UnknownFileType("") as an answer, too. Enums can't do that.
Example:
(We'll despatch by String, not int -- since your code appears to be using Java 7. This makes command resolution easier, than requiring both a syntactical "name" and an internal integer "code".)
public static class Command {
protected String code;
protected String desc;
public String getCode() {return code;}
public String getDesc() {return desc;}
public Command (String code, String desc) {
this.code = code;
this.desc = desc;
}
public String toString() {return code;}
}
public class StandardCommands {
public static Command READ = new Command("READ", "read a record");
public static Command CREATE = new Command("WRITE", "create a record");
public static Command EDIT = new Command("WRITE", "modify a record");
}
public class FurtherCommands extends StandardCommands {
public static Command LIST = new Command("LIST", "list all records");
}
public class QueryCommands extends FurtherCommands {
public static class QueryCmd extends Command {
protected String search;
public String getSearch() {return search;}
// constructor..
}
public static QueryCmd QUERY_EXAMPLE = new QueryCmd("QUERY", "example", "query for specified string");
public static QueryCmd createQuery (String search) {
return new QueryCmd( "QUERY", search, "query for specified string");
}
}

Categories