Today, let's talk about java generics:
- Collection<Number>
- Collection<? extends Number>
- Collection<?>
- Collection<Object>
Let's start with a simple example:
public void testGenerics() { Collection<Number> numbers = new ArrayList<>(); numbers.add(1); // ok Collection<?> tmp = numbers; // don't work, you don't know what type 'tmp' obviously contains // tmp.add(1); Collection<? extends Number> tmp2 = numbers; // don't work, you don't know what subtype 'tmp2' obviously contains // tmp2.add(1); Collection<Integer> integers = new ArrayList<>(); tmp = integers; tmp2 = integers; Collection<String> strings = new ArrayList<>(); tmp = strings; // tmp2 = strings; // don't work }
This problem is actually a bit anti human. It is estimated that the first reaction of most people (including me) to this transformation must be "of course it is right.", Say my understanding:
- Collection < Number >: indicates that the collection contains objects of type Number, which can be Integer/Long/Float, because the compiler can judge obj instanceof Number == true;
- Collection<? Extensions Number >: indicates that this collection is a collection instance of "a subtype" of type Number, which can be collection < integer > / collection < long >, so call tmp Add (1) does not work because the compiler does not know which subtype of Number is the element contained in this tmp, and the compiler cannot judge the result of obj instanceof UnknownType;
- Collection < E >, this e type is a specific type, not multiple subtypes of a parent.
When it comes to why write operations cannot be allowed without specifying the type, it is for the sake of runtime security. For example:
public void testGenerics2() { List<Integer> integers = new ArrayList<>(); List<? extends Comparable> comparables = integers; integers.add("1"); comparables.get(0).intValue(); // fail }
If Comparable types are allowed to be added, the runtime may throw some unexpected runtimeexceptions, resulting in abnormal end of the method and even crash of the program.
Now let's talk about collection < Object > and collection <? >, The first reaction of many people (including me) must be "object is the common parent of all java objects, so collection < Object > can represent any type of collection". Let's take an example:
public void testGenerics3() { List<Integer> integers = new ArrayList<>(); List<Object> objects = integers; // don't work List<?> objects1 = integers; // ok }
- Collection<?> The range represented is larger than collection < Object >;
- The correct way to represent any type of collection is collection <? >;
- Collection < Object > cannot represent any type of collection.
Why does collection < Object > not represent any type? In fact, the compiler thinks that there is a risk of type conversion errors:
public void testGenerics4() { List<Integer> integers = new ArrayList<>(); List<Object> objects = new ArrayList<>(); // this will be ok if List<Object> equals List<?> // objects = strings; // objects.add("1"); // Integer i = (Integer) objects.get(0); // and crashes List<?> objects1 = new ArrayList<>(); // ok // objects1.add("1"); // compiler will make it illegal }
- List < Object > can add data to the set, because object is the parent class of all objects and is a known type, which can be judged by obj instanceof Object;
- List<?> The compiler is not allowed to throw data into it, because it does not know what kind of data type the list is, and it cannot be judged by obj instanceof UnknownType;
- ? Object represents an unknown type, and object represents a known type;
- If list < Object > represents any type, according to Murphy's Law (what may happen must happen), the crash in the above example is bound to happen.. (another online fault)
Postscript:
I haven't spoken for a long time. I've always wanted to write some praise for the tips in search architecture design. However, I just moved a few words. First, I'll fill in the emptiness with some essays.