code: private static Type[] normalizeUpperBounds(final Type[] bounds) {
          Assert.requireNonNull(bounds, "bounds");
          // don't bother if there's only one (or none) type
          if (bounds.length < 2) {
              return bounds;
          }
  
          final Set<Type> types = new HashSet<>(bounds.length);
  
          for (final Type type1 : bounds) {
              boolean subtypeFound = false;
  
              for (final Type type2 : bounds) {
                  if (type1 != type2 && isAssignable(type2, type1, null)) {
                      subtypeFound = true;
                      break;
                  }
              }
  
              if (!subtypeFound) {
                  types.add(type1);
              }
          }
  
          return types.toArray(new Type[types.size()]);
      }
docs: <p>This method strips out the redundant upper bound types in type
  variable types and wildcard types (or it would with wildcard types if
  multiple upper bounds were allowed).</p> <p>Example, with the variable
  type declaration:
  <p>
  <pre>&lt;K extends java.util.Collection&lt;String&gt; &amp;
  java.util.List&lt;String&gt;&gt;</pre>
  <p>
  <p>
  since {@code List} is a subinterface of {@code Collection},
  this method will return the bounds as if the declaration had been:
  </p>
  <p>
  <pre>&lt;K extends java.util.List&lt;String&gt;&gt;</pre>
  
  @param bounds an array of types representing the upper bounds of either
  {@link WildcardType} or {@link TypeVariable}, not {@code null}.
  @return an array containing the values from {@code bounds} minus the
  redundant types.