Why subclasses inherit private fields? - java

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.

Related

Serializable by extending with empty constructor?

TLDR: Is there a way to force to a subclass to have an empty constructor when the super does not?
I need to be to initialize a non-serializable class, TravelTimeDataArray, from a serialized data container. The TravelTimeDataArray cannot be serialized because it does not implement the Serializable interface, lacks an empty constructor, and uses a non-serializable field of type Link.
public class TravelTimeDataArray implements TravelTimeData {
private final double[] timeSum;
private final int[] timeCnt;
private final double[] travelTimes;
private final Link link; //I'm not serializable
public TravelTimeDataArray(final Link link, final int numSlots) {
this.timeSum = new double[numSlots];
this.timeCnt = new int[numSlots];
this.travelTimes = new double[numSlots];
this.link = link;
resetTravelTimes();
}
//getters and setters
}
My first thought was to extend this as a serializable class. Instead of using a Link, I can use a serializable String of it's ID attribute and add the empty constructor.
public class SerialTravelTimeDataArray extends TravelTimeDataArray implements java.io.Serializable{
private final String linkId = null; // I am serializable
public SerialTravelTimeDataArray(){ }
public SerialTravelTimeDataArray(TravelTimeDataArray ttDA){
// intialize me using ttDA's data
}
// Methods to serialize the fields.
// Methods to populate super's fields from the deserialized data containers
}
Since the super does not have an empty constructor, I get an error with the subclass's empty constructor. Is there a way to force to a subclass to have an empty constructor when the super does not?
According to The Serializable Interface:
A Serializable class must do the following:
Implement the java.io.Serializable interface
Identify the fields that should be serializable (Use the serialPersistentFields member to explicitly declare them serializable
or use the transient keyword to denote nonserializable fields.)
Have access to the no-arg constructor of its first nonserializable superclass
A no-arg constructor of a object's first nonserializable superclass is need to have access because it will be called while deserializing the object. Otherwise, an exception will be thrown. Note that serializing a object do not call its superclass's default constructor and no exception will be thrown.
If extending a class is not a must, you can consider using encapsulation like follows:
public class Foo implements Serializable {
private final double[] timeSum;
private final int[] timeCnt;
private final double[] travelTimes;
private final String linkId;
private final transient TravelTimeDataArray ttDA;
public Foo(TravelTimeDataArray ttDA) {
this.ttDA = ttDA;
this.timeSum = ttDA.getTimeSum();
this.timeCnt = ttDA.getTimeCnt();
this.travelTimes = ttDA.getTravelTimes();
this.linkId = ttDA.getLink().getId();
}
// Methods
}
If you do not need to access TravelTimeDataArray in your class, you can skip the field transient TravelTimeDataArray ttDA. Hope this can help.

java inheritance field setup vs constructor [duplicate]

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);
}

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.

Calling superclass from a subclass constructor in 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.

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