search
HomeJavajavaTutorialLet's analyze Java generics and generic wildcards together

This article brings you relevant knowledge about java, which mainly introduces issues related to generics and generic wildcards, because the support of generics is compiler support, byte Generic information has been erased when the code is loaded into the virtual machine, so generics do not support some runtime features. Let's take a look at them together. I hope it will be helpful to everyone.

Let's analyze Java generics and generic wildcards together

Recommended study: "java video tutorial"

Generics are not a runtime feature

We still have it here What I’m talking about is Open JDK

Because generic support is supported by the compiler, the generic information has been erased when the bytecode is loaded into the virtual machine, so generics do not support some runtime features. So be aware that some writing methods will not compile, such as new.

As follows, the class Plate is a class with generics, as shown below,

new Plate(...)
new Plate<T>(...)
class Plate<T> {
    T item;
    public Plate(T t) {
        new T();//是错误的,因为T是一个不被虚拟机所识别的类型,最终会被编译器擦除转为Object类给到虚拟机
        item = t;
    }
    public void set(T t) {
        item = t;
    }
    public T get() {
        return item;
    }
}

The generic T cannot be new, because T is a type that is not recognized by the virtual machine.

Generic wildcard

There are three forms of generic variable expression using wildcard characters, which are:

  • ## extends A>: C extends A> c, the element types in c are all A or subclasses of A

  • ## super B>:C super B> c, in c The element type is B or the parent class of B
  • ##>: C> c, the element type in c is uncertain
  • Let’s take a look at what it specifically means and how to use it~
Upper bound wildcard

In the field of object-oriented programming, we believe that the base class base is at the top. From the perspective of the inheritance tree, the Object class is at the top.

So we call this expression extends T> the upper bound wildcard.

extends T>Represents T or any generic type that inherits T type.

First look at the following example.

RequestBodyAdvice in Sping Webmvc

public interface RequestBodyAdvice {
   /**
    * Invoked first to determine if this interceptor applies.
    * @param methodParameter the method parameter
    * @param targetType the target type, not necessarily the same as the method
    * parameter type, e.g. for {@code HttpEntity<String>}.
    * @param converterType the selected converter type
    * @return whether this interceptor should be invoked or not
    */
   boolean supports(MethodParameter methodParameter, Type targetType,
         Class<? extends HttpMessageConverter<?>> converterType);
   ...
}
In ping Webmvc, RequestBodyAdvice is used to Processing the body of the http request, supports is used to determine whether the conversion of a certain parameter type to an HttpMessage request is supported.

HttpMessageConverter is an interface, such as the JsonViewRequestBodyAdvice class that supports Body in Json format. The implementation is as follows:

@Override
public boolean supports(MethodParameter methodParameter, Type targetType,
      Class<? extends HttpMessageConverter<?>> converterType) {
   return (AbstractJackson2HttpMessageConverter.class.isAssignableFrom(converterType) &&
         methodParameter.getParameterAnnotation(JsonView.class) != null);
}

Use AbstractJackson2HttpMessageConverter to process JsonView. The Jackson2 library is one of the popular Java JSON parsing libraries. Springboot's own HttpMessageConverter.

Different users can define different types of Advice, so that it can support a lot of parameter types such as xml, and the function of sping-webmvc will be more flexible and versatile. Translate many Types into different HttpInputMessage requests through different HttpMessageConverters. As shown below,

@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage request, MethodParameter parameter,
      Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
   for (RequestBodyAdvice advice : getMatchingAdvice(parameter, RequestBodyAdvice.class)) {
      if (advice.supports(parameter, targetType, converterType)) {
         request = advice.beforeBodyRead(request, parameter, targetType, converterType);
      }
   }
   return request;
}

obtains the matching advice list through getMatchingAdvice(parameter, RequestBodyAdvice.class), traverses this list, parses the advice that supports parameter, and obtains a request of type HttpInputMessage.

The expression of the upper bound wildcard can no longer be set

The expression using the previous wildcard can no longer set the generic field. In fact, it means that the upper bound wildcard is no longer set. Wildcards cannot change the set generic type. Let's take a look at this demo.

    @Test
    void genericTest() {
       
        Plate<Apple> p = new Plate<Apple>(new Apple());
        p.set(new Apple());//可以set
          Apple apple = p.get();
          
        Plate<? extends Fruit> q = new Plate<Apple>(new Apple());
       
        Fruit fruit = q.get();
      
         q.set(new Fruit());//将编译错误
    }

