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 numbers.add(0.1); // ok Collection<? extends Number> numbers2 = new ArrayList<>(); // don't work, you don't know which subtype 'numbers2' exactly contains numbers2.add(1); // oops! }
This example 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" (this is a pit). Let me explain 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 numbers2 is called Add (1) does not work because the compiler does not know which subtype of Number the element contained in numbers2 is, and the compiler cannot judge the result of obj instanceof UnknownType;
- Collection < E >, this e type is a "one" specific type, and cannot be a placeholder for multiple seed types representing a parent;
Another example:
public void testGenerics() { Collection<Number> numbers = new ArrayList<>(); Collection<Integer> integers = new ArrayList<>(); Collection<? extends Number> numbers2 = new ArrayList<>(); numbers2 = integers; // ok numbers2 = numbers; // ok // don't work, Collection<Number> != Collection<Integer> numbers = integers; // oops! }
Integer obviously inherits Number, so why
- Collection<Number> == Collection<Integer>
If not, let's take another example:
public void testGenerics() { Collection<Integer> profits = new ArrayList<>(); insertSomething(profits); // line 1 Integer profit = profits.iterator().next(); // oops! crash } private void insertSomething(Collection<Number> numbers) { numbers.add(Long.MAX_VALUE); }
If line 1 is true, the next profit will be a negative number, and a series of subsequent calculations will sound exceptions. If the code is not robust enough, it may even throw some unexpected runtimeexceptions, resulting in abnormal end of the method and even program crash.
So in a word, collection < number >= Collection < integer > is to solve possible type conversion exceptions at compile time for the safety of run time.
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 testGenerics2() { Collection<Integer> integers = new ArrayList<>(); Collection<?> objects2 = integers; // ok // don't work, which type of 'objects2' contains is uncertain objects2.add(1); // oops! Collection<Object> objects = integers; // oops! }
- Collection<?> The range represented is larger than collection < Object >;
- Cannot call objects2 Add (1) is because the compiler cannot accurately infer which data type container objects2 is, which may cause type conversion exceptions at run time;
- The correct way to represent a collection of any data type is collection <? >;
- Collection < Object > cannot represent any type of collection.
Why does collection < Object > not represent collections of any type? In fact, the compiler thinks that there is a risk of type conversion errors:
public void testGenerics() { Collection<Integer> integers = new ArrayList<>(); Collection<Object> objects = integers; // oops! // don't work, which type of 'objects2' contains is uncertain objects.add("1"); Integer one = objects.iterator().next(); // oops! crash }
- Collection < Object > can add data to the container, because object is the parent class of all objects and is a known type, which can be judged by obj instanceof Object;
- Collection<?> You can't put data into the container because? (UnknownType) is an unknown type, and the result of obj instanceof UnknownType cannot be judged;
- ? Is an unknown type, and Object is a known type;
- If collection < Object > represents any type, according to Murphy's Law (what may happen must happen), the crash in the above example is inevitable.. (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.