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.
Related
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.
edit: added employee constructors;
my question involves constructor chaining for a subclass (to a super which is itself a subclass). I have written constructors that seem to work, but I feel that they are incorrectly written as I will explain. PTEmployee extends to Employee who is extended to a Person. The code below seems to work in my test class,
public class PartTimeEmployee extends Employee {
public static final int DEFAULT_HOURSPRWK = 0;
private int hoursPerWk;
public PartTimeEmployee() {
this(DEFAULT_HOURSPRWK);
}
public PartTimeEmployee(int hoursPerWk) {
this(DEFAULT_HIRE_DATE, DEFAULT_INCOME, hoursPerWk);
}
public PartTimeEmployee(String hireDate, double incomeWk, int hoursPerWk) {
super(hireDate, incomeWk);
this.hoursPerWk = hoursPerWk; // I dont think I need two this.var?
}
public PartTimeEmployee(String firstName, String surname, int age, Address address, String hireDate, double incomeWk, int hoursPerWk) {
super(firstName, surname, age, address, hireDate, incomeWk);
this.hoursPerWk = hoursPerWk;
}
But I feel that the use of two constructors with (super) and this.hoursPerWk = hoursPerWk is wrong, shouldn't '(super)' and 'this.var = var' only need to be written once? If I adjust the code to remove the PTEmp(hiredate, incomewk, hrswk) constructor than I get a 'no constructor found' error in my second constructor. Other edits have led to recursor errors.
So the supplied code works and calls all details in my test class, but is it correctly written (I need to have a Person class that is extended by Employee which is extended by PTEmp or Boss etc.). Appreciate any feedback (or jsut to know this is correct if it is.
Thanks.
Added Employee constructors here...
public class Employee extends Person {
public static final String DEFAULT_HIRE_DATE = "00/00/00";
public static final double DEFAULT_INCOME = 0;
private String hireDate;
private double incomeWk;
public Employee() {
this(DEFAULT_HIRE_DATE, DEFAULT_INCOME);
}
public Employee(String hireDate, double incomeWk) {
this(DEFAULT_FIRSTNAME, DEFAULT_SURNAME, DEFAULT_AGE, new Address(), hireDate, incomeWk);
}
public Employee(String firstName, String surname, int age, Address address, String hireDate, double incomeWk) {
super(firstName, surname, age, address);
this.hireDate = hireDate;
this.incomeWk = incomeWk;
}
Not sure what super() does if you don't specify names, address, etc, but assuming that you can use some defaults, maybe you can call it like this:
public PartTimeEmployee(String hireDate, double incomeWk, int hoursPerWk) {
this(DEFAULT_FIRST_NAME, DEFAULT_SURNAME, DEFAULT_AGE, DEFAULT_ADDRESS, hireDate, incomeWk, hoursPerWk);
}
Consider using builder patterns, if you think that you have too many overloaded constructors:
When would you use the Builder Pattern?
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.
The Question is:
1) How can i get subclass parameter values to superclass?
2) i want to take the name(From subclass) for collection.sort , like this.model.compareTo(other.model). However, I don't know how to get the "Name" Value from subclass and do the collection.sort.
** Is it correct to write public int compareTo(Car other, Taxi other2)??? **
Here is the code:
public class Car implement comparable <Car>()
{
private string model;
private int price;
public car(String model , int price)
{
this.model=model;
this.price=price;
}
............some getmethod here..........
public int compareTo (Car other)
{
** Want to sort by name , like this.model.compareTo(other.model)**
}
}
Taxi.java:
public class taxi extends Car ()
{
private string name;
public taxi (String model , int price, String name)
{
super(model, price);
this.name = name;
}
......some getmethod here..........
}
you can use subclass values by creating object of sub class in superclass.
It is also known as delegation.
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.