I have a question to keyword this and variables scope in methods.
In general I know how to use this keyword, but got confused when observed the same result for all 3 options below into method balance.
The question is, what is the correct implementation of option and why it treats all the options with the same result.
Does it mean that if there is no local variable in the method balance, this keyword is ignored?
Thanks a lot!
option#1
public int balance(int balance) {
this.age = this.age + balance;
return age;
}
option#2
public int balance(int balance) {
age = age + balance;
return age;
}
option#3
public int balance(int balance) {
age = age + balance;
return this.age;
}
Code
package com;
public class Elephant {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
if (age > 0) {
this.age = age;
}
}
public int balance(int balance) {
age = age + balance;
return age;
}
public int getAge() {
return age;
}
public Elephant(String name, int age) {
this.name = name;
if (age > 0) {
this.age = age;
}
}
}
package com;
import java.util.Scanner;
public class MainClass {
public static void main(String arg[]) {
Elephant e1 = new Elephant("Elephant1: ", 7);
System.out.printf("Elephant name: %s age: %s \n", e1.getName(), e1.getAge());
Scanner sc = new Scanner(System.in);
int i = sc.nextInt();
e1.balance(i);
System.out.printf("Entered deposit for e1: %d \n", i);
System.out.printf("Balance for e1: %s", e1.getAge());
}
}
Result for all 3 options is the same:
Elephant name: Elephant1: age: 7
11
Entered deposit for e1: 11
Balance for e1: 18
Apart from situations when you need to pass or store a reference to the object from inside its instance method, you need keyword this when resolving an unqualified name requires applying disambiguation rules.
For example, this code needs it:
public void setAge(int age) {
if (age > 0) {
this.age = age;
}
}
Identifier age could refer to the member field age or the parameter age. The compiler applies the rule that parameters and local variables "shadow" fields with identical names to remove ambiguity. That is why you must prefix age with this in the assignment; otherwise, the field wouldn't be assigned.
Your balance method, on the other hand, does not need keyword this at all, because it has no ambiguous name resolutions.
In Java, this is always a reference to the current object. Object properties and methods of the current object can be accessed without explicitly mentioning this. Which one you want to use (with or without mentioning this), is often merely a matter of clarity and coding style guides.
Also see:
What is the accepted style for using the this keyword in Java?
When should I use “this” in a class?
Using the this Keyword (Oracle Java Doc)
Related
I have encountered a rather difficult problem, Suppose there is an entity class, the code is as follows:
class Human {
private Integer age; // age of the human
private String describe; // description of the human based on their age
/**
* Setter method for the age of the human
*
* #param age the age of the human
*/
public void setAge(Integer age) {
this.age = age;
}
/**
* Setter method for the description of the human
* The description is determined based on their age
*
* #param gender the gender of the human
*/
public void setDescribe(String gender) {
String describe = "";
if (this.age < 30) {
describe = "young " + gender;
} else if ( this.age <= 55 && this.age >= 30) {
describe = "middle-aged " + gender;
} else {
describe = "old " + gender;
}
this.describe = describe;
}
}
As shown in the code (just an example, the attribute or class may be arbitrary), if I use spring and use spring to generate beans, I must ensure that method setAge is called first. How can I ensure this?
If there is a table in the database that stores age and gender, how can I ensure that setAge is called first when I use jpa, mybatis or other libraries to reflect entities?
I tried to search, but I didn't find the answer. The following are the keywords I searched and some related answers, but it doesn't seem to solve my doubts:
Spring init bean, how to ensure that a setter method is executed first
Spring reflection entity class, how to ensure that a setter method is executed first
spring call setter after other setter
When jpa reflects entity classes setter methods call order
Spring setter method order
Spring - why initialization is called after setter method
For tgdavies comment,if the demand of the product is to expand the gender description function and add the age description,the class like this:
class Human {
private Integer age;
private String gender;
public void setAge(Integer age) {
this.age = age;
}
public void setGender(String gender) {
String describe = "";
if (this.age < 30) {
describe = "young " + gender;
} else if ( this.age <= 55 && this.age >= 30) {
describe = "middle-aged" + gender;
} else {
describe = "old" + gender;
}
this.gender = describe;
}
}
Test with:
spring-core-5.2.12.RELEASE.jar
spring-beans-5.2.12.RELEASE.jar
java version "1.8.0_121"
Looking forward to a better solution.
Here is my code for testing and debugging:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
public class RepositoryBean {
public static void main(String[] args) {
ApplicationContext AcContext = new AnnotationConfigApplicationContext(User.class, Configs.class);
System.out.println(AcContext.getBean("user", User.class));
}
}
#Configuration
class Configs {
#Bean
public String name() { return "the name"; }
#Bean
public int age() { return 100; }
}
#Component
class User {
private int age;
private String name;
public User() { }
#Autowired
public void setName(String name) { this.name = name; }
public User(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() { return age; }
public String getName() { return name; }
#Autowired
public void setAge(int age) {
this.age = age;
// text = Objects.requireNonNull(this.name) + age;
}
#Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
I am full of curiosity about this question. I have tried to find the answer from the source code these days (only for spring, other middleware, I have no energy to do it)
First of all, the conclusion is that when spring initializes beans, it cannot control the order in which the setter methods are called(According to the results of my investigation of the source code, there may be omissions. If there is an error in my conclusion, I hope everyone can help point out).
Now, please take a look at the documentation of Class#getDeclaredMethods:
The elements in the returned array are not sorted and are not in any particular order.
Through reflection, when using getDeclaredMethods to get the Method array, there is no "order". No "order" means that it is not sorted according to any rules, but the returned order seems to be regular every time it is called, i use the following code to test:
class User {
private int age;
private String name;
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getName() { return name; }
}
public static void main(String[] args) {
Class<User> c = User.class;
Method[] m = c.getDeclaredMethods();
Arrays.stream(m).forEach(System.out::println);
}
No matter how many times I run it(run about 20 times in a row, and run once in a while later), no matter what the setter method and attribute order in the User class are, the final output result, setAge is before setName:
public int com.anno.User.getAge()
public void com.anno.User.setAge(int)
public java.lang.String com.anno.User.getName()
public void com.anno.User.setName(java.lang.String)
or:
public void com.anno.User.setAge(int)
public int com.anno.User.getAge()
public java.lang.String com.anno.User.getName()
public void com.anno.User.setName(java.lang.String)
Therefore, in spring, when obtaining the method list through reflection, it is impossible to specify the order, and track the entire operation chain, and finally to the execution of the setter method, the method list still maintains the order in which it was obtained.
During the entire initialization process, the processing of sorting the data in the method data is not seen.
The method org.springframework.util.ReflectionUtils#getDeclaredMethods(Class<?>, boolean) use Class#getDeclaredMethods to gets the array of all methods in User:
private static Method[] getDeclaredMethods(Class<?> clazz, boolean defensive) {
Assert.notNull(clazz, "Class must not be null");
Method[] result = declaredMethodsCache.get(clazz);
if (result == null) {
try {
Method[] declaredMethods = clazz.getDeclaredMethods();
List<Method> defaultMethods = findConcreteMethodsOnInterfaces(clazz);
if (defaultMethods != null) {
result = new Method[declaredMethods.length + defaultMethods.size()];
System.arraycopy(declaredMethods, 0, result, 0, declaredMethods.length);
int index = declaredMethods.length;
for (Method defaultMethod : defaultMethods) {
result[index] = defaultMethod;
index++;
}
}
else {
result = declaredMethods;
}
declaredMethodsCache.put(clazz, (result.length == 0 ? EMPTY_METHOD_ARRAY : result));
}
catch (Throwable ex) {
throw new IllegalStateException("Failed to introspect Class [" + clazz.getName() +
"] from ClassLoader [" + clazz.getClassLoader() + "]", ex);
}
}
return (result.length == 0 || !defensive) ? result : result.clone();
}
Other related methods are as follows, please check by yourself:
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessProperties
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata
org.springframework.util.ReflectionUtils#doWithLocalMethods
The final conclusion is that no matter how the setter methods and attributes are arranged in the User entity, setAge will be called first when the bean is initialized.
In other words, the final setter method will only be called in the order of the methods in the method array returned by Class#getDeclaredMethods()
I'm not sure if other libraries provide the ability to specify the order in which the setter methods are called during reflection, so I can only assume that the order in which the setter methods are called cannot be guaranteed.
some advices
I think I understand your question, you seem to want to encapsulate the changing part into the setter method, so that even in your application, there are many places referencing this entity (say there are 100 places referencing it), you can just pass
Modify the setter method once to make the function effective for all referenced places.
I think there is really no way to control its calling order. Apart from spring, we can't figure out all the implementations of other libraries.
But we can do conversion during the development process, you can look at the concepts of PO (persistant object)
, BO(business object), DTO(data transfer object), VO(value object).
You can use PO, get the data from the xml、yml、configuration center or other data sources:
class HumanPO {
private Integer age;
private String gender;
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
public String getGender() { return gender; }
public void setGender(String gender) { this.gender = gender; }
}
Then, convert it to a business object 'BO' where you can encapsulate logic:
class HumanBO {
private Integer age;
private String gender;
private String describe;
public static HumanBO PoConvertToBo(HumanPO humanPo) {
HumanBO rt = new HumanBO();
rt.setAge(humanPo.getAge());
rt.setGender(humanPo.getGender());
rt.setDescribe(humanPo.getGender());
return rt;
}
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
public String getGender() { return gender; }
public void setGender(String gender) { this.gender = gender; }
public String getDescribe() { return describe; }
public void setDescribe(String gender) {
String describe = "";
if (this.age < 30) {
describe = "young " + gender;
} else if ( this.age <= 55 && this.age >= 30) {
describe = "middle-aged " + gender;
} else {
describe = "old " + gender;
}
this.describe = describe;
}
}
Now, you can implement your changing needs by modifying HumanBO.
If you have a table in the database containing age and gender you could use something like this:
#Entity
public class Human {
#Id
private String id;
private Integer age;
private String gender;
#Transient
private String describe;
public void setId(String id){
this.id = id;
}
public void setAge(Integer age){
this.age = age;
}
public void setGender(String gender){
this.gender = gender;
}
#PostLoad
public void initDescribe(){
if (this.age < 30) {
this.describe = "young " + this.gender;
} else if ( this.age <= 55 && this.age >= 30) {
this.describe = "middle-aged " + this.gender;
} else {
this.describe = "old " + this.gender;
}
}
}
Since the describe field is not in the database table it can be annotated with #Transient and the #PostLoad annotation will ensure that the initDescribe() method is called after age and gender fields are set.
I am very new to Java and have searched through previously asked questions which haven't helped my issue...
How do I pass the int variable age, and the String name, from the main class to the Person class?
package engineers;
import java.util.Scanner;
public class Engineers {
public static void main(String[] args) {
// TODO code application logic here
Scanner scan = new Scanner(System.in); //declaration and ssignment of scanner
System.out.println("Enter name: "); //name prompt
String name = scan.next(); //reads name input from user
System.out.println("Enter age: "); //age prompt
int age = scan.nextInt(); //reads age input from user
System.out.println("Pay check amount: ");
double salary = scan.nextDouble();
Person person = new Person();
}
private static class Person {
/**
* A default constructor
*/
public Person() {
}
/**
* method for displaying the computation result
*/
double avgSalary = 40000 * Math.sqrt(Math.exp(0.04295 * age + 0.141) );
public void showData(int age, double pay){
System.out.printf( "%s earns $%4.3f for age %3d.\n", name, (pay*Math.sqrt(age)*.15), age);
}//end method showData
}
}
You should use Person constructor like this:
public Person(int age, String name) {
this.age = age;
this.name = name;
}
And add two fields in your Person class, before your constructor:
private int age;
private String name;
Then I am assuming you need to use this variables inside the person class, in order to do this, you can do something like this:
double avgSalary = 40000 * Math.sqrt(Math.exp(0.04295 * this.age + 0.141) );
To reference your variable:
public void showData(){
System.out.printf( "%s earns $%4.3f for age %3d.\n", this.name, (pay*Math.sqrt(this.age)*.15), this.age);
}//end method showData
Finnaly, you need to instantiate your Person object to use it:
Person p = new Person(name, age);
I would also recommend (since you are learning java), to understand the difference between getters/setters and constructor approach: Setter methods or constructors
You mean something like this?
int age;
String name;
class Person(int age, String name) {
this.age = age;
this.name = name;
}
Or (And)
void setAge(int age) {
this.age = age;
}
void setName(String name) {
this.name = name;
}
You would want to define a constructor with any argument another class may need for the most basic functioning.
A Person istance would be initialized with a name and age (even though It would be better to store a birth date and calculate the age against the current date).
To do this, you'd need the class Person to look like this:
public class Person{
private String name;
private Date birthdate;
//Constructor method
public Person(String n, Date bd){
name=n;
birthdate=bd;
}
//Other methods
}
In the main() method, you would then create a new istance of Person, after getting anything needed, like this:
Person p = new(name, date);
package studentclient;
public class StudentClient {
public static void main(String[] args) {
Student s1 = new Student("Samson", "101875643", 2.7);
System.out.println(s1.toString());
System.out.println();
Student s2 = new Student("Delilah", "511978900", 3.9);
System.out.println(s2.toString());
System.out.println();
/*Using the equals method and a selection control structure
(if statement), compare objects s1 and s2 and output an appropriate
message indicating if the objects are equal
*/
/*Using the appropriate mutator methods on student object s2,
change the name, social security number and GPA to the same
values as in object s1. Use the set methods.
*/
/*Again, using the equals method and a selection control structure
(if statement), compare objects s1 and s2 and output an
appropriate message indicating if the objects are equal
*/
}
}
I need to 1st compare two objects: in this case, Samson and Delilah, and I need to use an if statement structure to achieve that under StudentClient. Then, I need to use the appropriate mutator methods to change Delilah into a direct copy of Samson (that means, name, SSN and GPA). Finally after that change is done, I need to compare them again. How do I do that? This is very confusing for me, and my experience in C, and Python are of little help as my object-oriented programming muscles are extremely new.
Here is the other part of the code...
package studentclient;
public class Student {
private String name;
private String SSN;
private double gpa;
public Student(String name, String SSN, double gpa) {
this.name = name;
this.SSN = SSN;
this.gpa = gpa;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getSSN() {
return this.SSN;
}
public void setSSN(String SSN) {
this.SSN = SSN;
}
public double getGpa() {
return this.gpa;
}
public void setGpa(double gpa) {
this.gpa = gpa;
}
#Override
public String toString() {
String information = "Name: " + name;
information += "\n" + "Social Security Number: " + SSN;
information += "\n" + "GPA: " + gpa;
return information;
}
public boolean equals (Student student)
{
this.name = student.getName();
this.SSN = student.getSSN();
this.gpa = student.getGpa();
/*equals method returns boolean
Compares two Student objects for the same field values
returns a boolean, true if this object
has the same field value as the parameter object*/
return false;
}
}
import java.util.Scanner;
class IronMan {
private double totalTime = 3.7;
public IronMan() {
System.out.println("First Constructor running");
}
public IronMan() {
System.out.println("Second Constructor running");
}
}
public class Marathon {
public static void main(String[] args) throws InterruptedException {
IronMan person1 = new IronMan();
Scanner scan = new Scanner(System.in);
System.out.println(
"A triathlon is a challenging task. This program will allow you to know which is the perfect course for you.");
Thread.sleep(3000);
System.out.println("What is your age?");
int age = scan.nextInt();
Thread.sleep(1000);
System.out.println("What is your time for one mile, in minutes?(ex: 5.3 or 6.2");
double time = scan.nextDouble();
Thread.sleep(1000);
System.out.println("How much is your budget?");
double money = scan.nextDouble();
System.out.println(money);
if (money <= 100) {
System.out.println("You can't afford entrance!");
} else if (money > 100) {
if (age < 10) {
System.out.println("You don't qualify!");
} else {
if (time > 10) {
System.out.println("You do not qualify");
} else {
System.out.println("Good! you do qualify");
IronMan person2 = new IronMan();
}
}
}
}
}
I am a bit new to the concept of constructors. I was trying to create the constructor IronMan; however, Eclipse gives me an error message under the word IronMan. It says that "Duplicate method IronMan() in type IronMan". I don't understand why it says the method is duplicated, since it is supposed to be a constructor.
You have two constructors with the same signature (both without parameters). This is not allowed, since there's nothing that distinguishes between the two.
When you write IronMan person1 = new IronMan();, you have no way of specifying which of these two constructors should be invoked, so it's not allowed to have both.
Constructors allow you how to create an instance of an object. You can create ironMan IronMan ironMan = new IronMan() without set ironMan name and age, IronMan ironMan = new IronMan("Brad") this means your ironMan name is brad. IronMan ironMan = new IronMan("Brad", 29) means your ironman name is Brad and his age is 29. if you delete IronMan() constructor, you will enforce to the developer to enter ironMan name(with IronMan(String name)) or name and age (with IronMan(String name, int age)) while creating an instance of IronMan.
public class IronMan {
private String name;
private int age;
public IronMan() {
}
public IronMan(String name) {
this.name = name;
}
public IronMan(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
I'm coding a fairly simple program that simply outputs 2 employee's Names, their salary, and a 10% raise to that salary.
I have 2 issues: 1) The salary prints as '$0.000000' 2) Ii cannot get the raise method to work properly
Here's my code:
public class Employee {
// instance variable
private String name;
private String lastName;
private double salary;
// setters
public String getLastName() { return lastName; }
public String getName() { return name; }
public double getSalary() { return salary; }
public void raise(double raise) { salary = salary + (salary * .1); }
// getters
public Employee(String name, String lastName, double salary) {
this.name = name;
this.lastName = lastName;
if (salary > 0.0) {
this.salary = salary;
}
}
}
public class EmployeeTest {
public static void main(String[] args) {
Employee raise1 = new Employee("Betty", "Jones", 4000.0);
Employee raise2 = new Employee("Sally", "Mae", 6000.0);
// Print statements for the employee's name and salary
System.out.printf("Employee #1\nFirst Name: %s\nLast Name: %s\n\n" + "Salary: $%f", raise1.getName(), raise1.getLastName(), raise1.getSalary());
// THIS IS WHERE I'M HAVNG TROUBLE
System.out.printf("Her raise will be: %d", raise1.raise(salary));
System.out.printf("Employee #1\nFirst Name: %s\nLast Name: %s\n\n" + "Salary: %f", raise1.getName(), raise1.getLastName(), raise1.getSalary());
raise2.raise(salary);
}
}
Thanks in advance for the help!
The reason salary printed $0.00000 is because you've placed if statement for some reason instead of just setting salary you passed to constructor. Second thing, void methods does not return anything that's the reason raise method did not work the way you wanted. I fixed it for you so take a look, hopefully I helped you understand where you went wrong and if you have any questions feel free to ask I'm here for you.
Employee Test class:
public class EmployeeTest {
public static void main(String[] args) {
Employee raise1= new Employee("Betty","Jones",4000.0);
Employee raise2= new Employee("Sally","Mae",6000.0);
//Print statements for the employee's name and salary
System.out.printf("Employee #1\nFirst Name: %s\nLast Name: %s\n\n" +
"Salary: $%.2f",
raise1.getName(),
raise1.getLastName(),
raise1.getSalary());
System.out.printf("\nHer raise will be: $%.2f",
raise1.raise(raise1.getSalary()));
System.out.printf("\n\nEmployee #2\nFirst Name: %s\nLast Name: %s\n\n" +
"Salary: $%.2f",
raise2.getName(),
raise2.getLastName(),
raise2.getSalary());
System.out.printf("\nHer raise will be: $%.2f\n",
raise2.raise(raise2.getSalary()));
}
}
Employee class:
public class Employee {
//instance variable
private String name;
private String lastName;
private double salary;
//getters
public String getLastName() {
return lastName;
}
public String getName() {
return name;
}
public double getSalary() {
return salary;
}
public double raise(double raise){
salary = salary + (salary*.1);
return salary;
}
//constructor
public Employee(String name, String lastName, double salary){
this.name = name;
this.lastName = lastName;
this.salary = salary;
}
}
Print output from the program above:
Employee #1
First Name: Betty
Last Name: Jones
Salary: $4000.00
Her raise will be: $4400.00
Employee #2
First Name: Sally
Last Name: Mae
Salary: $6000.00
Her raise will be: $6600.00
When you do
Employee raise1= new Employee("Betty","Jones",4000.0);
you call the constructor of Employee class that have the following condition:
if (salary <0.0){
this.salary = salary;
}
Since 4000.0 is more than 0, it never gets assigned.
Your raise() method's return type is void, which means that it will not return anything at all. Change the return type to double, and simply typing return this.salary at the end should work fine. It should look like this:
public double raise(double salary)
{
this.salary = salary + (salary * 0.1);
return this.salary;
}
The this keyword references the instance of the object that you are using. Put it simply, you probably want to reference the classes salary variable, rather than the parameter passed in the method, otherwise it will reference the parameter passed in.
And you also need call this.salary = salary; in your constructor, because the only way it was assigned before is if salary is below zero, but 4000 is not below zero.