Option 1 - just add new method overload (meaning: a method with same name, but with different signature and technically never considered the same method from the language perspective) to the class that implements the interface
This is the answer suggested by Lars.
Pros: Least effort.
Cons: Only callers which knew the name of your new concrete class
fancyNewImpl could perform the downcasting. Furthermore, if the new method signature happens to be also implemented another concrete class, such as
fancyNewImplTwo, callers which attempt to downcast to the first concrete class would fail; a caller would have to try both (or, all relevant) concrete classes in order to find the method overload that can use.
Option 2 - Define an interface that inherits from the original one, and has the new method overload.
public interface FancyCarManager extends CarManager
Car getCar(Map<String, Int> modelAndYear);
Then, implement the two methods in the concrete class that implements the
Callers will still have to do an upcast (technically an interface check) to
FancyCarManager and call the new method. But, this option allows multiple concrete classes, such as
FancyNewImplTwo, to be callable through the same new method signature, through the new interface.
Option 3 - Call the method anyway, without interface, via Java Reflection
Basically this answer deserves to be downvoted just because I mentioned this. But in actual programming workplace, you should see a lot of this happening.
(Opinions are mine and are not related to my employer and not inspired from my work. This opinion can be seen in programming blogs elsewhere and articles on the internet.)
Option 4 - Abuse the string parameter by encoding things into it
For example, you can concatenate the year into the model string as
Car car = carManagerInstance.getCar(model + ";" + year);
You can add any number of parentheses (as string characters), other punctuations, Unicode characters, or even non-printable characters. You can see where this is going: shovel an XML fragment or a JSON into a string.
This will likely choke any existing code that expects the string to be formatted in the old way.
However, in legacy code bases where the old meets the new (in a bloody conflicting way), this will happen a lot. This requires a very high testing (quality assurance) effort, and will always have a higher defect rate no matter how much effort is put in.
Just because something is mentioned in this answer does not mean it is proper to use it. Ask your more experienced coworkers for opinions. This is especially valuable if your coworker knows the code base you're working on and your company's coding style.