java constructor handling lack of arguments - java

i have this code here for a person details and the person should be intialized always whatever the number of possible arguments given ,like for example only height and age or salary and age
and i find it difficult to declare a constructor for every combination of arguments , is there a more optimal solution than that ??
class person {
public static final int defalut_salary=1000;
public static final int default_age=20;
public static final double default_height=6;
public static final String default_name="jack";
protected int salary;
protected int age;
protected double height;
protected String name;
person(){
}
}

I would suggest using the Builder pattern:
public final class Person {
private final int salary;
private final int age;
private final double height;
private final String name;
public Person(int salary, int age, double height, String name) {
this.salary = salary;
this.age = age;
this.height = height;
this.name = name;
}
// Getters or whatever you want
public static class Builder {
// Make each field default appropriately
private int salary = 1000;
private int age = 20;
private double height = 6;
private String name = "jack";
public Builder setSalary(int salary) {
this.salary = salary;
return this;
}
// Ditto for other properties
public Person build() {
return new Person(salary, age, height, name);
}
}
}
Usage:
Person person = new Person.Builder().setAge(25).setHeight(15).build();
You can perform validation in the Person constructor, and if you want to make any of the fields mandatory, you could take those in the Builder constructor.

Initialize all fields in a default constructor and use methods to set values in the desired fields, for example like this:
class A{
Field a;
Field b;
Field c;
public A(){
a = SOME_VALUE;
b = SOME_VALUE;
c = SOME_VALUE;
}
public A withA(Field a){ this.a = a; return this; }
public A withB(Field b){ this.b = b; return this; }
public A withC(Field c){ this.c = c; return this; }
/* other code */
}
Then you can use it like this:
A a = new A().withB(SOME_OTHER_VALUE).withC(YET_DIFFERENT_VALUE);
If don't want the fields' values to be changed with subsequent calls to withX() methods, you can use a full-fledged builder pattern.

You could define the constructor to take primitive wrapper classes (like java.lang.Integer or java.lang.Double) instead of primitives. The difference is that this allows you to pass null instead of a value. You can then check them for null. When they are null, you assign the default value. When they aren't, you assign their value.
public Person(Integer salary, Integer age, Double height, String name) {
if (salary == null) this.salary = salary else this.salary = default_salary;
if (age == null) this.age = age else this.age = default_age;
//...
}
The invocation new Person(1200, null, 5.3, null); would mean "create a person with start salary 1200, default age, height 5.3 and default name".
Another approach is to use the builder pattern as shown in the answer by Jon Skeet. It is less concise, but more readable.

Related

How can I change the value of a field from a different class?

