简体   繁体   中英

Using abstract method with generic list as return type in java

im trying to build this abstract method within an abstract class and using it in one of my subclasses and it's return type shall be a List / ArrayList. I'm really struggling with the syntax, and most of the previous asked question are not referring to my special issue.

Most important for me to describe it in easy words.

  1. Let me use a method
  2. Output (return) of that method should be a list of...I don't what objects yet
  3. And it's original declaration is abstract

Here the abstract class *

private int employeeID;
    private String name, sID, department;
    private double salary;

    // Constructor (empty)
    public Employee() {

    }

    // Constructor => Every Employee has at least this attributes => Subclasses may have additonal attributes
    public Employee(int employeeID, String name, String sID, double salary, String department) {
        this.employeeID = employeeID;
        this.name = name;
        this.sID = sID;
        this.salary = salary;
        this.department = department;
    }

    // Getters and Setters below
    //.......

 // Abstract method with generic list as return type
    public abstract <T> List<T> read(String path);

Here is the Subclass

public class Clerk extends Employee {

    public Clerk() {

    }

    public Clerk(int employeeID, String name, String sID, double salary, String department) {
        super(employeeID, name, sID, salary, department);
    }

    @Override
    public <T> List<T> read(String path) {
        // TODO Auto-generated method stub

        String line = null;
        List<Clerk> clerk = new ArrayList<Clerk>();

        try {
            BufferedReader reader = new BufferedReader(new FileReader(path));
            reader.readLine();

            while ((line = reader.readLine()) != null) {
                String[] clerkValues = line.split(";");
                clerk.add(new Clerk(Integer.parseInt(clerkValues[0]), clerkValues[1], clerkValues[2], Double.parseDouble(clerkValues[3]), clerkValues[4]));

            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return clerk; // Error here,Type mismatch: cannot convert from List<Clerk> to List<T>

I'm always getting an error. And I don't want to build the superclass (Employee) as a generic Class like =>

 public abstract class Employee <T>{
    // Code here
    }

Thank you in advance for your support.

You can declare the method in Employee like this:

public abstract List<? extends Employee> read(String path);

You could translate this to English like this "read returns a list of some unknown type of employee". You'll be able to iterate the list and otherwise read from it, and treat elements as Employee . You won't be able to add new Employee elements to the list, or otherwise pass Employee elements as parameters to methods. For this use case, that is probably fine.

You can override it in Clerk and the other subclasses with method signatures like this:

public List<Clerk> read(String path)

This works because List<Clerk> is a subtype of List<? extends Clerk> List<? extends Clerk> , and Java allows you to override a method with the overriding method returning a more specific type than the method it overrides.

If you then call read on a reference of type Clerk , the return type will be List<Clerk> , as expected.

This would not work if the Employee class returned List<Employee> instead of List<? extends Employee> List<? extends Employee> , because List is invariant and therefore List<Clerk> is not a subtype of List<Employee> . To understand why that is, consider that a List<Employee> does allow you to add new Employee elements to it. If the actual type of the list were List<Clerk> , but the compiler allowed adding other types of Employee to the list that are not instances of Clerk , it would violate the expectation that the list only contained Clerk elements, and likely lead to runtime errors.

I do agree with Gene's comment that it doesn't make much sense to have these methods on instances of Employee and Clerk . Perhaps having an EmployeeReader interface and ClerkReader implementation would be better.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM