As an additional point, note that the elements you are citing are actually in java.lang
, i.e. there is no import statement, and one could say therefore no dependency to anything induced by using these types, besides the fact you use Java.
As soon as you step out of java.lang, I believe you are usually better off applying DIP, i.e. always prefer using a List<T>
over using a ArrayList<T>
.
The problem is to limit dependencies across borders of "components" (or module/package...) to only functional dependencies (i.e. abstractions, interfaces in Java). At some point you do need concrete implementations, that are necessarily built using at least some data structures, even if it is only arrays of basic int type. This does not violate DIP.
The use of Plain Old Data as suggested in @jaco0646 's answer, that are not violating DIP is kind of borderline ; in most cases you could use a signature that explicitly passes the fields of the struct you are considering instead of packing them into a single object ; this approach is indeed more general, e.g. you can implement it without having that POD class, maybe relying on some relational DBMS, you can interact with code written in any language etc...
However in practice, it can make sense to use POD in signatures, so that if I add a field to a POD, this will automatically propagate to all signatures that use the struct. Some of these functions may not use the new field, so we are now giving them too much information (we are leaking, with respect to strict "need to know"). Still, it can be a pragmatic answer in many cases to opt for this approach.
If we look at e.g. webservices, there is general tendency to consider POD are not a problem in service signatures, and using them helps keep clients compatible even if some new fields appear in the struct.