-3

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;
Progman
  • 16,827
  • 6
  • 33
  • 48
  • Suppose `E`, `PE` and `EV` are variable names and `Employee` or `PTEmployee` are _classes_ (types) respectively. What is the type of variable `EV` then? Do you also have _interfaces_ ? – hc_dev Jun 07 '22 at 20:33
  • 1
    Are Employee and PTEmployee related to each other in any way? – f1sh Jun 07 '22 at 20:35
  • PTEmployee inherits from Employee. PT = part time – tmiliketurtles Jun 07 '22 at 20:39
  • Suppose you really used `var` in your code (BTW: can you post an [example], please), and further you read [Java 10 LocalVariable Type-Inference](https://www.baeldung.com/java-10-local-variable-type-inference) - then: What is you question exactly? Or what do you want to achieve and what did not work out as expected? – hc_dev Jun 07 '22 at 20:39
  • I want to set EV to PE after I set EV to E. – tmiliketurtles Jun 07 '22 at 20:40
  • I edited my question and added a minimal reproducible example – tmiliketurtles Jun 07 '22 at 20:47
  • 1
    @tmiliketurtles You cannot change the type of a variable, it is specified at the declaration of the variable. – Progman Jun 07 '22 at 20:58
  • 2
    Why do you want to change the type of a variable, instead of just using a new variable? What esoteric advantage do you hope to gain from that? – Holger Jun 08 '22 at 08:00
  • What are the __specific methods__ of `PTEmployee` you want to use? Maybe the class-design (incl. inheritance hierarchy) can be adjusted to have a generic `Employee` with two specifications `PartTimeEmployee` and `FullTimeEmployee`. The `var` construct is meant for short-scoped usage. Type-switches can be solved differently. – hc_dev Jun 08 '22 at 11:58
  • We can't change Java's `var` behaviour for you, nor do I know any Java construct to change a var-type at runtime ([Java is a strongly and statically typed language](https://stackoverflow.com/questions/66756725/java-being-strongly-typed)). But we can help you find a solution, as soon as we know the context and use-case: What is the purpose and further usage of (sub-type capable) variable `EV` ? – hc_dev Jun 08 '22 at 18:41

2 Answers2

0

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.

hc_dev
  • 8,389
  • 1
  • 26
  • 38
  • This still doesn't let them _access the Class PTEmployee methods, because the IDE thinks that the variable EV is still of Employee Type_. – Sotirios Delimanolis Jun 07 '22 at 21:30
  • @SotiriosDelimanolis Exactly, that's the rational behind `var`: to have a type-safe definition. Depending on their use-case a `switch` construct or `interface` might be the solution to use needed methods. (Imagine we hire and place a part-time employee, but then decide and force this employee to work like a full-time equivalent .. a bit odd ️) – hc_dev Jun 08 '22 at 11:51
  • Right, but I believe their intention is for `ev` to be typed as `PTEmployee`. – Sotirios Delimanolis Jun 08 '22 at 13:05
  • @SotiriosDelimanolis I tried to clarify their intention (which I also assume and must admit is not possible with local-var). So I added this _believed_ contradiction between `var` and sub-typing by illustrating imaginative use-cases. – hc_dev Jun 08 '22 at 18:32
0

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