Plate extends Fruit>This expression means that the Java compiler only knows that the container contains Fruit and its derived classes. The specific type is not known, it may be Fruit, Apple or other Subclass, after the compiler assigns p, the plate is not marked as "Apple", but is marked with a placeholder "CAP#1" (which can be serious by decompiling the bytecode with javap) to indicate the capture of a Fruit or A subclass of Fruit.

But regardless of whether it is written as a wildcard, generics ultimately refer to a specific type, and the compiler uses a special "CAP#1", so we can no longer reset this field. Otherwise, compilation errors with inconsistent types will occur.

But this feature does not hinder usage. The framework uses the upper bound wildcard paradigm to achieve flexible expansion.

Lower bound wildcard

Next let’s look at the lower bound wildcard, super T> represents any type of T or T’s parent class, and the lower bound type is T.

Language trap

We easily fall into a trap in understanding, thinking that we can only set Fruit or the base class of Fruit. In fact, only Fruit and Fruit subclasses can be set in. Let's write a unit test to see.

@Test
void genericSuperTest() {
    Plate<? super Fruit> p = new Plate<Fruit>(new Fruit());
    p.set(new Apple()); //ok,存取的时候可以存任意可以转为T的类或T
    p.set(new Object()); //not ok,无法 set Object
    Object object = p.get();//ok
    Fruit object = p.get();//not ok,super Fruit不是Fruit的子类
}

When accessing, you can save classes or T that can be converted to T, that is, classes that can set Fruit or Fruit subclasses.

But you must use object to reference when using it.

spring-kafka’s asynchronous callback

Now, let’s look at a practical example.

SettableListenableFuture是spring 并发框架的一个类,继承自Future,我们知道Future表示异步执行的结果,T表示返回结果的类型。ListenableFuture可以支持设置回调函数,如果成功了怎么处理,如果异常又如何处理。

在spring-kafka包里使用了SettableListenableFuture来设置异步回调的结果,kafka客户端调用 doSend发送消息到kafka队列之后,我们可以异步的判断是否发送成功。

public class SettableListenableFuture<T> implements ListenableFuture<T> {
  ...
   @Override
   public void addCallback(ListenableFutureCallback<? super T> callback) {
      this.settableTask.addCallback(callback);
   }
   @Override
   public void addCallback(SuccessCallback<? super T> successCallback, FailureCallback failureCallback) {
      this.settableTask.addCallback(successCallback, failureCallback);
   }
 ...

SettableListenableFuture有重载的addCallback函数,支持添加ListenableFutureCallback super T> callback和SuccessCallback super T> successCallback;当调用的异步方法成功结束的时候使用notifySuccess来触发onSuccess的执行,这个时候将实际异步执行的结果变成参数给callback调用。

private void notifySuccess(SuccessCallback<? super T> callback) {
   try {
      callback.onSuccess((T) this.result);
   }
   catch (Throwable ex) {
      // Ignore
   }
}

SuccessCallback是一个函数式接口,从设计模式的角度来看是一个消费者,消费类型的result。ListenableFutureCallback同理。

public interface SuccessCallback<T> {
   /**
    * Called when the {@link ListenableFuture} completes with success.
    * <p>Note that Exceptions raised by this method are ignored.
    * @param result the result
    */
   void onSuccess(@Nullable T result);
}

为什么要用notifySuccess(SuccessCallback super T> callback)呢?

这是因为super能支持的范围更多,虽然实际产生了某一个具体类型的结果,比如kafka的send函数产生的结果类型为SendResult,其他的客户端可能使用其他的Result类型,但是不管是什么类型,我们在使用Spring的时候,可以对异步的结果统一使用Object来处理。

比如下面的这段代码,虽然是针对kafka客户端的。但对于其他的使用了Spring SettableListenableFuture的客户端,我们也可以在addCallback函数里使用Object来统一处理异常。

 @SneakyThrows
    public int kafkaSendAndCallback(IMessage message) {
        String msg = new ObjectMapper().writeValueAsString(message);
        log.debug("msg is {}. ", msg);
        ListenableFuture send = kafkaTemplate.send("test", msg);
        addCallback(message, send);
        return 0;
    }
    private void addCallback(IMessage msg, ListenableFuture<SendResult<String, String>> listenableFuture) {
        listenableFuture.addCallback(
                new SuccessCallback<Object>() {
                    @Override
                    public void onSuccess(Object o) {
                        log.info("success send object = " + msg.getContentType() + msg.getId());
                    }
                },
                new FailureCallback() {
                    @Override
                    public void onFailure(Throwable throwable) {
                        log.error("{}发送到kafka异常", msg.getContentType() + msg.getId(), throwable.getCause());
                    }
                });
    }
}

