Translation | Java in variant (Variance)

Original Java communities from abroad javacodegeeks, author George Aristy, Portal

A few days ago, I saw an article in occasional cases, author of the article about the pros and cons of view after using GO 8 months on it. I use the GO work for a long period of time, basically agree with the authors said points.

Despite this preamble, but this article on Java variant, the goal is to re-understand what is a variant, as well as some minor differences in Java implementation.

What is the variant?

Wikipedia is described variants of:

A so-called variant refers to how the sub-type relationship between the type of composition to determine the relationship between the subtype of more complex types.

"More complex types" as used herein refers to a container such as a high-level structure, functions and the like. Thus, through the variation about the type hierarchy ( the Type Hierarchy assignment function between the container and the parameters of the connection) compatible composition. It allows the security parameters and subtype polymorphism integration. For example, it can be a way to return the cat list assignment to type "list of animals" in a variable? Can I be a list of objects Audi Cars passed to the method accepts a list of them?

In Java, it is defined in the point of use variation (use-site) them.

Variant 4 types

Set forth in the wiki, the type constructors means:

  • Covariant (Covariant): not accept receiving subtype supertype
  • Inverter (Contravariant): accepted supertype does not accept sub-type
  • Variable bis (Bivariant): while receiving subtypes and supertypes
  • Immutable (Invariant): and does not accept subtype supertype

(Obviously, the type parameter declared in all cases be acceptable)

Java in the immutability (Invariance)

Using the set point must not be variations in the type of boundary parameters.

If you Aare Bone of the super-type, GenericType<A>not a GenericType<B>super type, and vice versa.

This means that two types of no contact with each other, and can not be converted into each other under any circumstances.

The same container

In Java, no variable could be the first one you come across, and is the most intuitive generic examples. As expected, the method of the type parameter is usable. All types of method parameters are accessible.

But they are not interchangeable:

// 类型层级:Person :> Joe :> JoeJr
List<Person> p = new ArrayList<Joe>(); // 编译错误
List<Joe> j = new ArrayList<Person>(); // 编译错误
复制代码

But you can add objects:

// 类型层级:Person :> Joe :> JoeJr
List<Person> p = new ArrayList<>();
p.add(new Person()); // ok
p.add(new Joe()); // ok
p.add(new JoeJr()); // ok
复制代码

It can also be read:

// 类型层级:Person :> Joe :> JoeJr
List<Joe> joes = new ArrayList<>();
Joe j = joes.get(0); // ok
Person p = joes.get(0); // ok
复制代码

Covariant in Java

Point of use disclosed variants must have a lower bound of the parameter type.

If you Bare Aa sub-type, GenericType<B>it is GenericType<? extends A>a sub-type.

Java in the array has been covariant

Prior to the introduction of a generic Java 1.5, the array is the only available generic containers. They have been covariance, for example, Integer[]a Object[]sub-type. The compiler allows you to Integer[]pass to the receiving Object[]method. If the method of inserting a Integersuper type, ArrayStoreException exception at run time throws. Covariant generic type rules compile time achieve such checks to prevent errors in the first place.

public static void main(String... args) {
  Number[] numbers = new Number[]{1, 2, 3, 4, 5};
  trick(numbers);
}
 
private static void trick(Object[] objects) {
  objects[0] = new Float(123);  // ok
  objects[1] = new Object();  // ArrayStoreException 在运行时抛出
}
复制代码

Covariant container

Java allows subtype (covariant) generic types, but it limits how do these generic types "flow in and out" in accordance with the principle of least astonishment (POLA). In other words, a method return type parameter value is accessible, and the method of the type parameter is an input parameter having inaccessible.

You can replace a sub-type super type:

// 类型层级:Person :> Joe :> JoeJr
List<? extends Joe> = new ArrayList<Joe>(); // ok
List<? extends Joe> = new ArrayList<JoeJr>(); // ok
List<? extends Joe> = new ArrayList<Person>(); // 编译错误
复制代码

From the vessel read is straightforward:

// 类型层级:Person :> Joe :> JoeJr
List<? extends Joe> joes = new ArrayList<>();
Joe j = joes.get(0); // ok
Person p = joes.get(0); // ok
JoeJr jr = joes.get(0); //
复制代码

