简体   繁体   中英

Can I overload an interface method in Java?

I have a data description interface:

public interface DataDescription {
     int getId();
}

And two implementations:

public class DataWithId1 implements DataDescription {
    // ... simple getter impl.
}

public class OtherDataWithId implements DataDescription {
    // ... simple getter impl.
}

Now I have this interface:

public interface DataProcessor {
    void process(DataDescription data);
}

I would like to implement the DataProcessor with one class, something like this:

public class DataProcessorImpl implements DataProcessor {
    @Override
    public void process(DataDescription data) {
        // Do something...
    }

    public void process(DataWithId1 data) {
        // Do something specific with this type (e.g. directly store in table of database)
    }

    public void process(OtherDataWithId data) {
        // Do something specific with this type (convert to format DataWithId1 and then store in DB)
    }
}

And some code to call it:

public Main {
    private DataProcessor dataProcessor = new DataProcessor();

    public static void main(String[] args) {
        DataDescription data = new DataWithId1(1);
        dataProcessor.process(data);
    }
}

What I would like to achieve is that the DataProcessor caller doesn't have to worry about the data conversion (they have a DataDescription and don't have to know about the two types). Additionally I would like to avoid instanceof code.

The assumption I've made is that I can overload an interface method like this. I was unable to find proof for this when looking at section 15.12 of the java language specification (which doesn't mean it isn't there...).

Is my assumption about overloading correct? Can I avoid instanceof ?

No, this won't work.

There is no overloading in your code. dataProcessor 's static type is DataProcessor , and DataProcessor only has one process method.

If you change dataProcessor 's static type to DataProcessorImpl , you still won't get the desired outcome, since overloading resolution is determined at compile time. Therefore, since the compile time type of data is DataDescription , dataProcessor.process(data) will still invoke public void process(DataDescription data) and not public void process(DataWithId1 data) .

Maybe you are looking for the Visitor Pattern :

public interface DataDescription {
    int getId();
    void accept(DataProcessorImpl p);
}

public class DataWithId1 implements DataDescription {
    private final int id;

    public DataWithId1(int id) {
        this.id=id;
    }
    @Override
    public void accept(DataProcessorImpl p) {
        p.process(this);
    }
    @Override
    public int getId() {
        return id;
    }
    // ... simple getter impl.
}

public class OtherDataWithId implements DataDescription {
    private final int id;

    public OtherDataWithId(int id) {
        this.id=id;
    }
    @Override
    public void accept(DataProcessorImpl p) {
        p.process(this);
    }
    @Override
    public int getId() {
        return 42;
    }
    // ... simple getter impl.
}
public interface DataProcessor {
    void process(DataDescription data);
}

public class DataProcessorImpl implements DataProcessor {
    @Override
    public void process(DataDescription data) {
        data.accept(this);
    }

    public void process(DataWithId1 data) {
        System.out.println("process(DataWithId1)");
        // Do something specific with this type
        // (e.g. directly store in table of database)
    }

    public void process(OtherDataWithId data) {
        System.out.println("process(OtherDataWithId)");
        // Do something specific with this type
        // (convert to format DataWithId1 and then store in DB)
    }
}

public class Main {
    private static DataProcessor dataProcessor=new DataProcessorImpl();

    public static void main(String[] args) {
        DataDescription data = new DataWithId1(1);
        dataProcessor.process(data);
        data = new OtherDataWithId(100);
        dataProcessor.process(data);
    }
}

It's easy to do if you add the "something specific" into a method in the DataDescription interface.

The process() method belongs with each subtype. You've placed it in the wrong interface.

Let the DataProcessor call that method on each DataProcessor :

public interface DataDescription {
     void somethingSpecific();
}

Polymorphism does the work:

public class DataProcessorImpl implements DataProcessor {
    @Override
    public void process(DataDescription data) {
        data.somethingSpecific();  // polymorphism does it for you here
    }
}

You could use an abstract class to handle the conversion for you, or alternatively use Java8's default method in the interfaces.

Simply add the keyword 'default' to the method in your interface and give them a body.

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