Calling superclass from a subclass constructor in Java - java

I am trying to create a constructor that takes a field as a parameter, then puts it in a field that is stored in a superclass. Here is the code I am using
public crisps(String flavour, int quantity) {
this.flavour = super.getFlavour();
this.quantity = quantity;
}
In the superclass I have initialised the field with
private String flavour;
and I have an accessor method
public String getFlavour() {
return flavour;
}
I am getting an error "flavour has private access in the superclass", but I believe this shouldn't matter as I am calling the accessor method that returns it to the field?

What you should do:
Add a constructor to your super class:
public Superclass {
public SuperClass(String flavour) {
// super class constructor
this.flavour = flavour;
}
}
In the Crisps class:
public Crisps(String flavour, int quantity) {
super(flavour); // send flavour to the super class constructor
this.quantity = quantity;
}
Comments
Some comments to your question:
"In the superclass I have initialised the field with "
private String flavour;
This is not an initialization, it is a declaration. An initialization is when you set a value.
"I am getting an error " flavour has private access in the superclass" but I believe this shouldn't matter as I am calling the accessor method that returns it to the field?"
When you call a accessor (aka getter), it is ok - depends on the getter visibility.
The problem in you code is the:
this.flavour =
because flavour is not a field declared on Crisps class, but on the supper class, so you can't do a direct access like that. you should use my suggestion or declare a setter on the super class:
public void setFlavour(String flavour) {
this.flavour = flavour;
}
Then you can use it on the child class:
public Crisps(String flavour, int quantity) {
this.quantity = quantity;
super.setFlavour(flavour);
}

flavour is private. Although you're reading it from the public method, you're assigning it to a private field, and you likely didn't declare it in this class.
You could set flavour to protected in the parent class or define a setter for it
Ultimately your code doesn't really make sense though. Even if it did compile, it would be more or less: flavour = flavour. Perhaps you should rethink what you're trying to do a little bit
I think you may need a tighter grasp on Java and Object Oriented Programming.
http://docs.oracle.com/javase/tutorial/java/concepts/
You should start here.

public crisps(String flavour, int quantity)
{
super(flavour);
this.quantity = quantity;
}
This should work as see Docs

make
private String flavour;
public,otherwise your subclasses won't have access to this String.
Your superclass doesn't know about existence of any subclass. According to Java documentation, "private" makes any variable and method available within that class,where private variable or method was declared, no any class has access to it,even subclasses.
Once you chance your access modifier, you won't get any errors.

Related

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.

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.

what is difference in "return name;" and "return this.name"

I am trying the Jacco testing and I am able to test the getStudentId from a class called Student which has:
public String getStudentId() {
return studentId;
}
When I try to test my other class named Product, I get an error - the only difference between the two is in the getX method. The getName method of Product is:
public String getName() {
return this.name;
}
and the error message says:
constructor Product in class Product cannot be applied to given types
The keyword this references the instance of the object you are currently in. Imagine having a class like this:
public class A {
private String property;
public void changeProperty(String property) {
this.property = property
}
}
Outside of the method the variable name property is not ambiguous and references the member variable of class A. But it is ambiguous inside the method changeProperty because there is also the argument named property.
How does Java resolves this conflict? If you just type property you will always reference the object with a smaller scope, so the argument of the method and not the member variable. By using this.property you can reference the member variable again.
If there is no such conflict in your object, like in your example, then you do not need the this statement and this.name is the same as name.
However as prevention of very nasty bugs one could always use this when referencing a member variable, just as good practice. Imagine you would create a method with such a name conflict in the future and forget about the member variable, whoops you easily create a bug that is hard to debug.
Some programmers even go further and do always give member variables other names than arguments, to prevent such name conflicts. For example member variables are often named:
mProperty or
_property
Note that the method this(...) references a constructor of the own object. It can be used in a constructor to pass the task to another constructor like:
public class A {
public A(String fileName) {
this(new File(fileName), true);
}
public A(File file) {
this(file, true);
}
public A(File file, boolean doSomething) {
// Code ...
}
}
Analogously there is also the keyword super which references the parent-class. For example:
public class A {
protected String property;
}
public class B extends A {
private String property;
public void foo() {
// Property of B
System.out.println(property);
// The same
System.out.println(this.property);
// Property of A
System.out.println(super.property);
}
}
This keyword can also be used to reference parent-constructor or other methods of the parent class.
So all in all it is just about resolving such name conflicts.
Now we know that, it is easy to see that the code you posted does not contain the bug.
When you use this.name you are using a attribute defined in your class, the attribute name. However, when you use only name, it could be any variable called so in your code, even the attribute. Example:
public String getName(){
String name = "Mery";
this.name = "Jacob";
return name;
}
This method return the value "Mery". If you put return this.name then you return the value "Jacob".
There's a chance you set studentID to a public variable. Anytime you are using this.whatever to return a variable from a getX function, the this. implies it's a private variable. More likely than not the studentID is public and that's why you got away with no 'this.' in front of it.

