Warum soll das nicht gehen? Du kannst von einem Interface kein konkretes Objekt erzeugen, aber als Variable definieren kann man es.
Du sagst damit nur "Dieser Variable sind Objekte zugewiesen, die dieses Interface implementieren". Das heißt du kannst da z.B. eine ArrayList aber auch eine LinkedList zuweisen.
Und genau das ist auch der Grund und Vorteil. Kapselung bzw. man will nur notwendige Details nach ausgeben. Nehmen wir mal folgende Signatur an, die in einer größeren Bibliothek, die man wiederverwenden kann, drin ist.
Code:
public List ermittleDaten();
Damit ist hier gesagt, es kommt irgendwas zurück, das List implementiert. Ob es eine ArrayList oder eine LinkedList oder irgendwas anderes ist egal. Das heißt, wenn sich der Entwickler der Bibliothek entscheidet mal die konkrete Liste aus z.B. Performance Gründen zu ändern, funktionieren alle Aufrufe immer noch.
Wenn da aber ArrayList stehen würde und man würde es auf LinkedList umstellen, müsste jeder Aufrufer es umstellen. Daher ist es fast immer sinnvoller möglichst generische Interfaces zu verwenden.
Dabei geht es um die Entkopplung von Schnittstelle und der konkreten Implementierung.
Nehmen wir Autos als Beispiel. Stell dir vor du lernst ein Auto zu fahren in der Fahrschule, du kannst das auch perfekt fahren, aber sobald du in ein anderes Auto einsteigst stehst du wie der Ochs vorm Scheunentor weil alles biszchen anders ist und du damit absolut nicht umgehen kannst. Du hast also nicht "Autofahren" gelernt, sondern "Wie lenke ich dieses bestimmte Auto", also nicht so hilfreich.
Genauso verhaelt es sich auch mit den Schnittstellen. Wenn du nur eine bestimmte List Implementierung uebernimmst, ist das nicht so hilfreich. Nehmen wir zum Beispiel mal eine Methodendeklaration als Beispiel:
Wir sehen, wir sind ploetzlich sehr limitiert, wir brauchen immer die konkrete Implementierung von List. Das ist nicht so toll, weil manchmal hast du eine komplett andere Liste, zum Beispiel eine LinkedList. Manchmal kannst du dich von den konkreten Typen nicht mehr ableiten weil diese final sind, und so weiter.
Dadurch dass du die konkrete Implementierung erwartest ohne Funktionalitaet von dieser zu brauchen, limitierst du deine Moeglichkeiten. Stell dir vor du verwendest immer eine LinkedList weil du dir eingebildet hast dass das eine gute Idee. Jetzt hast du festgestellt dass eine ArrayList fuer deinen Anwendungsfall doch eine bessere Leistung bringt. Wenn du jetzt in deiner gesamten Code-Basis ueberall die Listen als LinkedList deklariert hast, hast du Spasz das alles zu aendern.
Deswegen deklariert man immer den geringsten Typ den man wirklich braucht, weil dann haelt man die Moeglichkeiten offen dass andere konkrete Implementierungen eingesetzt werden.
Kein Unterschied, außer dass du bei der ersten Variante dann nicht auf die ArrayList-eigenen Funktionen zugreifen kannst.
Wenn dir die Implementierung nicht wichtig ist, reicht das Interface als Typ für die Variable.
Mittlerweile geht auch das hier:
Java:
var arrList =newArrayList<>(Arrays.asList(arr));
Der Compiler macht aus dem "var" ein "ArrayList<String>" (sofern es sich bei arr um ein Array von Strings handelt).
Ist es sinnvoll, an dieser Stelle eine ArrayList-Variable zu verwenden? Eigentlich komplett egal, sofern du keine ArrayList-eigenen Methoden brauchst.
@Robert Zenz hat allerdings den Vorteil genannt, den man hat, wenn man eine List<?> anstatt einer Implementierung für eine Methode akzeptiert.
Was die Rückgabewerte angeht, haben wir uns bereits lang und ausgiebig darüber gestritten, ob es sinnvoll wäre, möglichst viele Informationen mitzugeben oder eben nur das Interface. Da gibt es verschiedene Paradigmen. Damit fang ich jetzt nicht nochmal an