T Wildcard chat Java Generics, E, K, V ,?


About the author:
Shang Xun teacher, JAVA development work in seven years,
specializes in Javaweb, small things develop public programs No. develop
public number: java back-end technology featured
csdn Column: https: //blog.csdn.net/love468092550
major share JVM, Spring, Spring Boot, Cloud , IDEA, Dubbo, Redis, git, micro-services,
MySQL, clusters, distributed, middleware, message queues, Linux, network, multi-threaded, No. public development, applet development, face questions Wait.


 

Foreword

Java generics (generics) is a new feature introduced in JDK 5, generics provide compile-time type safety detection mechanism, this mechanism allows developers to detect illegal type at compile time.

Generic nature of the parameter type, data type that is being operated is specified as a parameter.

The benefits brought by generics

In the absence of generic case, the parameters achieved by reference to Object type "arbitrary" and "arbitrary" of the disadvantages of explicit do is cast, and this conversion is required developer the case of the actual parameter types can predict performed.

For mandatory conversion error, the compiler may not prompt an error, it appears abnormal at run time, which is itself a security risk.

Then the generic benefit is able to check at compile time type safety, and all the cast are automatic and implicit.

public class GlmapperGeneric<T> {
        private T t;
    public void set(T t) { this.t = t; }
    public T get() { return t; }

    public static void main(String[] args) {
        // do nothing
    }

  /**
    * 不指定类型
    */
  public void noSpecifyType(){
    GlmapperGeneric glmapperGeneric = new GlmapperGeneric();
    glmapperGeneric.set("test");
    // 需要强制类型转换
    String test = (String) glmapperGeneric.get();
    System.out.println(test);
  }

  /**
    * 指定类型
    */
  public void specifyType(){
    GlmapperGeneric<String> glmapperGeneric = new GlmapperGeneric();
    glmapperGeneric.set("test");
    // 不需要强制类型转换
    String test = glmapperGeneric.get();
    System.out.println(test);
  }
}

specifyType method of the above code is omitted from cast, at compile time type safety check, it can be used in classes, methods, interfaces.

Generics wildcards

We define a generic class, generic methods, when generic interface often run into a lot of different wildcards, such as T, E, K, V, etc., these are the wild card and what does that mean?

Common T, E, K, V ,?

These are essentially a wildcard, nothing different, just something a convention when coding. For example, in the above code T, we can replace any letter between AZ can be, and will not affect the normal operation of the program, but if replaced by other letters instead of T, on the readability may be weaker. Typically, T, E, K, V ,? It is this agreement:

  • ? Represent undefined type java

  • T (type) is represented by a specific type java

  • KV (key value) represent the key Key Value java

  • E (element) on behalf of Element

? Unbounded wildcard

Start with a small example looks, in the original:

https://codeday.me/bug/20180113/116421.html

I have a parent class Animal and several sub-categories, such as dogs, cats, etc., and now I need a list of animals, my first thought was like this:

List<Animal> listAnimals

But the boss's idea is really this:

List<? extends Animal> listAnimals

Why use a wildcard rather than a simple generic it? Wildcards In fact, when you declare a local variable is meaningless, but when you declare a method as a parameter, it is very important.

static int countLegs (List<? extends Animal > animals ) {
    int retVal = 0;
    for ( Animal animal : animals )
    {
        retVal += animal.countLegs();
    }
    return retVal;
}

static int countLegs1 (List< Animal > animals ){
    int retVal = 0;
    for ( Animal animal : animals )
    {
        retVal += animal.countLegs();
    }
    return retVal;
}

public static void main(String[] args) {
    List<Dog> dogs = new ArrayList<>();
     // 不会报错
    countLegs( dogs );
    // 报错
    countLegs1(dogs);
}

When you call countLegs1, it will be rosy, suggesting the following error message:

So, for uncertain or do not care about the type of operation to be practical, you can use an unrestricted wildcard (angle brackets in a question mark, that is  <?>), that can hold any type. Like countLegs approach, defining the last, but do not care about what specific type, so for all subclasses of Animal incoming can support, and does not complain. And countLegs1 can not.

The upper bound wildcard <? Extends E>

The upper bound: The extends keyword statement, represents the parameterized type may be specified by type or subtype of class.

Represents the generic use extends the argument must be a subclass of E or E in a type parameter, this has two advantages:

  • If the incoming type is not a subclass of E or E, the compiler unsuccessful

  • Generics can use E method, or else have to turn into a strong E to use

 

private <K extends A, E extends B> E test(K arg1, E arg2){
    E result = arg2;
    arg2.compareTo(arg1);
    //.....
    return result;
}