Different constructor for subclass

I have an abstract superclass with a constructor of the form
public classname(String name, int amount)
and want to create a subclass of that abstract class that instead of taking a String as its first parameter takes an integer value that represents a given String name, so e.g. 0 stands for some String, 1 for another and so on.
When I try to write a constructor of the form subclass(int number, int amount) I get an error of the form "implicit super constructor is undefined. Must explicitly invoke another constructor."
Why is it not possible to create another, different constructor in the subclass?
Wrong question, you can write another constructor in the subclass, but as the super class has no default/no-argument constructor, you have to explicitely call the constructor of the super class you mentioned to ensure the invariance of the super class.
As mentioned by others in derived class you need to invoke constructor of its super class using super(arguments). Also this call must be first instruction in your constructor so you will probably face problem where you will need to determine value you want to place as name before calling constructor like
MyClass(int id, int amount){
super("???",amount);
}
here we don't know yet what value to use in place of "???". Unfortunately you can't use
MyClass(int id, int amount){
if (id==1) super("foo",amount);
else super("bar",amount);
}
One of possible solutions is to create separate method which will return correct name based on id and use it as super parameter like
MyClass(int id, int amount){
super(choseName(id),amount);
}
private static String choseName(int id){
if (id==1)
return "foo";
else
return "bar";
}
One solution is to use static factory methods. Consider this:
public abstract class Amount
{
protected static final List<String> IDENTIFIERS
= Arrays.asList("idfor0", "idfor1" /* etc */);
protected final String identifier;
protected final int amount;
public static Amount forIdentifierNumber(final int number, final int amount)
{
return new IdBasedAmount(IDENTIFIERS.get(number), amount);
}
protected Amount(final String identifier, final int amount)
{
this.identifier = identifier;
this.amount = amount;
}
}
Then, in the same package:
final class IdBasedAmount
extends Amount
{
IdBasedAccount(final String identifier, final int amount)
{
super(identifier, amount);
}
}
Call from code:
final Amount amount = Amount.forIdentifierNumber(0, 20100);
After that, it is only a matter of defining whatever methods are needed in the Amount class (either final or delegated to subclasses).
Of course, adapt to your code.
Edit: an example of static factory methods yielding classes with different internal state but the same behaviour: here. SchemaKey is abstract, acts as an "interface" and has static factory methods within itself to generate concrete classes.
You need to call super() in your subclass's constructor and hence explicitly call the super class's constructor.

Why Enum constructor can't have protected or public access modifier

Enum constructors must be either private or package default, and protected or public access modifier is not allowed. Why so
Because an enum, by definition, has a fixed set of instances which are declared and constructed in the enum itself. Using the constructor from outside of the enum class itself thus doesn't make sense.
And AFAIK, an enum constructor is always, explicitely or implicitely, private.
From the Java tutorial:
The constructor for an enum type must be package-private or private access. It automatically creates the constants that are defined at the beginning of the enum body. You cannot invoke an enum constructor yourself.
It doesn't make sense to be able to create new instances of an enum, so the language prevents you from doing so!
Enum is not meant to be instantiated (by you).
http://docs.oracle.com/javase/tutorial/reflect/special/enumTrouble.html :
Tip: It is a compile-time error to attempt to explicitly instantiate an enum because that would prevent the defined enum
constants from being unique. This restriction is also enforced in
reflective code. Code which attempts to instantiate classes using
their default constructors should invoke Class.isEnum() first to
determine if the class is an enum.
The reason you can't dynamically extend an enum is that the instantiated values are compiled into the bytecode for the Class object:
public T[] getEnumConstants()
Returns the elements of this enum class or null if this Class object does not
represent an enum type.
As a result, any attempt to construct a new instance would not be able to passed onto the actual Class, since Class objects cannot be changed. If you want this behavior, you'll have to simulate it yourself, and give it some kind of unique value to represent each one, then have an ordinal counter, and finally a static map (or some other structure) to hold all the values.
public class MyEnum {
private static AtomicInteger nextOrdinal = new AtomicInteger(0);
private static Map<Integer, MyEnum> instances =
new HashMap<Integer, MyEnum>();
private int ordinal;
private String name;
public MyEnum(String name) {
super();
this.ordinal = nextOrdinal.incrementAndGet();
this.name = name;
instances.put(Integer.valueOf(this.ordinal), this);
}
public String name() {
return name;
}
public int ordinal() {
return ordinal;
}
public static Set<MyEnum> getEnumConstants() {
return Collections.unmodifiableSet(instances.values());
}
public static MyEnum fromInt(int ordinal) {
return instances.get(Integer.valueOf(ordinal));
}
public static MyEnum fromString(String name) {
for (MyEnum val : instances.values()) {
if (val.name().equals(name)) {
return val;
}
}
return null;
}
}
You'll probably also want a .equals and .hashcode method, as well as preventing the same name from being used more than once (which you could do in the constructor and throw an IllegalStateException or something if you have a duplicate name).

Categories