How to change a variable type in Java?

1k Views Asked by At

I have two objects:

  • Employee E
  • PTEmployee PE

I need to do the following manipulation

  • EV=E

  • EV=PE

I believe I would need to do the following: var EV = E But then when I set EV = PE, I cannot access the Class PTEmployee methods, because the IDE thinks that the variable EV is still of Employee Type.

This is what I have tried:

Employee E = new Employee(name, ssn, position, new Date(dobMonth, dobDay, dobYear), pay);

PTEmployee PE = new PTEmployee(name, ssn, position, new Date(dobMonth, dobDay, dobYear), nHours, wages);
    
var EV = E;
    
EV = PE;
2

There are 2 best solutions below

4
hc_dev On

Given

// base class
class Employee {
    // common fields omitted
    BigDecimal pay;

    public Employee(String name, String ssn, String position, Date dob, BigDecimal pay) {}

    // method can be overridden in sub-classes
    public BigDecimal calculatePay() {
        return pay;  // here: the monthly salary
    }

}

    
// part-time (PT) employee inherits from employee
class PTEmployee extends Employee {

    // common fields omitted
    int nHours;
    BigDecimal wagePerHour;

    public PTEmployee(String name, String ssn, String position, Date dob, int nHours, BigDecimal wagePerHour) {}

    // method is specifically implemented for a part-time employee
    @Override
    public BigDecimal calulatePay() {
        return wagePerHour.multiply(nHours); // hour-based salary-model
    }

    // method only exists in this generation (this class and sub-classes)
    public double timePercentage() {
        return Employee.FULL_TIME_HOURS / nHours; // half-time would return 50
    }
}

Why does the second assignment downcast?

Inferred type using var

// renamed EV, E and PE to follow 
// Java-naming conventions: lower-case variable names
Employee e = .. // initialization omitted
PTEmployee pe = .. // initialization omitted


var ev = e; // type of local variable ev gets inferred as Employee
System.out.println(ev.getClass()); // debug-print the type

// now we assign another instance of the same (Employee) or a sub-type (PTEmployee)    
ev = pe;  // type of ev is still Employee (the assigned instance is down-casted)
System.out.println(ev.getClass()); // debug-print the type

The Java compiler and your IDE (e.g. method-suggestions or autocompletion) both have the type inferred already with the first and initial assignment.

All further assignments will not change the type of this variable.

See also:

How to declare the variable to accept any sub-class ?

Use-case allowing the shorthand var

Now lets assume the use-case that you have a work-force of 2 employees that should get paid. But the accountant does not care about their time-percentage, only calculating their pay is important. The type of employment is not important.

List<? extends Employee> workforce = List.of(e, pe);

void payWorkforce() {
    for (var worker : workforce) { // here the var is useful and a shortcut
       System.out.printf("Paying worker %s: %s \n", worker.getName(), worker.calculatePay());
    }
}

In the first use-case scenario, the for-each loop, the var declaration is sufficient and shortens our loop-head. We are only interested to call the methods of base-class Employee, so we can use var safely.

Use-case requiring distinct subtypes

For the HR staff, which has to write the contract, the working-hours and contracted salary model however is very important. So the type of employee is accurately defined.

// using different variable-type declarations depending on the type needed
void hireCandidate(.., int preferredHours) {
    if (preferredHours <= 0) {
        System.out.println("Sorry. We need you to work at least 1 hour.");
        return;
    } else if (preferredHours < Employee.FULL_TIME_HOURS) {
        PTEmployee partTime = new PTEmployee(.., preferredWeeklyHours, HOURLY_PAY);  // define sub-type to use
        workforce.add(partTime);
        System.out.printf("Hired a %d percent partTime employee.\n", partTime.timePercentage());  // then you can use the specific sub-class' method
    } else {
        Employee fullTime = new Employee(.., MONTHLY_SALARY);
        workforce.add(fullTime);
        System.out.printf("Hired a fullTime employee.\n");
    }
    return;
}

In the second use-case scenario, you can see, that because we expect to deal with different types of employees in the hireCandidate method, we also declared the variables with different types as needed.

0
Sina Ramezani On

When we use a variable with the reserved word var, its typing is determined at initialization, which is why when you assign another type of class to this variable, you do not have access to its methods, and the IDE behaves quite correctly. For more information, you can read more about it in the following link https://openjdk.java.net/projects/amber/guides/lvti-faq#Q6