But it does not allow cross-layer write (counterintuitive), in order to prevent an array of traps. For example, in the following example, List<Joe>the call / owner will feel surprised if other parameters with covariance List<? extends Person>method to add an Jillobject.

// 类型层级:Person :> Joe :> JoeJr
List<? extends Joe> joes = new ArrayList<>();
joes.add(new Joe());  // 编译错误 (你不清楚哪种 Joe 的超类型在列表中)
joes.add(new JoeJr()); // 编译错误 (同上)
joes.add(new Person()); // 编译错误
joes.add(new Object()); // 编译错误
复制代码

Java in the inverter

Point of use must have a variation of the type disclosed in the parameters on the boundary.

If you Aare Ba super type, GenericType<A>it is a GenericType<? extends B>super type.

Inverter container

Behavior and knowledge of the container opposite to the inverter: and covariant container contrast, access method type return parameter values is not feasible , and the parameters of the access method type parameters are possible:

You can replace sub-type super-type:

// 类型层级:Person :> Joe :> JoeJr
List<? super Joe> joes = new ArrayList<Joe>();  // ok
List<? super Joe> joes = new ArrayList<Person>(); // ok
List<? super Joe> joes = new ArrayList<JoeJr>(); // 编译错误
复制代码

Unable to capture a particular type when reading:

// 类型层级:Person :> Joe :> JoeJr
List<? super Joe> joes = new ArrayList<>();
Joe j = joes.get(0); // 编译错误 (能够为 Object 或者 Person)
Person p = joes.get(0); // 编译错误 (同上)
Object o = joes.get(0); // 允许,因为在 Java everything IS-A Object
复制代码

You can add a "lower bound" sub-types:

// 类型层级:Person :> Joe :> JoeJr
List<? super Joe> joes = new ArrayList<>();
joes.add(new JoeJr()); // 允许
复制代码

But you can not add a super-type:

// 类型层级:Person :> Joe :> JoeJr
List<? super Joe> joes = new ArrayList<>();
joes.add(new Person()); // 编译错误
joes.add(new Object()); // 编译错误
复制代码

Bis-change type

Use point variant type parameters must be declared in the unbounded wildcard .

Generic type has unbounded wildcard is the same type of super-generic type of all bounded variant. For example, GenericType<?>a GenericType<String>super-type. Since the unbounded type is hierarchythe root type, therefore, for its parameter types, it can only be accessed from inherited java.lang.Objectmethod.

It will be GenericType<?>regarded GenericType<Object>.

N-type structure parameter variations

Java allows covariant return type and exceptions type override methods:

interface Person {
  Person get();
  void fail() throws Exception;
}
 
interface Joe extends Person {
  JoeJr get();
  void fail() throws IOException;
}
 
class JoeImpl implements Joe {
  public JoeJr get() {} // 重写
  public void fail() throws IOException {} // 重写
}
复制代码

But trying to use covariance parameters covering methods will only lead to overload:

interface Person {
  void add(Person p);
}
 
interface Joe extends Person {
  void add(Joe j);
}
 
class JoeImpl implements Joe {
  public void add(Person p) {}  // 重载
  public void add(Joe j) {} // 重载
 }
复制代码

Epilogue

Variant for the Java introduces additional complexity. Although the rules around the types of variants is easy to understand, but the accessibility rules governing the type parameter method is a violation of common sense. Understand them not only to achieve the "obvious" - come to think of logic need to stop them.

However, my experience tells me everyday, these nuances are often out of the way:

  • I have not tried inverter must declare an instance of a parameter, but I rarely come across them (although they do exist)
  • Covariance parameters depending on the number seems to be more common, but fortunately they are also more easily inferred

Considering the subtype is an object-oriented programming technique wherein a basic, but variations is its biggest advantage.

Conclusion : variant provides adequate benefits in my daily programming, particularly when compatible with the subtype of time (which is common in object-oriented programming).


Small speakers

Guangzhou reed Java technology development team

Reed Technology - Internet software services company specializing in Guangzhou

Seize every detail, to create a better every

Our public concern number to find out more

We want to fight with you? lagou search for " reed technology " or put your resume to [email protected] join us.

Follow us your comments and point us praise our greatest support

Guess you like

Origin juejin.im/post/5d0f807e51882532d834bc4c