How to initialize a reference attribute in a constructor in Java? - java

I'm adding an instance variable to a class "Person" which is a reference type ("Date", which I have written a class for). In the constructor for my Person class, I am therefore trying to initialize the Date attribute using the constructor of the Date class, but I am unsure how to do this. Previously I have only ever initialized primitive types (or Strings), as seen below. This is a segment from my code. I'm unsure how to initialize "birthday" so that it uses the constructor of the Date class. Thanks!
public class Person {
/* Attribute declarations */
private String lastName; // last name
private String firstName; // first name
private String email; // email address
private Date birthday; // birth date
/**
* Constructor initializes the person's name, email address, and birthday
*/
public Person(String firstName, String lastName, String email, Date birthday) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.birthday = ????

Are you saying you want to initialize this.birthday in the constructor of Person using the Date constructor? Then use the new keyword like this:
this.birthday = new Date(<arguments if any exist>);
new calls the constructor of an object. If that's the case, you do not need the Date birthday constructor argument for Person, unless you use it for something else.

You can do this:
this.birthday = new Date(birthday.getTime());
This creates a copy of the date object. Since a Date can be modified it is dangerous to use the same object, which you'd be doing if you just copied the reference:
this.birthday = birthday;
That would allow the outside world to change your birthday without you knowing about it.

You can just simple
this.birthday = (Date) birthday.clone();
Why this way instead of ?
this.birthday = birthday;
Cause outsiders can modify your date object, and then they are modifying your internal structure and that is not good, breaks encapsulation.
Why this way instead of ?
this.birthday = new Date(birthday.getTime());
Date is not a final class what happen if Date object you pass is not a "true Date" and is a subclass , if you do this don't preserve internal structure of subclass, but when you cloning preserves the information, but this approach it depends on what you want.

Related

How can I avoid misuse of a constructor with multiple parameters of the same type?

Should I avoid constructors like this?
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Because they can be misused:
Person person = new Person("Smith", "John");
And if so, what should I do instead?
Constructor with multiple fields of the same type is a valid implementation.
If you want to avoid misused issues you can use a builder pattern instead.
Person person = Person.builder().firstName("John").lastName("Smith").build();
Use builder, and Lombok project can simplify code
#Builder
public class Person {
private final String firstName;
private final String lastName;
}
Usage is
Person.builder()
.firstName("John")
.lastName("Smith")
.build();
Using the builder-pattern will help, but if you really want to avoid misuse, you should make firstName and lastName typed using value classes.
Proper value classes with no overhead will come in a later Java version, but you could use records if you're on Java 14 (preview feature) or later. It's a bit more cumbersome to make value classes on lower Java versions (you need to create a class with 1 property).
record FirstName(String firstName) {}
record LastName(String lastName) {}
Now you can do this in your constructor:
public Person(FirstName firstName, LastName lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
With this, your example where you switched "John" and "Smith" would no longer compile.
I often use this pattern when I have a lot of ID-fields I need to pass around. The consequence of mixing them up would be greater.
Another nice side effect of doing this is that your IDE (at least IntelliJ) will have more type-information to suggest auto-completion of your code. Using value classes could therefore speed up your coding a little bit :)

In Java why would you assign a variable to itself

I am learning Java at University but I am struggling to understand why you would assign a variable to itself inside a constructor.
This is example code:
private String name;
private int age;
private boolean student;
private char gender;
public Person(String name, int age, boolean student, char gender)
{
this.setName(name);
this.age = age;
this.student = student;
}
I am struggling to understand the purpose of 'this.age = age' and 'this.student = student'. These values are already assigned to whatever they hold so why would you need to do that? My only theory is that it is to initialize the variable but I'm not sure.
You are not assigning the variable to itself, this.VAR and VAR are different variables.
When using a class in Java, you can refer to your attributes by using the this prefix. In many methods the this prefix is optional because there is not any method parameter with the same name. However, when a method has variables that have the same name than the class attributes, it is mandatory to use the this prefix to differentiate between the class attribute and the method parameters (otherwise the most local variable - the method parameter - hides the most global one - the class attribute).
So when you are using:
this.age = age
you are initializing your class attribute to the value of the method parameter called age.
Notice that you can avoid using the this prefix if the method parameters have always different names than the class attributes:
private String name;
private int age;
private boolean student;
private char gender;
public Person(String name, int ageParam, boolean studentParam, char genderParam){
setName(name);
age = ageParam;
student = studentParam;
gender = genderParam;
}
Personally, I think that using the this prefix is more polite because you can quickly look if you are modifying your class attributes and the method parameters preserve its useful name (which is better to document and understand the code).
The critical point here is that there are two variables called age. The first is the local variable which is a parameter to the constructor; the second is the instance variable of the Person class.
Inside the constructor, the parameter hides the instance variable, so just writing age will always refer to the parameter. However, if you write this.age, you must be referring to the instance variable. Thus:
this.age = age
assigns the value of the constructor parameter to the instance variable.
This is only because of naming conventions that you have this, in fact this is 100% the same :
private String name;
private int age;
private boolean student;
private char gender;
public Person(String nnn, int aaa, boolean sss, char ggg){
this.setName(nnn);
this.age = aaa;
this.student = sss;
this.gender = ggg;
}
But with this, this. becomes useless, because age = a; is ok, that's why when there is a misunderstand possible you use this. to precise that it's the attribute of the class, different of the parameter of the constructor.
this.age = age , this.age is the variable associated with class Person's object (this keyword refers to the class' object reference) , and age is a local variable (it's scope is just within constructor definition) whose value that you are passing in the constructor to be assigned to the object's variable.
So when you call class's constructor when creating object :
Person p = new Person("name",22,true,'M');
the p object's age will be set as 22 .
If you would have used :
public Person(String name, int yearsOld, boolean student, char gender)
{
this.setName(name);
age = yearsOld;
//here you could avoid using this since local variable name is different and age will refer to class level's age .
this.student = student;
}

Java QueryDSL 3.6.0 Projection.bean(Person.class, person.firstName, person.count())

I am using QueryDSL in my project to return a list of Person groupBy LastName and no of persons with that lastName. Below is the Person.java
#Entity
class Person {
private String firstName;
private String lastName;
private boolean isCitizen;
private int age;
private int groupByCount; //Property to return groupByCount - could use Group tuple for this, but doing a research trying to set it as an object field.
//Constructors to support n! ways of object creation - where n is no of fields in the object
public Person(String lastName, int groupByCount){
this.lastName = lastName;
this.groupByCount = groupByCount;
}
public Person(int age, int groupByCount){
this.age = age;
this.groupByCount = groupByCount;
}
public Person(boolean isCitizen, int groupByCount){
this.isCitizen = isCitizen;
this.groupByCount = groupByCount;
}
// keeps going to cover all possible constructors - i want to avoid this for maintainability reasons - want to be able to build objects dynamically with different parameters
//Below is code for Getter and setters for above fields
}
The QueryDSL query which uses these Constructors are below.
personRepo.getQueryDSL().createQuery(person).groupBy(person.lastName)
.list(Projections.constructor(Alarm.class, person.lastName, person.count());
personRepo.getQueryDSL().createQuery(person).groupBy(person.age)
.list(Projections.constructor(Alarm.class, person.age, person.count());
personRepo.getQueryDSL().createQuery(person).groupBy(person.isCitizen)
.list(Projections.constructor(Alarm.class, person.isCitizen, person.count());
How to avoid writing those n! constructors for a class with n fields using QueryDSL ?? I tried Projections.bean like below, after removing the constructors in the Person class
personRepo.getQueryDSL().createQuery(person).groupBy(person.isCitizen)
.list(Projections.bean(Alarm.class, person.isCitizen, person.count());
It complains .count() is not a valid expression. It is notable to assign the value of count to groupByCount field in person object. How to set groupByCount of the person object with person.count() value using Projections.bean method ??
Thanks in Advance. Really appreciate your help.
I believe that Projections.fields is what you're looking for. Have the setter names in the POJO mirror the column names in the query - it looks like you already have this in place.
I chained .as method on top of .count to groupByCount attribute as shown below. This way I was able to avoid writing n! constructors.
personRepo.getQueryDSL().createQuery(person).groupBy(person.isCitizen)
.list(Projections.bean(Alarm.class, person.isCitizen,
person.count().as(person.groupByCount));

Passing constructor parameters to initialize an object [duplicate]

This question already has answers here:
How to initialize a reference attribute in a constructor in Java?
(3 answers)
Closed 7 years ago.
I'm writing a java class that borrows elements of another class and need to pass three of the four parameters of the constructor to initialize the other class object. I'm lost as to how to initialize it, though. Any help is much appreciated. Here's what I have right now:
private String name;
private MyDate birthday;
/**
* Constructs a new Person object.
*/
public Person(String name, int month, int day, int year) {
this.birthday = birthday(month, day, year);
this.name = name;
}
This will depend on whether or not the birthday class is connected by some means (extended or friended) or if the birthday.birthday field is publicly accessible.
For example, if you wanted to keep up with good practice. You could set up a
GetBirthday(); method inside of the birthday class and do the following.
private MyDate birthdate;
public Person(String name, int month, int day, int year) {
birthday bDay = new birthday(month, day, year);
this.birthdate = bDay.GetBirthday();
this.name = name;
}
You could also create an inline function birthday() which calculates birthdays, but I would not advise doing it as such.

Specific Datatype for this situation?

I want to pull data from a database. Name, Age, Sex, Location.(maybe more fields)
I want to hold the data in an object similar to how I would expect it to look in a JSON object.
Like:
myData{
row1[name:beavis, age:48, sex:male, location:Joburg]
row2[name:quintus, age:43, sex:, location:Helsinki]
...up to say 500 rows
}
So i'd like to be able to do tempName = row(i).name and so on in java.
Any suggestions.
// Defines a Person datatype
public class Person {
// fields
private String name;
private int age;
private String location;
// gets the value of a field
public String getName() {
return name;
}
// sets the value of a field
public void setName(aName) {
this.name = aName;
}
}
What I did here was define a Person type with a number of fields. Also I give here an example of a setter and getter for the name field. You can put them in an array or collection. For example:
Person people[] = new Person[2];
people[0] = new Person();
people[0].setName("Alice");
You can also dispense with the setters and getters by making the fields public, but I wouldn't recommend it.
A straight translation of that data structure would be along the lines of
List<Map<String, Object>> myData
so you'd be able to call
tempName = (String) myData.get(i).get("name");
Like the JSON array, this doesn't enforce typing (which you'll have to deal with explicitly in Java) and doesn't limit the fields to only those from the database.
If all the database values are strings, things get cleaner as no casts are necessary.
List<Map<String, String>> myData
tempName = myData.get(i).get("name");

Categories

Resources