声明某个条件的任意类型?

比如 Collection类的这个函数,

@Override
public boolean removeAll(Collection<?> collection) {
  return delegate().removeAll(collection);
}

Collection的removeAll函数移除原集合中的一些元素,因为最终使用equals函数比较要移除的元素是否在集合内,所以这个元素的类型并不在意。

我们再看一个例子,LoggerFactory

public class LoggerFactory {
    public static Logger getLogger(Class<?> clazz) {
        return new Logger(clazz.getName());
    }
}

LoggerFactory可以为任意Class根据它的名字生成一个实例。

总结:设计模式PECS

PECS是producer extends consumer super的缩写。

也是对我们上面的分析的一个总结

意思是extends用于生产者模式,而super用于消费者模式。

  • 消费者模式:比如上面的callback结果是为了消费;这些结果被消费处理。

  • 生产者模式:比如那些Converter,我们要处理特定格式的http请求,需要生产不同的转换器Converter。

推荐学习:《java视频教程

The above is the detailed content of Let's analyze Java generics and generic wildcards together. For more information, please follow other related articles on the PHP Chinese website!

Statement
This article is reproduced at:掘金. If there is any infringement, please contact admin@php.cn delete
带你搞懂Java结构化数据处理开源库SPL带你搞懂Java结构化数据处理开源库SPLMay 24, 2022 pm 01:34 PM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于结构化数据处理开源库SPL的相关问题,下面就一起来看一下java下理想的结构化数据处理类库,希望对大家有帮助。

Java集合框架之PriorityQueue优先级队列Java集合框架之PriorityQueue优先级队列Jun 09, 2022 am 11:47 AM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于PriorityQueue优先级队列的相关知识,Java集合框架中提供了PriorityQueue和PriorityBlockingQueue两种类型的优先级队列,PriorityQueue是线程不安全的,PriorityBlockingQueue是线程安全的,下面一起来看一下,希望对大家有帮助。

完全掌握Java锁(图文解析)完全掌握Java锁(图文解析)Jun 14, 2022 am 11:47 AM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于java锁的相关问题,包括了独占锁、悲观锁、乐观锁、共享锁等等内容,下面一起来看一下,希望对大家有帮助。

一起聊聊Java多线程之线程安全问题一起聊聊Java多线程之线程安全问题Apr 21, 2022 pm 06:17 PM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于多线程的相关问题,包括了线程安装、线程加锁与线程不安全的原因、线程安全的标准类等等内容,希望对大家有帮助。

详细解析Java的this和super关键字详细解析Java的this和super关键字Apr 30, 2022 am 09:00 AM

本篇文章给大家带来了关于Java的相关知识,其中主要介绍了关于关键字中this和super的相关问题,以及他们的一些区别,下面一起来看一下,希望对大家有帮助。

Java基础归纳之枚举Java基础归纳之枚举May 26, 2022 am 11:50 AM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于枚举的相关问题,包括了枚举的基本操作、集合类对枚举的支持等等内容,下面一起来看一下,希望对大家有帮助。

java中封装是什么java中封装是什么May 16, 2019 pm 06:08 PM

封装是一种信息隐藏技术,是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法;封装可以被认为是一个保护屏障,防止指定类的代码和数据被外部类定义的代码随机访问。封装可以通过关键字private,protected和public实现。

归纳整理JAVA装饰器模式(实例详解)归纳整理JAVA装饰器模式(实例详解)May 05, 2022 pm 06:48 PM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于设计模式的相关问题,主要将装饰器模式的相关内容,指在不改变现有对象结构的情况下,动态地给该对象增加一些职责的模式,希望对大家有帮助。

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
2 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
Repo: How To Revive Teammates
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: How To Get Giant Seeds
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

SublimeText3 Linux new version

SublimeText3 Linux new version

SublimeText3 Linux latest version

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

Atom editor mac version download

Atom editor mac version download

The most popular open source editor

WebStorm Mac version

WebStorm Mac version

Useful JavaScript development tools

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

Powerful PHP integrated development environment