Here is a quote from my exercise:
The method weight queried some information from the parameter object by calling its method. It is also possible to change the state of the parameter. Add to class Reformatory the method public void feed(Person person) that increases the weight of its parameter by one.
The problem is I cant think how to do this without using a constructor or extra parameters that were not given in the exercise template.
Main
public class Main {
public static void main(String[] args) {
Reformatory theReformatory = new Reformatory();
Person brian = new Person("Brian", 1, 110, 7);
Person pekka = new Person("Pekka", 33, 176, 85);
System.out.println(theReformatory.weight(brian));
theReformatory.feed(brian);
System.out.println(theReformatory.weight(brian));
}
}
Person
public class Person {
private String name;
private int age;
private int height;
private int weight;
public Person(String name, int age, int height, int weight) {
this.name = name;
this.age = age;
this.height = height;
this.weight = weight;
}
public int getWeight() {
return this.weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
Reformatory
public class Reformatory {
private int weight;
public int weight(Person person) {
weight = person.getWeight();
return weight;
}
public void feed(Person person) {
weight++;
}
}
In the same way that you use person.getWeight() in the weight(Person person) method, you can use getWeight together with setWeight:
int newWeight = person.getWeight() + 1;
person.setWeight(newWeight);
You can of course also collapse this to a single line, if you want:
person.setWeight(person.getWeight() + 1);
Don't declare field weight in your Reformatory.
public class Reformatory {
public int weight(Person person) {
return person.getWeight();
}
public void feed(Person person) {
person.setWeight(person.getWeight()+1);
}
}
Java is pass by value and it is not possible to pass primitives by reference in Java. Therefore, in the Reformatory class you should get the Person's weight, increase it and set it again in Person object.
In Reformatory:
public void feed(Person person) {
person.setWeight(person.getWeight()+1);
}
Your solution increases the weight of the Reformatory object and not the Person's object.

Constructor + Inheritance support

I am fairly new to Inheritance, and I'm not sure if I am doing it right but I seem to be on the right track. The program runs fine except the output I am getting isn't right. I think the problem is to do with my constructors.
public class Person {
protected static String name;
protected static int birthYear;
public Person(String name, int birthYear) {
}
public String name (String n) {
n = name;
return n;
}
public int birthYear (int bY) {
bY = birthYear;
return bY;
}
#Override
public String toString() {
return String.format(name + birthYear);
}
}
public class Student extends Person {
protected String major;
public Student(String name, int birthYear, String major) {
super(name, birthYear);
major = "";
}
public String major(String maj) {
maj = major;
return maj;
}
public String toString() {
super.toString();
return super.toString() + major;
}
}
public class Instructor extends Person {
protected static int salary;
public Instructor(String name, int birthYear, int salary) {
super(name, birthYear);
salary = 0;
}
public int salary(int sal) {
sal = salary;
return sal;
}
public String toString() {
super.toString();
return super.toString() + salary;
}
}
public class PersonTester {
public static void main(String[] args) {
Person p = new Person("Perry", 1959);
Student s = new Student("Sylvia", 1979, "Computer Science");
Instructor e = new Instructor("Edgar", 1969, 65000);
System.out.println(p);
System.out.println("Expected: Person[name=Perry,birthYear=1959]");
System.out.println(s);
System.out.println("Expected:" +
"Student[super=Person[name=Sylvia,birthYear=1979],major=Computer]");
System.out.println(e);
System.out.println("Expected:" + "Instructor[super=Person[name=Edgar,birthYear=1969],salary=65000.0]");
}
}
OUTPUT I AM GETTING:
null0
Expected: Person[name=Perry,birthYear=1959]
null0null
Expected: Student[super=Person[name=Sylvia,birthYear=1979],major=Computer Science]
null00
Expected: Instructor[super=Person[name=Edgar,birthYear=1969],salary=65000.0]
Try changing your constructor in Person to:
public Person(String name, int birthYear) {
this.name = name;
this.birthYear = birthYear;
}
Currently, the constructor has an empty body, so when you call super(name, birthYear); in the subclass constructor, nothing actually happens.
Your Student constructor also has an error. You forgot to initialize the major field.
public Student(String name, int birthYear, String major) {
super(name, birthYear);
this.major = major;
}
You have the same problem in the Instructor constructor...
public Instructor(String name, int birthYear, int salary) {
super(name, birthYear);
this.salary = salary;
}
Finally, you need to take away the static keywords before the fields in Person. This is because static ensures, that there will always be one (and only one) instance of those fields per class, as opposed to one per instance, like you want it to be:
protected String name;
protected int birthYear;
Same thing for the salary field in Instructor.
n = name; this causing your problem. It must be name = n;. All your setter function contain this problem, correct them all and tell me result.

Java auto increment issue

I'm having trouble with this requirement. I have this snippet:
private String id;
private int age;
private static int index;
public Customer(int a) {
this.id = a + "C" + index;
index++;
this.age = a;
}
It works fine. But the thing is, I want for every age the index will be reset to 1, like <10C1, 10C2> when there are 2 10-year-old customers and if you create a new customer with the age of 20 it will go back to <20C1,20C2,..>. Since there are no restriction to the age so the if statement seems not possible.
Use a static map in user:
private String id;
private int age;
private static map indexMap = new HashMap();
public Customer(int a) {
this.id = a + "C" + index;
index++;
this.age = a;
}
public synchronized static int getIndexOfAge(int age) {
if (!indexMap.contains(age)) {
indexMap.put(age, 1);
}
int theIndex = indexMap.get(age);
theIndex++;
indexMap.put(age, theIndex);
}
But I have to say this is really not a good way to code. You should use something like UserIndexFactory to create user index. You should also consider the thread safe and performance.

Inheritance super variables

I'm writing a simple program in which I have a super class Person inherited by the sub-classes Customer and Employee (they inherit the variables ID, name and surname).
public class Person {
int id;
String name;
String surname;
public Person() {}
public Person(int i, String n, String s) {
id = i;
name = n;
surname = s;
}
}
public class Employee extends Person implements Serializable {
String username;
String password;
String date;
int hpw;
int recordSold;
float hourPay;
public Employee() {}
public Employee(String u, String n, String s, String p, int i, int h, String d, int rSold, float hPay) {
username = u;
super.name = n;
super.surname = s;
password = p;
super.id = i;
hpw = h;
date = d;
recordSold = rSold;
hourPay = hPay;
}
}
However the problem is here: when I try to get the variables ID, name and surname through my main class, they fail to return (0,null,null). Why is this? I have get-Methods in my sub-classes which should return the super variables, but they are not. Thanks for your time and patience.
public String getName() {
return super.name;
}
UPDATE:
ok so I sorted out the super(id,name,surname) in the Employee class constructor. I also removed all the getters and setters in the employee class since those are inherited from the Person superclass (correct me if I'm wrong?..)
Person superclass:
public class Person {
private int id;
private String name;
private String surname;
public Person () {
}
public Person(int i, String n, String s) {
this.id = i;
this.name = n;
this.surname = s;
}
public void setID(int i) {
this.id = i;
}
public void setName(String n) {
this.name = n;
}
public void setSurname(String s) {
this.surname = s;
}
public int getID() {
return id;
}
public String getName() {
return name;
}
public String getSurname() {
return surname;
}
}
Employee subclass:
import java.io.*;
public class Employee extends Person implements Serializable {
protected String username;
protected String password;
protected String date;
protected int hpw;
protected int recordSold;
protected float hourPay;
public Employee() {
super();
}
public Employee(int i, String u, String n, String s, String p, int h, String d, int r, float hP) {
super(i,n,s);
username = u;
password = p;
date = d;
hpw = h;
recordSold = r;
hourPay = hP;
}
public void setUser(String u) {
username = u;
}
public void setPassword(String p) {
password = p;
}
public void setHWeek (int h) {
hpw = h;
}
public void setDate (String d) {
date = d;
}
public void setRSold (int r) {
recordSold = r;
}
public void setHPay (float p) {
hourPay = p;
}
public String getUser() {
return username;
}
public String getPassword() {
return password;
}
public int getHWeek() {
return hpw;
}
public String getDate() {
return date;
}
public int getRSold() {
return recordSold;
}
public float getHPay() {
return hourPay;
}
however, when I run the main program the ID, name and surname variables are still null, they are not being returned by the superclass. Am I missing something please? Thanks
Inheritance only works for methods NOT for variables. It is also bad practice to implement methods in subclasses that access super class variables directly. You'd better implement access methods in your superclass. Due to inheritance, those methods will be available in the sub-classes ass well.
Another thing is the visibility of you instance varibles. You are using the default visibility which is "package-wide". So if your sub-classes are not in the same package, they can't access those variables. If you use "private" or "protected" visibility you are much safer accessing the variables.
Another point is that you are initializing the objects not correctly. Calling the sub-class constructor has to call the super-class constructor as well because your Employee object relies on the functionality that your Person object provides. A more scientific description of this principle exists:
Barbara Liskov - Liskov substitution principle
public class Person {
private int id;
private String name;
private String surname;
public Person() {}
public Person(int i, String n, String s) {
id = i;
name = n;
surname = s;
}
public int getId() {
return this.id;
}
public String getName() {
return this.name;
}
public int getSurname() {
return this.surname;
}
}
Add access methods for super class instance variables and set visibility to private.
public class Employee extends Person implements Serializable {
private String username;
private String password;
private String date;
private int hpw;
private int recordSold;
private float hourPay;
public Employee() {}
public Employee(String u, String n, String s, String p, int i, int h, String d, int rSold, float hPay) {
super(id, name, surname);
this.username = u;
this.password = p;
this.hpw = h;
this.date = d;
this.recordSold = rSold;
this.hourPay = hPay;
}
}
Call the super class constructor for initialization of the super class.
Your code should look something like this:
public class Person {
private int id;
private String name;
private String surname;
public Person (int id, String name, String surname) {
this.id = id;
this.name = name;
this.surname = surname;
}
public int getId() {
return id;
}
... //similarly for getName() and getSurname()
}
public class Employee extends Person {
private String username;
private String password;
private String date;
private int hpw;
private int recordSold;
private float hourPay;
public Employee (int id, String name, String surname, String username, String password, String date, int hpw, int recordSold, float hourPay) {
super(id, name, surname);
this.username = username;
... //similarly for other parameters.
}
}
The important bit is super(id, name, surname).
EDIT
lionc claims that I did not answer the question, which is true. I did this because the original poster seems to be new to Java and, hence, might be asking the "wrong" question. I should have highlighted this in my original response. Given that my answer is currently marked as the best, I believe that I made the right decision.
You haven't initialized those variables, that's why it is returning default value for those variables. In java following are default values for variables.
int -> 0
String -> null (because String is Object in Java)
You define those attributes in both of your classes so you override them in the subclass. Moreover, your Employee constructor is not the way it should. You should call the adapted super-constructor as your first statement.
public class Person {
protected int id;
protected String name;
protected String surname;
public Person(int id, String name, String surname) {
this.id = id;
this.name = name;
this.surname = surname;
}
}
public class Employee extends Person implements Serializable {
private String username;
private String password;
private String date;
private int hpw;
private int recordSold;
private float hourPay;
public Employee(String username, String name, String surname, String pswd, int id,
int hpw, String date, int rSold, float hPay) {
super(id,name,surname);
this.username = username;
this.password = pswd;
this.hpw = hpw;
this.date = date;
this.recordSold = rSold;
this.hourPay = hPay;
}
}
In your constructors, I consider a best practice to give the same name to your parameters as the name of your attributes to initialize and differenciate them thanks to this. Some people also use the same names except that they add a _ at the beginning of all the members of the class. In any case, don't use such meaningless names as "s", "n" etc when the variables they represent have a special meaning (surname, name). Keep those names for example for local variables without any particular semantic (n would be an integer, s would be a String...).
In your example, you don't need tu use super to access the attributes defined in the super class since you are using package visibility for them (and both seems to be in the same package).
However, this is NOT the proper way to write Java code.
You should define a visibility for your attributes. In most case, it is recommended to use private visibility and to define getter and setter methods to access them:
public class Person {
private int id;
private String name;
private String surname;
public Person() {}
public Person(int id, String name, String surname) {
this.id = id;
this.name = name;
this.surname = surname;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
// And so on...
}
In sub-classes, you just have to call getId() or setId(...) to access the Id attribute. No need to call super.getId(). Since Employee extends Person, it has access to all of its public, protected (and package if they are in the same package) attributes and method.
This means that in your current code, you can simply write name = n instead of super.name = n.
public class Employee extends Person implements Serializable {
private String username;
private String password;
private String date;
private int hpw;
private int recordSold;
private float hourPay;
public Employee() {}
public Employee(String username, String name, String surname, String password, int id, int hpw, String date, int rSold, float hPay) {
super(id, name, surname);
this.username = username;
this.password = password;
this.hpw = hpw;
this.date = date;
this.recordSold = rSold;
this.hourPay = hPay;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
// And so on...
}
Now to use these classes, you can write code like:
Employee e = new Employee("user3149152", "Ulrich", "Ser", "passwd", 1234, 0, "2014/08/13", 0, 0);
System.out.println("Employee " + e.getName() + ' ' + e.getSurname() + " has for id " + e.getId() + '.');
For reference, this code works even with your current code.
It prints:
Employee Ulrich Ser has for id 1234.

Create a default constructor in Java

I need to create a method with a default constructor, which sets name to an empty string and sets both credits and contactHours to zero. How to do it? Thanks, Pieter.
Methods don't have constructors... classes do. For example:
public class Dummy
{
private int credits;
private int contactHours;
private String name;
public Dummy()
{
name = "";
credits = 0;
contactHours = 0;
}
// More stuff here, e.g. property accessors
}
You don't really have to set credits or contactHours, as the int type defaults to 0 for fields anyway.
You're likely to want at least one constructor which takes initial values - in which case your parameterless one can delegate to that:
public class Dummy
{
private String name;
private int credits;
private int contactHours;
public Dummy()
{
this("", 0, 0);
}
public Dummy(String name, int credits, int contactHours)
{
this.name = name;
this.credits = credits;
this.contactHours = contactHours;
}
// More stuff here, e.g. property accessors
}
public class Test {
private String name;
private int credits;
private int contactHours;
public Test {
this( "", 0, 0);
}
public Test (String name, int credits, int contactHours) {
this.name = name;
this.credits = credits;
this.contactHours = contactHours;
}
// more code here
}
public class Bibabu{
private String name;
private int credits;
private int contactHours;
public Bibabu(){
name = ""; // you could also write this.name and so on...
credits = 0;
contactHours= 0;
}
// more code here
}
You don't need a constructor:
public class Dummy
{
private int credits = 0;
private int contactHours=0;
private String name="";
/*
public Dummy()
{
name = "";
credits = 0;
contactHours = 0;
}
*/
// More stuff here, e.g. property accessors
}
//constructor
public Account(int id, double balance, Person owner){
this.id = id;
this.balance = balance;
this.owner = owner;

Categories

Resources