Type parameter list if there are a plurality of types of parameters ceiling, separated by commas

Lower bound wildcard <? Super E>

Lower bound: declared by super, a parameter indicating the type may be of the type specified, or a supertype of this type until Object

Use super generic parameters indicates that the parent must be in the E or E type parameter.

private <T> void test(List<? super T> dst, List<T> src){
    for (T t : src) {
        dst.add(t);
    }
}

public static void main(String[] args) {
    List<Dog> dogs = new ArrayList<>();
    List<Animal> animals = new ArrayList<>();
    new Test3().test(animals,dogs);
}
// Dog 是 Animal 的子类
class Dog extends Animal {

}

Type dst "not less than" src type, where the "Greater than" refers to a range of larger than dst indicates the src, dst so pretend to be a container can be installed src.

? And the difference between T

? And T have said the type of uncertainty, the difference is that we can operate on the T, but? No, this example is as follows:

// 可以
T t = operate();

// 不可以
?car = operate();

Brief summary follows:

T is a certain type, and is typically used to define the generic class of the generic method,? Type is an uncertain, generally for a generic method and calling code parameter, a generic definition of classes and methods can not be used.

1 difference: to ensure the consistency of generic parameters by T

// 通过 T 来 确保 泛型参数的一致性
public <T extends Number> void
test(List<T> dest, List<T> src)

//通配符是 不确定的,所以这个方法不能保证两个 List 具有相同的元素类型
public void
test(List<? extends Number> dest, List<? extends Number> src)

Like the following code, agreed that T Number of subclasses can be, but is declared when the String, so the error will be rosy.

List can not guarantee that two elements have the same type of situation

GlmapperGeneric<String> glmapperGeneric = new GlmapperGeneric<>();
List<String> dest = new ArrayList<>();
List<Number> src = new ArrayList<>();
glmapperGeneric.testNon(dest,src);

The above code is not an error in the compiler, but when internal testNon method proceeds to operation (such as assignment), and for dest src, it would still require conversion.

2 differences: type multiple parameters may be defined not Wildcard

Symbol set & using multiple boundaries (Multi Bounds), T must be a generic type designated subtype consensus MultiLimitInterfaceB MultiLimitInterfaceA and at this time variable t is defined to have all the attributes and methods. For wildcards, because it is not a determination of the type can not be defined for multiple.

Difference 3: Wildcards can be defined using the superclass and not a type parameter

Type parameter T defines only one type by:

T extends A

? But wildcards for either limited:

? extends A
? super A

Class <T> and Class <?> Difference

Introduced in front of? And the difference between T, then for, Class<T> and  <Class<?> what difference does it make?

The most common scenario is used in the reflection, where the code used to transmit the period will be described next.

// 通过反射的方式生成  multiLimit 
// 对象,这里比较明显的是,我们需要使用强制类型转换
MultiLimit multiLimit = (MultiLimit)
Class.forName("com.glmapper.bridge.boot.generic.MultiLimit").newInstance();

对于上述代码,在运行期,如果反射的类型不是 MultiLimit 类,那么一定会报 java.lang.ClassCastException 错误。

对于这种情况,则可以使用下面的代码来代替,使得在在编译期就能直接 检查到类型的问题:

Class<T> 在实例化的时候,T 要替换成具体类。Class<?> 它是个通配泛型,? 可以代表任何类型,所以主要用于声明时的限制情况。比如,我们可以这样做申明:

// 可以
public Class<?> clazz;
// 不可以,因为 T 需要指定类型
public Class<T> clazzT;

所以当不知道定声明什么类型的 Class 的时候可以定义一 个Class<?>

那如果也想 public Class<T> clazzT; 这样的话,就必须让当前的类也指定 T ,

public class Test3<T> {
    public Class<?> clazz;
    // 不会报错
    public Class<T> clazzT;

小结

本文零碎整理了下 JAVA 泛型中的一些点,不是很全,仅供参考。如果文中有不当的地方,欢迎指正。


 

本文已经获得尚珣老师授权转发,其他人若有兴趣转载,请直接联系作者授权。

 


作者简介:
尚珣老师,从事7年JAVA开发工作,
擅长 Javaweb,小程序  物联网开发   公众号开发
公众号:java后端技术精选
csdn专栏:https://blog.csdn.net/love468092550
主要分享JVM、Spring、Spring Boot、Cloud、IDEA、Dubbo、Redis、git、微服务、
MySQL、集群、分布式、中间件、消息队列、Linux、网络、多线程、公众号开发、小程序开发、面试题等。

发布了759 篇原创文章 · 获赞 1062 · 访问量 59万+

Guess you like

Origin blog.csdn.net/jnshu_it/article/details/104682521