Consider this scenario,
I have two classes Student and HonorsStudent respectively.
class Student{
String name;
int roll;
Student(String name, int roll){
this.name = name;
this.roll = roll;
}
}
class HonorStudent extends Student{
int honorid;
HonorStudent(String name, int roll,int honorid){
this.name = name;
this.roll = roll;
this.honorid = honorid;
}
HonorStudent(String name, int roll){
this.name = name;
this.roll = roll;
}
}
Now, there might be scenarios in which I might want to convert a Student into an HonorStudent. Since downcasting is not allowed in this situation, I can't do this:
Student s1 = new Student("abc",123);
HonorStudent s = (HonorStudent)s1;
So the other way of doing this would be to define a method in HonorStudent which inputs a Student Object and returns a HonorStudent:
public static HonorStudent convertToHonor(Student s){
return new HonorStudent(s.name,s.roll);
}
This is convenient if there are only two attributes(name, roll), but what if I have a lot of attributes say 50 ? In that case I would have to input each and every attribute into HonorStudent?
I strongly feel there might be an easier way to do this?
You are asking if there is a more convenient way to do this. If we consider just copying parameters from one object to another then there is no another way to do this. There might be ways to work around the problem by having objects for groups of member fields or by automating it by code that can copy member fields with same name from object to another.
Small fix
But first, let's improve design a bit. Fields should not be duplicated like this between classes in a class hierarchy. So let's eliminate that duplication:
public class Student {
private String name;
private int roll;
public Student(String name, int roll) {
this.name = name;
this.roll = roll;
}
public String getName() {
return name;
}
public int getRoll() {
return roll;
}
}
public class HonorStudent extends Student {
private int honorId;
public HonorStudent(String name, int roll, int honorId) {
super(name, roll);
this.honorId = honorId;
}
public int getHonorId() {
return honorId;
}
}
Copy constructor
If there is really a need to copy objects then copy constructor can be useful. Creating a copy constructor will allow you to skip passing each member field only by one.
public Student(Student other) {
this.name = other.name;
this.roll = other.roll;
}
Then creating Student part of the HonorStudent becomes simpler
public HonorStudent(Student student, int honorId) {
super(student);
this.honorId = honorId;
}
Design
Now it is not common that objects change their type. So this is not a common thing to do. This is usually solved by different kind of design of classes. For example, honorId could be part of Student class because, I guess, student can gain this attribute or loose it. Behaviour related to honor can be in some other class that is attached to student class.
Reading about behavioural design patterns can be useful. Depending which pattern to choose will depend on the use case and the problem that you are trying to solve.
Related
Just a question RE: Constructor Chaining in subclasses that I can't find a good answer on and I'm confusing myself a bit with.
I'm making a basic little Text Based RPG for some practice and I'm going through my constructors for an abstract class and have the constructors from 0-4 params chained together like below
abstract class Creature {
// Fields
private String name;
private int lifeForce;
private int strength;
private int agility;
// Constructors + Chaining
public Creature() {
this("Unknown")
}
public Creature(String name) {
this(name, 100);
}
public Creature(String name, int lifeForce) {
this(name, lifeForce, 10);
}
public Creature(String name, int lifeForce, int strength) {
this(name, lifeForce, strength, 10);
}
public Creature(String name, int lifeForce, int strength, int agility) {
this.name = name;
this.lifeForce = lifeForce;
this.strength = strength;
this.agility = agility;
}
My confusion is how best to format the constructors of a subclass of creature, for example this simple Person class introduces two new fields. There's definitely too much repetition if I write the constructors like this
// Constructors + Chaining
public Person() {
super("Unknown");
this.skillClass=new Mage();
this.dialogue="...";
}
public Person(String name) {
super(name);
this.skillClass=new Mage();
this.dialogue="...";
} etc etc etc
I suppose I could restrict the constructors to limit the repetition but I'm mostly just wondering if there's good best practice that I'm missing here.
Any and all suggestions welcome and if anyone has any good resources to recommend that go deeper than the usual
Class B extends Class A
examples I'd massively appreciate.
In situations like this one when you need to use multiple constructors with different parameters, it is recommended to use the builder pattern like this :
abstract class Creature {
// Fields
private String name;
private int lifeForce;
private int strength;
private int agility;
private Creature(Builder<?> builder) {
this.name = builder.name;
this.lifeForce = builder.lifeForce;
// Add the other attributes here.
}
public static abstract Builder extends Builder<T extends Builder<T>> {
private String name;
private int lifeForce;
private int strength;
private int agility;
public Builder(//here you put the attributes that you need to have in all instances) {
// here you do the affectations.
}
// now you need to make the functions that set each property :
public Builder lifeForce(int lifeForce) {
this.lifeForce = lifeForce;
return this;
}
// you do the same thing for all the other attributes.
...
public Creature build() {
return new Creature(this);
}
}
}
So for the explanation : This pattern will allow you to create instances of your class by setting only the needed attributes.
As here you have subclasses the builder pattern will be little bit more harder to understand but it is the perfect solution in such situation.
We need to apply the builder pattern also for every subclasse so let's do it for the person class :
public class Person extends Creature {
private int anotherField;
public Person(Builder builder) {
super(builder);
this.anotherField = anotherField;
}
public static Builder extends Creature.Builder<Builder> {
public Builder(//add the fieldHere if it is needed in all class instances) {
// if the field is not mandatory you can omit this constructor but you need to put the function below.
}
public Builder anotherField(int anotherField) {
this.anotherField = anotherField;
}
public Person build() {
return new Person(this);
}
}
Now let me show you how tricky is this solution :
1/ declare person with 2 fields :
Person p1 = Person.Builder().name("name").anotherField(0).build();
2/ declare another one with just one field
Person p2 = Person.Builder().agility(1000).build();
Remark : In these two examples, i supposed that your builders' constructors don't have parameters. If for example the name is mandatory field :
Person p3 = Person.Builder("name").anotherField(0).build();
I wish that you had the idea about using builder pattern.
I have the following interface:
public interface IStaff {
public StaffPosition getPosition();
public String toString();
}
and the class:
public class Worker implements IStaff {
private String name = null;
private String surname = null;
private int age = 0;
//StaffPosition is an enumeration class
private StaffPosition position= null;
public Worker (String name, String surname, int age, StaffPosition position){
this.name = name;
this.surname= surname;
this.age= age;
this.position= position;
}
#Override
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append(this.name);
buffer.append(" ");
buffer.append(this.surname);
return buffer.toString();
}
#Override
public StaffPosition getPosition() {
return this.position;
}
public int getAge(){
return this.age;
}
In another class - Building, I have a HashMap<Office, IStaff> officeswhere Office is a normal class which only holds the number of the office and has a getter for that number.
And then in a yet another class Company I have an ArrayList<Building> buildings, which holds information about all the buildings of a company. In this class I need to get the age of a worker but how can I do that? So far I have a loop like this to get to the map:
for (Building building: buildings) {
for (Map.Entry<Office, IStaff> office: building.offices.entrySet()) {
//get the age of a worker
}
}
Is there a way to do that?
The only real answer is: when you need such an information in places where only your interface should show up, then that information needs to sit on the interface.
So your interface could have a method getAge(), or maybe getBirthday().
Side notes:
using I for "interface" in class names ... is bad practice, or at least: very much against java conventions.
you don't need to have a toString() in your interface. You get one from Object anyway.
(of course, there are dirty tricks, like doing an instanceof check somewhere, and then casting to the type of the concrete class. But as said: that is really bad practice)
Make IStaff an abstract class and then call the method.
UML Diagram
I am brand new to Java, though I've taken other programming courses. I'm really struggling with the class concept from a UML diagram. I have a parent class and two child classes. My assignment is to create this class structure. I am struggling with the concept of class and relationships in general though.
Example: If my parent class is "Animal" and my child classes are "Monkey" and "Bear" - if the only choices that will be implemented are "Monkey" and "Bear", this makes the class "Animal" an abstract class distinction as there will never be just "Animal", it will always be a "Monkey" or a "Bear".
So, how would I create three files (Animal.java, Monkey.java, Bear.java) if Animal is abstract? I understand that the properties and traits of Animal are inherited by Monkey and Bear. Assuming that I have, for instance, name and age of the animal as attributes and getters and setters for each - if name and age of "Animal" class are private (code below), how does "Bear" class pick up the name and age if it is in its own java file/class? My code is below...
Animal.java
public class Animal {
private String animalName;
private int animalAge;
public void setName (String name) {
animalName = name;
}
public void setAge (int age) {
animalAge = age;
}
public static String getName() {
return animalName;
}
public static String getAge() {
return animalAge;
}
}
Bear.java
public class Bear {
public int weight;
public static int weight() {
return weight;
}
}
// This is where I get stuck & don't know where to go from here.
I understand that I am creating an object "Bear" which is part of the class "Animal", but as Bear is its own class, how does "Bear" get its assigned values from Animal? I can assign "Animal" and "Bear" with default values, but my brain cannot put together how they're talking to one another.
This might be outside the scope of this forum but my professor is unresponsive and I've read through books, ebooks, the course material, and several lectures and this is just not coming to me and I'm two weeks behind at this point trying to understand this concept so I can move forward with the actual code in the program.
Thanks in advance.
You forgot to do this:
public class Bear extends Animal {
// ...
}
I would recommend that you add constructors:
public class Animal {
private String name;
private int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() [ return this.name; }
public int getAge() { return this.age; }
}
public class Bear extends Animal {
private int weight;
public Bear(String name, int age, int weight) {
super(name, age);
this.weight = weight;
}
public int getWeight() { return this.weight; }
}
You can do this, because Bear IS-A Animal:
Animal b = new Bear("Smokey", 10, 300);
System.out.println(b.getName()); // prints "Smokey"
I'm writing a simple program that displays a persons card number, name and limit in Java fx. How can i make it so that a subclass inherits one less argument in its constructor? I have 2 different card types, a debit card, that has no limit, and a credit card that I will give a limit when creating the object.
public AccountData(String id, String name, int limit) {
this.id = id;
this.name = name;
this.limit = limit;
}
So when creating a debit card subclass that extends AccountData, I do not want the limit argument, because it does not have one.
Thank you in advance.
The clean way would be to leave the limit out of your AccountData class (since it is obviously not a common property) and only introduce it in your credit card class:
public class AccountData {
private String id;
private String name;
public AccountData(String id, String name) {
this.id = id;
this.name = name;
}
}
public class CreditCardAccountData extends AccountData {
private int limit;
public CreditCardAccountData(String id, String name, int limit) {
super(id, name);
this.limit = limit;
}
}
If you want to stick to your current approach, you can add a second constructor to your AccountData class and e.g. set the limit to a default value (maybe Integer.MAX_VALUE or -1, although the former seems more appropriate):
public AccountData(String id, String name) {
this(id, name, Integer.MAX_VALUE);
}
I have 2 different card types, a debit card, that has no limit, and a credit card that I will give a limit when creating the object.
Then presumably CreditCard and DebitCard are subclasses of the AccountData type; so make the limit a property of the CreditCard subclass, not AccountData:
class AccountData {
AccountData(String id, String name) { ... }
}
class CreditCard extends AccountData {
CreditCard(String id, String name, int limit) {
super(id, name);
this.limit = limit;
}
}
class DebitCard extends AccountData {
DebitCard(String id, String name) {
super(id, name);
}
}
Just add another constructor for debit cards in the super class that takes less arguments
Just write a new constructor with less argument something like this:
class DebitCard extends AccountData {
public DebitCard(String id, String name) {
super(id, name, Integer.MAX_VALUE);
}
}
Conceptually, I will suggest to rework on design as it won't be a good idea to have one child class with different sets of inherited members and other child class having different, both inheriting the same parent class.But, for adhoc, I can suggest to make private int limit, in AccountData and CreditCard class. In this, way you can protect your member.
If you just have a constructor with less argument, will create issues. As, if limit is public, it can be accessed from DebitCard class as it will inherit.
So, better to make private int limit to both AccountData and CreditCard class.
Well, i was trying to pass arraylist of objects from one activity to another. I have 2 constructors in the class Student.
If, i use, Serializable than the code is like below:
#SuppressWarnings("serial")
public class Student implements Serializable
{
private int studentdID;
private String studentName;
private String studentDept;
public Student(){}
public Student(String name, String dpt)
{ this.studentName = name;
this.studentDept = dpt;}
public Student(int id, String name, String dpt)
{ this.studentdID = id;
this.studentName = name;
this.studentDept = dpt; }
public int getstudentdID() { return studentdID; }
public void setstudentdID(int studentdID) {this.studentdID = studentdID;}
public String getstudentName() { return studentName;}
public void setstudentName(String studentName) {this.studentName = studentName;}
public String getstudentDept() { return studentDept; }
public void setstudentDept(String studentDept) { this.studentDept = studentDept;}
}
But the problem i am facing is that how am i going to do this with parcelable? How am i going to set the values of the variables in class-like i did with Serializable? I mean separately using 2 constructors-one without ID another without the ID?
Did you read how Parcelable works?
You need only one constrcutor for parcelable to read what you pass to it, and Parcelable interface will add a method writeToParcel where you put the data to save.
It's not an automatic process like Serializable, everything is up to you.
The constructor which Parcelable will use will accept only one argument Parcel where you will find some methods like read*(KEY) to read back values.
And in writeToParcel you will write in the Parcel (the argument of the method) the values you want pass to pass with write*(KEY, VALUE).
Parcelable don't care about your constructors or fields.
P.S You will need a CREATOR too. Read some tutorial online to know more about it if you need.
Marco's answer explains why Parcelable doesn't automatically decide what constructor to use - it can't.
However, there is a way around this. Use Parcel.dataAvail(), which
Returns the amount of data remaining to be read from the parcel. That
is, dataSize()-dataPosition().
For example,
public Student(){}
public Student(String name, String dpt)
{
this.studentName = name;
this.studentDept = dpt;}
public Student(int id, String name, String dpt)
{ this.studentdID = id;
this.studentName = name;
this.studentDept = dpt;
}
public Student(Parcel in) {
name = in.readString();
dpt = in.readString();
if(in.dataAvail() > 0) // is there data left to read?
id = in.readInt();
}
^ The above constructor will allow for the necessary variables to be instantiated correctly. Also, you define writeToParcel() something like:
public void writeToParcel(Parcel out) {
out.writeString(name);
out.writeString(dpt);
//0 is the default value of id if you didn't initialize it like
// in the first constructor. If it isn't 0, that means it was initialized.
if(id != 0)
out.writeInt(id);
}
Of course, you'll need to define your CREATOR like so:
public static final Parcelable.Creator<Student> CREATOR = new Parcelable.Creator<Student>() {
public Student createFromParcel(Parcel in) {
return new Student(in);
}
public Student[] newArray(int size) {
return new Student[size];
}
};
#u3l solution is not required..how many constructors are there it doesn't matter.
simple it works go as normal implementation.
I mean no special care is required when multiple constructors present in parcelable.