When we build constructs that interact with other types, we often specify the type we are interacting with directly. This is helpful because it means we know the capabilities that the type has; we can put those capabilities to use and ensure that the outputs have the correct type. However, we now have a construct that can only interact with the specified type; it can't be reused with other types, even if the concepts are the same.
Generics give us the advantage of having a defined type while being generically applicable to other types. It is, perhaps, best illustrated with an example.
Let's create a custom collection object that will store the last five strings as copies so that the user can paste not just the last string copied, but any of the last five. You can add strings to the list and then ask it for all the strings in the list, and it...