<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Yuriy F</title>
    <description>The latest articles on DEV Community by Yuriy F (@yuriy_f_0991a94b85ba44f9e).</description>
    <link>https://dev.to/yuriy_f_0991a94b85ba44f9e</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3511723%2Fdf0cbace-db8a-4440-97e6-254b1f416d59.png</url>
      <title>DEV Community: Yuriy F</title>
      <link>https://dev.to/yuriy_f_0991a94b85ba44f9e</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yuriy_f_0991a94b85ba44f9e"/>
    <language>en</language>
    <item>
      <title>Same named methods in Java. Part 2: When Generics Warp Overload Resolution</title>
      <dc:creator>Yuriy F</dc:creator>
      <pubDate>Mon, 06 Oct 2025 19:54:31 +0000</pubDate>
      <link>https://dev.to/yuriy_f_0991a94b85ba44f9e/same-named-methods-in-java-part-2-when-generics-warp-overload-resolution-42no</link>
      <guid>https://dev.to/yuriy_f_0991a94b85ba44f9e/same-named-methods-in-java-part-2-when-generics-warp-overload-resolution-42no</guid>
      <description>&lt;p&gt;As we learned in Part 1 of this series, &lt;a href="https://dev.to/yuriy_f_0991a94b85ba44f9e/same-named-methods-in-java-part-1-dont-underestimate-overloading-1f4i"&gt;Don’t Underestimate Overloading&lt;/a&gt;, overloading is about guessing. The compiler is trying to guess which method to execute, based on the types of parameters you pass. Generics add another layer of guessing called type inference. That’s the compiler trying to guess the parameter types from the context before deciding which overload to pick. For this part, again, we’ll leave compilation errors aside — those are safe because the compiler and IDEs do a good job pointing them out right away. t is more dangerous when code compiles but a different method is called than expected. Or when a “harmless” signature change causes a different overload to be picked. We are also not going to touch inheritance - we will dive into it in future parts.&lt;/p&gt;

&lt;p&gt;Let’s check this example we’ll review later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.io.Serializable&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Teaser&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Serializable&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"m(T)"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
                                 &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"m(instance T)"&lt;/span&gt;&lt;span class="o"&gt;);}&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Teaser&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="na"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Teaser&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="na"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see two calls that look nearly identical end up taking different paths, all because of how generics, inference, and overloading interact.&lt;/p&gt;

&lt;p&gt;Before we dive into inference and overload resolution, let us take a quick step back. Generics in Java are a way to parameterize types. Instead of writing the same code for String, Integer, List, etc., we use a type parameter, like T, and then the compiler substitutes it in.&lt;/p&gt;

&lt;p&gt;Generics can be declared at two different levels:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Type level&lt;/strong&gt; — the type parameter is attached to the whole type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
  &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; 
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt; 
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Method level&lt;/strong&gt; — the type parameter exists only for that method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Utils&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
   &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;identity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt; 
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To simplify, we’ll start with method-level generics only, since that is where inference and overload resolution play together most directly. Once we’ve covered how the compiler “guesses” method-level types, we’ll bring class-level generics back in and see how they make things even more complicated.&lt;/p&gt;

&lt;p&gt;With generics involved, the compiler has to juggle two separate decisions at once:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Which type variable substitutions make the call type-correct.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Which overload is the most specific match once those substitutions are made.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sometimes these guesses reinforce each other, and everything looks obvious. Other times, they clash, and you get outcomes that seem counter-intuitive. That is why two almost identical calls may resolve to different methods, or why a method that looks like a perfect candidate isn’t even considered applicable.&lt;/p&gt;

&lt;p&gt;Generics in Java are tied to two separate compile-time processes. Both happen before your code ever reaches the JVM, but they serve very different purposes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Type inference&lt;/strong&gt; is &lt;em&gt;how&lt;/em&gt; the compiler figures out which types to plug in when choosing a method. This guides overload resolution and ensures type safety without requiring you to spell out every &lt;code&gt;&amp;lt;T&amp;gt;&lt;/code&gt; explicitly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Type erasure&lt;/strong&gt; is what the compiler does &lt;em&gt;after&lt;/em&gt; that choice, to generate valid bytecode for the JVM.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s look at this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;pick&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
        &lt;span class="c1"&gt;// infers T = Integer&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pick&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; 

        &lt;span class="c1"&gt;// infers T = Comparable&amp;lt;? extends Object&amp;gt;&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pick&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Comparable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;)&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; 

        &lt;span class="c1"&gt;// infers T = Number &amp;amp; Constable &amp;amp; ConstantDesc &amp;amp; Comparable&amp;lt;? extends Number &amp;amp; Comparable&amp;lt;?&amp;gt; &amp;amp; Constable &amp;amp; ConstantDesc&amp;gt;&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pick&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2L&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; 
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compiler guesses &lt;code&gt;T&lt;/code&gt; differently depending on context — that’s type inference. The method declaration, after compilation, is erased to:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pick(Object, Object)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bounded generics&lt;/strong&gt; add constraints to a type variable: &lt;code&gt;T&lt;/code&gt; must be a subtype (or an implementation) of some bound. The common form is an &lt;em&gt;upper bound&lt;/em&gt; with &lt;code&gt;extends&lt;/code&gt;, e.g. &lt;code&gt;&amp;lt;T extends Number&amp;gt;&lt;/code&gt;, and you can have intersection bounds like &lt;code&gt;&amp;lt;T extends Number &amp;amp; Comparable&amp;lt;T&amp;gt;&amp;gt;&lt;/code&gt;. Bounds affect &lt;strong&gt;applicability&lt;/strong&gt; (an overload with &lt;code&gt;&amp;lt;T extends CharSequence&amp;gt;&lt;/code&gt; can’t accept &lt;code&gt;Object&lt;/code&gt;) and often affect &lt;strong&gt;specificity&lt;/strong&gt; (a bounded parameter is considered “tighter” than an unbounded &lt;code&gt;&amp;lt;T&amp;gt;&lt;/code&gt; when both are applicable). That’s why introducing or tightening a bound can silently change which overload the compiler picks, while everything still compiles.&lt;/p&gt;

&lt;p&gt;In the example below:&lt;br&gt;&lt;br&gt;
&lt;code&gt;static &amp;lt;T extends Number&amp;gt; void pick(T a, T b)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;will be erased to:&lt;br&gt;&lt;br&gt;
&lt;code&gt;void pick(Number, Number)&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Example&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;                &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;pick&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unbounded"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;pick&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bounded"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="c1"&gt;// infers T = Serializable &amp;amp; Comparable&amp;lt;? extends Serializable &amp;amp; Comparable&amp;lt;?&amp;gt; &amp;amp; Constable &amp;amp; ConstantDesc&amp;gt; &amp;amp; Constable &amp;amp; ConstantDesc&lt;/span&gt;
        &lt;span class="n"&gt;pick&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Prints Unbounded&lt;/span&gt;

        &lt;span class="c1"&gt;// infers T = Integer&lt;/span&gt;
        &lt;span class="n"&gt;pick&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Prints Bounded&lt;/span&gt;

        &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// infers T = Object&lt;/span&gt;
        &lt;span class="n"&gt;pick&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;//Prints Unbounded&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In all three calls, &lt;strong&gt;inference first&lt;/strong&gt; tries to find a single &lt;code&gt;T&lt;/code&gt; that fits both arguments; then overload resolution picks the &lt;strong&gt;most specific&lt;/strong&gt; applicable method:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;For &lt;code&gt;pick(1, "a")&lt;/code&gt;, the bounded overload &lt;code&gt;&amp;lt;T extends Number&amp;gt;&lt;/code&gt; is &lt;strong&gt;not applicable&lt;/strong&gt; ( &lt;code&gt;"a"&lt;/code&gt; isn’t a &lt;code&gt;Number&lt;/code&gt; ), so the &lt;strong&gt;unbounded&lt;/strong&gt; version wins; the compiler chooses an intersection type that both &lt;code&gt;Integer&lt;/code&gt; and &lt;code&gt;String&lt;/code&gt; satisfy (e.g., &lt;code&gt;Serializable &amp;amp; Comparable&amp;lt;?&amp;gt; &amp;amp; Constable &amp;amp; ConstantDesc&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For &lt;code&gt;pick(1, 2)&lt;/code&gt;, both overloads are applicable with &lt;code&gt;T = Integer&lt;/code&gt;, and the &lt;strong&gt;bounded&lt;/strong&gt; one is more specific, so it prints &lt;strong&gt;Bounded&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For &lt;code&gt;Object n = 2; pick(1, n)&lt;/code&gt;, the static types are &lt;code&gt;Integer&lt;/code&gt; and &lt;code&gt;Object&lt;/code&gt;; the bounded overload can’t accept &lt;code&gt;Object&lt;/code&gt; (not a &lt;code&gt;Number&lt;/code&gt;), but the unbounded one can infer &lt;code&gt;T = Object&lt;/code&gt;, so it prints &lt;strong&gt;Unbounded&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But what if argument types are not available? Let’s look at another example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NullPick&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;                &lt;span class="no"&gt;U&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;U&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"m(U)"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;;}&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;U&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;U&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;U&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"m(U extends Number)"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//infers U = Integer&lt;/span&gt;
        &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Prints m(U extends Number)&lt;/span&gt;

        &lt;span class="c1"&gt;//infers U = Number&lt;/span&gt;
        &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;//Prints m(U extends Number)&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For both calls, &lt;code&gt;null&lt;/code&gt; fits any reference type and is no help for the type inference. Both declared methods are applicable for both calls, i.e. can handle null. And &lt;code&gt;m( U extends Number)&lt;/code&gt;wins in both cases as a more specific method for the arguments.&lt;/p&gt;

&lt;p&gt;But what if I add another call:&lt;br&gt;&lt;br&gt;
&lt;code&gt;String s = m(null);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It causes a compilation error instead of a seemingly logical choice - the first method declared, “&lt;code&gt;&amp;lt;U&amp;gt; U m(U u)&lt;/code&gt;”. The reason is that &lt;code&gt;m(U extends Number)&lt;/code&gt; is still most specific, and cannot return String. And if I want this call to compile, I need to give an additional hint:&lt;br&gt;&lt;br&gt;
&lt;code&gt;String t = NullPick.&amp;lt;String&amp;gt;m(null);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;OR&lt;/p&gt;

&lt;p&gt;&lt;code&gt;String t = m((String)null);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Note that while the return type is inferred, it does not participate in overload resolution.&lt;/p&gt;

&lt;p&gt;The type could be bound to at most one class and to multiple interfaces. If there is a class, it must appear first (leftmost). The erasure will use the leftmost type.&lt;/p&gt;

&lt;p&gt;For example methods defined here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Example&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nc"&gt;Comparable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;      &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;;}&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Serializable&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nc"&gt;Comparable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;;}&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Comparable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nc"&gt;Serializable&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Are erased to :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Serializable&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Serializable&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Comparable&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Comparable&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But in this case, even though erasures are different, the compiler will not be able to pick between the last two methods, so both are unusable in practice.&lt;/p&gt;

&lt;p&gt;Now let’s look at the example (we remove one of the ambiguous methods ):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Example&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nc"&gt;Comparable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;       &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Number"&lt;/span&gt;&lt;span class="o"&gt;);}&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Comparable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nc"&gt;Serializable&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Serializable"&lt;/span&gt;&lt;span class="o"&gt;);}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Prints Number&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Prints Number&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Prints Serializable&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First two calls print &lt;code&gt;Number&lt;/code&gt;. The reason is &lt;code&gt;Number&lt;/code&gt; actually implements &lt;code&gt;Serializable&lt;/code&gt;, so it is the more specific candidate. The last call does not extend &lt;code&gt;Number&lt;/code&gt;, but it does implement &lt;code&gt;Comparable&lt;/code&gt; and &lt;code&gt;Serializable&lt;/code&gt;, which provides enough argument type information for the compiler to pick a method.&lt;/p&gt;

&lt;p&gt;Now let’s see how adding Type level generics definitions affect the overload resolution. Check out the code below and compare it to &lt;em&gt;NullPick&lt;/em&gt; example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;X&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;{&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;U&lt;/span&gt;  &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;U&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;U&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"m(U extends Number)"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;;}&lt;/span&gt;
                        &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"m(T)"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ClassLevelGeneric&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="no"&gt;X&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="no"&gt;X&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;    &lt;span class="c1"&gt;//Prints m(U extends Number)&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Prints m(T)&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;//Prints m(T)&lt;/span&gt;
        &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'a'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;    &lt;span class="c1"&gt;//Prints m(U extends Number)&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even though by erasure, &lt;code&gt;&amp;lt;U extends Number&amp;gt; U m(U u)&lt;/code&gt; is more specific than &lt;code&gt;T m(T t)&lt;/code&gt; we see that &lt;code&gt;m(null)&lt;/code&gt; and &lt;code&gt;m(1L)&lt;/code&gt; resolve to the &lt;code&gt;T m(T t)&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;With all that in mind, let’s take another look into the teaser from the beginning of the article:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.io.Serializable&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Teaser&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Serializable&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"m(T)"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
                                 &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"m(instance T)"&lt;/span&gt;&lt;span class="o"&gt;);}&lt;/span&gt;

        &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Teaser&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="na"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Teaser&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="na"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first call passes an Integer, and out of two methods, one taking &lt;code&gt;Long&lt;/code&gt; and one taking something that &lt;code&gt;extends Serializable&lt;/code&gt;, only the &lt;code&gt;Serializable&lt;/code&gt; one is eligible.&lt;/p&gt;

&lt;p&gt;The second call also passes an Integer. But now we have both methods eligible: one taking an &lt;code&gt;Integer&lt;/code&gt; and one taking a &lt;code&gt;Serializable&lt;/code&gt;. The &lt;code&gt;Integer&lt;/code&gt; one is more specific and wins.&lt;/p&gt;

&lt;p&gt;One thing to keep an eye on — the &lt;code&gt;T&lt;/code&gt; in &lt;code&gt;&amp;lt;T extends Serializable&amp;gt; void m(T a)&lt;/code&gt; and the &lt;code&gt;T&lt;/code&gt; in &lt;code&gt;Teaser&amp;lt;T&amp;gt;&lt;/code&gt; are two different, absolutely unrelated type variables.&lt;/p&gt;

&lt;p&gt;But what if we just do &lt;code&gt;new Teaser().m(null)&lt;/code&gt; ? This way we have two methods, one expecting something that extends &lt;code&gt;Serializable&lt;/code&gt;, and one that takes &lt;code&gt;Object&lt;/code&gt;. &lt;code&gt;Serializable&lt;/code&gt; one is more specific and wins, printing &lt;code&gt;m(T)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, let’s look at wildcards. A wildcard means “some unknown type” and depicted with “?”. You mostly see it as &lt;code&gt;? extends T&lt;/code&gt; (a &lt;strong&gt;producer&lt;/strong&gt; you read from) and &lt;code&gt;? super T&lt;/code&gt; (a &lt;strong&gt;consumer&lt;/strong&gt; you write to). They exist because &lt;strong&gt;generics are invariant&lt;/strong&gt;: &lt;code&gt;List&amp;lt;Integer&amp;gt;&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; a &lt;code&gt;List&amp;lt;Number&amp;gt;&lt;/code&gt;. Wildcards let you accept families of types safely. In Java, you most often see it all over the Collections API.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.io.Serializable&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;{&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Demo&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="kd"&gt;super&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="kd"&gt;super&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Wildcard"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;;}&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Comparable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Comparable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Extends"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Serializable&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;serializable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;integer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dbl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Prints Wildcard&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializable&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Prints Wildcard&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;di&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Prints Extends&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;dr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dbl&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Prints Extends&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since &lt;code&gt;Repo&amp;lt;? super Number&amp;gt;&lt;/code&gt; and &lt;code&gt;Repo&amp;lt;? extends Comparable&amp;lt;?&amp;gt;&amp;gt;&lt;/code&gt; both erased to &lt;code&gt;Repo&lt;/code&gt;, we can have same-named methods handling each. So we did a little trick: we add a second argument and set it to &lt;code&gt;null&lt;/code&gt; explicitly in the method calls, so no type information could be inferred from it by the compiler. For this to work there should also be no relation between those arguments type, so neither is more specific for the &lt;code&gt;null&lt;/code&gt; constant.&lt;/p&gt;

&lt;p&gt;What’s going on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;m(Repo&amp;lt;? super Number&amp;gt;, Integer)&lt;/code&gt; (“Wildcard”)&lt;br&gt;&lt;br&gt;
Works for &lt;code&gt;Repo&amp;lt;Number&amp;gt;&lt;/code&gt; and also &lt;code&gt;Repo&amp;lt;Serializable&amp;gt;&lt;/code&gt;: &lt;code&gt;? super Number&lt;/code&gt; means “Number or any supertype of Number,” and yes, &lt;strong&gt;interfaces count&lt;/strong&gt;—&lt;code&gt;Number&lt;/code&gt; implements &lt;code&gt;Serializable&lt;/code&gt;, so &lt;code&gt;Serializable&lt;/code&gt; qualifies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;T extends Comparable&amp;lt;T&amp;gt;&amp;gt; m(Repo&amp;lt;T&amp;gt;, String)&lt;/code&gt; (“Extends”)&lt;br&gt;&lt;br&gt;
Grabs Repo instances whose element type is self-comparable: &lt;code&gt;Integer&lt;/code&gt;, &lt;code&gt;Double&lt;/code&gt;, etc. &lt;code&gt;Number&lt;/code&gt; and &lt;code&gt;Serializable&lt;/code&gt; &lt;strong&gt;don’t&lt;/strong&gt; meet that bound, so they fall back to the “Wildcard” method. Here you handle the precise element type (&lt;code&gt;Repo&amp;lt;Integer&amp;gt;&lt;/code&gt;, &lt;code&gt;Repo&amp;lt;Double&amp;gt;&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is a simple example of using wildcards with collections:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.ArrayList&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Collection&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleCollections&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;                 &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Collection&amp;lt;?&amp;gt;"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"List&amp;lt;? extends Number&amp;gt;"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ExampleCollections&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Prints Collection&amp;lt;?&amp;gt; &lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ExampleCollections&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Prints List&amp;lt;? extends Number&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally let’s take a look at another code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.ArrayList&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;


&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MultiType&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Comparable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Same type, extends Comparable"&lt;/span&gt;&lt;span class="o"&gt;);}&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;U&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unbound types"&lt;/span&gt;&lt;span class="o"&gt;);}&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Same lists"&lt;/span&gt;&lt;span class="o"&gt;);}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Prints Unbound types&lt;/span&gt;

        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Prints Same type, extends Comparable&lt;/span&gt;

        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Prints Unbound types&lt;/span&gt;

        &lt;span class="nc"&gt;List&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Prints Same lists&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;m(1.0, 1)&lt;/code&gt;&lt;br&gt;&lt;br&gt;
The “same-type” overload needs a single &lt;code&gt;T&lt;/code&gt; that works for &lt;em&gt;both&lt;/em&gt; arguments &lt;em&gt;and&lt;/em&gt; that &lt;code&gt;T&lt;/code&gt; must implement &lt;code&gt;Comparable&amp;lt;T&amp;gt;&lt;/code&gt;. &lt;code&gt;Double&lt;/code&gt; and &lt;code&gt;Integer&lt;/code&gt; don’t share that one &lt;code&gt;T&lt;/code&gt;, so the catch-all &lt;code&gt;&amp;lt;T,U&amp;gt;&lt;/code&gt; takes the call.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;m(1, 1)&lt;/code&gt;&lt;br&gt;&lt;br&gt;
Both args are &lt;code&gt;Integer&lt;/code&gt;, and &lt;code&gt;Integer&lt;/code&gt; implements &lt;code&gt;Comparable&amp;lt;Integer&amp;gt;&lt;/code&gt;. The same-type overload fits and is more specific than &lt;code&gt;&amp;lt;T,U&amp;gt;&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;m(a, b)&lt;/code&gt;&lt;br&gt;&lt;br&gt;
Generics are &lt;strong&gt;invariant&lt;/strong&gt;: &lt;code&gt;List&amp;lt;Integer&amp;gt;&lt;/code&gt; and &lt;code&gt;List&amp;lt;String&amp;gt;&lt;/code&gt; can’t both be &lt;code&gt;List&amp;lt;T&amp;gt;&lt;/code&gt; with the &lt;em&gt;same&lt;/em&gt; &lt;code&gt;T&lt;/code&gt;. The same-lists overload is out; &lt;code&gt;&amp;lt;T,U&amp;gt;&lt;/code&gt; wins.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;m(c, d)&lt;/code&gt; where &lt;code&gt;c&lt;/code&gt; and &lt;code&gt;d&lt;/code&gt; are raw &lt;code&gt;List&lt;/code&gt;&lt;br&gt;&lt;br&gt;
Erasing element types makes both parameters look like plain &lt;code&gt;List&lt;/code&gt;. That makes &lt;code&gt;m(List&amp;lt;T&amp;gt;, List&amp;lt;T&amp;gt;)&lt;/code&gt; applicable (you’ll get an &lt;strong&gt;unchecked&lt;/strong&gt; warning), and it beats the &lt;code&gt;&amp;lt;T,U&amp;gt;&lt;/code&gt; version here.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Generic method overloading in Java boils down to a two-step guessing game: infer the types, then pick the most specific method. The tricky part is that inference, bounds, and specificity all influence each other, so tiny changes—swapping an argument type, tightening a bound, or just passing null—can completely flip which method gets called. While writing this article, I tested both Claude and GPT on picking the right method; they got roughly a third of the cases wrong, with total confidence. If AI struggles with this, you're in good company when it confuses you too.&lt;/p&gt;

</description>
      <category>java</category>
      <category>oop</category>
      <category>programming</category>
    </item>
    <item>
      <title>Same named methods in Java. Part 1: Don’t Underestimate Overloading</title>
      <dc:creator>Yuriy F</dc:creator>
      <pubDate>Thu, 18 Sep 2025 15:24:14 +0000</pubDate>
      <link>https://dev.to/yuriy_f_0991a94b85ba44f9e/same-named-methods-in-java-part-1-dont-underestimate-overloading-1f4i</link>
      <guid>https://dev.to/yuriy_f_0991a94b85ba44f9e/same-named-methods-in-java-part-1-dont-underestimate-overloading-1f4i</guid>
      <description>&lt;p&gt;Recently I posted a poll on LinkedIn about method selection in overloaded method calls and was rather surprised that only 20% of the answers were correct. That gave me a push to do this write-up, as I feel that same-named methods do not get the credit they deserve for the mess they can cause.&lt;/p&gt;

&lt;p&gt;I plan to continue this as a series. We’ll look at overloading with generics, the role of functional interfaces and lambdas, what happens with inheritance and overriding, and cases involving static imports and visibility across types. This part will look at method overloading within a single type definition (class, interface, or enum). Basically, we’re going to examine how the most specific method is selected by only looking at method arguments.&lt;/p&gt;

&lt;p&gt;Throughout this article, I am not going to get into the different cases of compilation errors, as build process and IDEs are taking a good care of those.&lt;/p&gt;

&lt;p&gt;To start the confusion, let’s look at a short example of two classes (all overloads are defined in one class, just as we talked):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Example1 {
    public static class Helper {
        private void m(double num)      { System.out.println("m(double)"); }
        public  void m(char... chars)   { System.out.println("m(char...)"); }
        public  void m(Comparable c) { System.out.println("m(Comparable)"); }
        public  void m(Object obj)      { System.out.println("m(Object)"); }
    }

    public static void main(String... args) {
        Helper h = new Helper();
        h.m('a');
    }
}

import Example1.Helper;

public class Example2 {
    public static void main(String... args) {
        Helper h = new Helper();
        h.m('a');
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execution of Example1 prints:&lt;br&gt;
&lt;strong&gt;m(double)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Execution of Example2 prints:&lt;br&gt;
&lt;strong&gt;m(Comparable)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Why does this happen? We’ll come back to this puzzle after covering some ground.&lt;/p&gt;

&lt;p&gt;The biggest danger with overloading, is that a change to a method signature or addition of a new method may change which method is getting executed by an unsuspecting caller, as it may not give you any error or even a warning. For the scope of this article it is somewhat simple, though not always obvious. But once we get to the next parts it will be progressively harder to spot.&lt;/p&gt;

&lt;p&gt;When two methods share the same name in Java, they may participate in overloading, overriding, or hiding, depending on their signatures, modifiers, and inheritance hierarchy. I will try to keep my examples short, but I have to say, the mess you can create by combining all three is incredible.&lt;/p&gt;

&lt;p&gt;The idea of overloading is actually older than OOP itself—FORTRAN already let you write ABS for integers or floating-point numbers in the 1950s. C++ in the 1980s then brought user-defined function overloading into mainstream OOP, and Java inherited it from day one. The idea behind it is to improve readability and API consistency by using the same logical name for conceptually similar operations and to allow API growth by adding new overloads without breaking code.&lt;/p&gt;

&lt;p&gt;So, what is overloading about?&lt;/p&gt;

&lt;p&gt;First the formal JLS definition (JLS 8.4.9 &lt;a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.9):" rel="noopener noreferrer"&gt;https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.9):&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;if two methods of a class (whether both declared in the same class, or both inherited by a class, or one declared and one inherited) have the same name but signatures that are not override-equivalent, then the method name is said to be overloaded. This fact causes no difficulty and never by itself results in a compile-time error. There is no required relationship between the return types or between the throws clauses of two methods with the same name, unless their signatures are override-equivalent.&lt;/p&gt;

&lt;p&gt;Since in this part we only going to look at methods defined within a single type, we are going to ignore “override-equivalent”, "inherited" or even not mentioned imported static functions (we will go overall of it in details in Part three) and just say:&lt;br&gt;
if a type declaration contains methods with the same name those methods are overloaded.&lt;br&gt;
This applies regardless of differences in return type, number of parameters, whether the methods are static or instance methods, or their access level. This also assumes there is no compile time error.&lt;/p&gt;

&lt;p&gt;Note: if your class defines more than one constructor, they are considered overloaded just like methods. All of the overload resolution rules we discuss here apply to constructors as well.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;static void m(int x) {}
private int m() { return 0; }
public String m(int x, long y) { return ""; }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Overloading is all about the compiler choosing a method to execute for you. Since it is in the compiler’s realm, this decision is made by the time the compiler has done its job, and it may or may not match your intent. It is not going to be changed at runtime, and if something changes you have to recompile. Let me show what I mean.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;We have two classes, Main and Helper:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package team1;
public class Helper {
    public void m(Object o) {
        System.out.println("m(Object)");
    }
}

import team1.Helper;
public class Main {
    public static void main(String... args) {
       new Helper().m("test");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s assume that the team that wrote class Main doesn’t have any control over the class Helper, and it is provided by another team in the form of a JAR file.&lt;/p&gt;

&lt;p&gt;When you build and execute main, it produces the following output:&lt;br&gt;
&lt;strong&gt;m(Object)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now let’s prove that if we change method m in the Helper class, the JVM will pick up the change without recompiling Main. This should work just fine as per the JLS 13.4.22: “Changes to the body of a method or constructor do not break compatibility with pre-existing binaries.”&lt;/p&gt;

&lt;p&gt;Lets edit the Helper class and rebuild the jar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package team1;
public class Helper {
    public void m(Object o) {
        System.out.println("V2 m(Object)");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we rerun Main, and see the new output:&lt;br&gt;
&lt;strong&gt;V2 m(Object)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Okay, it’s obviously picked up. Now it’s time to change Helper again and repeat the process. We are going to add a new method to it, which is again fine per the JLS 13.4.12: “Adding a method to a class does not break compatibility with pre-existing binaries.”&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package team1;
public class Helper {
    public void m(String o) {
        System.out.println("m(String)");
    }

    public void m(Object o) {
        System.out.println("V2 m(Object)");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just looking at the code, in theory, the call to new Helper().m("test") should print:&lt;br&gt;
&lt;strong&gt;m(String)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But since Main is not recompiled, we will still get:&lt;br&gt;
&lt;strong&gt;V2 m(Object)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And only after we recompiled Main with the new JAR and run it, we will get:&lt;br&gt;
&lt;strong&gt;m(String)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This clearly shows that overload resolution happens at compile time: without recompiling Main, the JVM cannot pick the newly added m(String) overload. Note, no changes to the class Main were done. No methods were modified. A new method was added and the compiler decided it is a better fit for the name and parameters you provided.&lt;/p&gt;

&lt;p&gt;This is what happens when compiler is picking a method for you. It is described in JLS 5 ( &lt;a href="https://docs.oracle.com/javase/specs/jls/se24/html/jls-5.html" rel="noopener noreferrer"&gt;https://docs.oracle.com/javase/specs/jls/se24/html/jls-5.html&lt;/a&gt; ): Conversions and Contexts and §15.12 ( &lt;a href="https://docs.oracle.com/javase/specs/jls/se24/html/jls-15.html#jls-15.12" rel="noopener noreferrer"&gt;https://docs.oracle.com/javase/specs/jls/se24/html/jls-15.html#jls-15.12&lt;/a&gt; ): Method Invocation Expressions. But here is the simplified set of rules, if we take inheritance and generics out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Determine Type to Search.&lt;/strong&gt; Figure out the name of the method to be invoked and which type to search for definitions of methods of that name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Determine Method Signature.&lt;/strong&gt; Using the name of the method and the argument expressions, locate methods that are both accessible and applicable, that is, declarations that can be correctly invoked on the given arguments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Identify Potentially Applicable Methods.&lt;/strong&gt; Keep only methods whose parameter lists could match the arguments, excluding obviously impossible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Identify Matching Arity Methods Applicable by Loose Invocation.&lt;/strong&gt; Try to match without using varargs. For each candidate, check if every argument can be converted to the corresponding parameter using method-invocation conversions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Identify Methods Applicable by Variable Arity Invocation.&lt;/strong&gt; If no fixed-arity method worked, try varargs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choosing the Most Specific Method.&lt;/strong&gt; If multiple applicable overloads remain, pick the most specific:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exact match &amp;gt; widening primitive &amp;gt; boxing/unboxing &amp;gt; reference upcast &amp;gt; varargs.
Let’s have a small recap there:

&lt;ol&gt;
&lt;li&gt;Widening primitive - implicit conversion of primitive types, for example int to long, or char to double. ( &lt;a href="https://docs.oracle.com/javase/specs/jls/se24/html/jls-5.html#jls-5.1.2" rel="noopener noreferrer"&gt;https://docs.oracle.com/javase/specs/jls/se24/html/jls-5.html#jls-5.1.2&lt;/a&gt; )&lt;/li&gt;
&lt;li&gt;Boxing/Unboxing - conversions of primitive types to a corresponding reference type, for example from int to Integer or char to Character. ( &lt;a href="https://docs.oracle.com/javase/specs/jls/se24/html/jls-5.html#jls-5.1.7" rel="noopener noreferrer"&gt;https://docs.oracle.com/javase/specs/jls/se24/html/jls-5.html#jls-5.1.7&lt;/a&gt; )&lt;/li&gt;
&lt;li&gt;Reference upcast - conversion of a Child type to the Parent type. Integer to Number or Integer to Object. ( &lt;a href="https://docs.oracle.com/javase/specs/jls/se24/html/jls-5.html#jls-5.1.5" rel="noopener noreferrer"&gt;https://docs.oracle.com/javase/specs/jls/se24/html/jls-5.html#jls-5.1.5&lt;/a&gt; )&lt;/li&gt;
&lt;li&gt;Varargs - (variable arity parameters) let a method accept zero or more arguments of the same type. At compile time, the arguments are packaged into an array and passed to the method. ( &lt;a href="https://docs.oracle.com/javase/specs/jls/se24/html/jls-8.html#jls-8.4.1" rel="noopener noreferrer"&gt;https://docs.oracle.com/javase/specs/jls/se24/html/jls-8.html#jls-8.4.1&lt;/a&gt; )&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Among reference types, the subtype parameter wins (e.g., anything &amp;gt; Object, Integer &amp;gt; Number, etc.)&lt;/li&gt;
&lt;li&gt;For competing varargs, compare their element types with the same priorities&lt;/li&gt;
&lt;li&gt;If no single winner exists → ambiguous method call error.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Is the Chosen Method Appropriate?&lt;/strong&gt; Correct receiver kind (static vs instance), still accessible, and any required unchecked conversions/generic warnings are accounted for. If this fails, it’s a compile-time error.&lt;/p&gt;
&lt;h3&gt;
  
  
  Lets look at some examples:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Example 1.&lt;/strong&gt; At this point let’s look at the puzzle from the beginning of this article.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Example1 {
    public static class Helper {
        private void m(double num)      { System.out.println("m(double)"); }
        public  void m(char... chars)   { System.out.println("m(char...)"); }
        public  void m(Comparable c) { System.out.println("m(Comparable)"); }
        public  void m(Object obj)      { System.out.println("m(Object)"); }
    }

    public static void main(String... args) {
        Helper h = new Helper();
        h.m('a');
    }
}

import Example.Helper;
public class Example2 {
    public static void main(String... args) {
        Helper h = new Helper();
        h.m('a');
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the main method of Example1:&lt;/p&gt;

&lt;p&gt;Private methods of inner class are accessible in the outer class, so all 4 methods could be applied&lt;/p&gt;

&lt;p&gt;'a' could be converted to double through primitive widening and to Character through boxing. But primitive widening beats boxing.&lt;/p&gt;

&lt;p&gt;Since there is fixed arity method available varargs are not looked into. Therefore m(double) is called&lt;/p&gt;

&lt;p&gt;In the main method of Example2:&lt;/p&gt;

&lt;p&gt;Private method is not accessible, so it is not one of the candidates&lt;/p&gt;

&lt;p&gt;'a' could be converted to Character. Character reference could be upcasted to Comparable or to Object. Comparable is more specific&lt;/p&gt;

&lt;p&gt;Varargs are not looked into. Therefore m(Comparable) is called.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 2&lt;/strong&gt;. Let’s look into another case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Example2 {
    static void m(Double a) { }
    static  void m(int...a) {}

    public static void main(String... arg) {
        m(Integer.valueOf(1));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Integer.valueOf(1) is an Integer, so it cannot be converted to Double. Therefore m(int...) is the only one method available.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Example2 {
    static void m(double a) { }
    static  void m(int...a) {}

    public static void main(String... arg) {
        m(Integer.valueOf(1));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, Integer is unboxed to int primitive, that widens to double, so m(double) is picked int this example. A fun note, in this example I could have replaced m(Integer.valueOf(1)) with m(Character.valueOf('a')) and get the same result in both cases. Note how the second class went to Unboxing and then to widening ( Integer - &amp;gt; int -&amp;gt; double ), but Unboxing -&amp;gt; widening -&amp;gt; Boxing is not happening.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 3&lt;/strong&gt;. Lets move to multiple arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Example3 {
    static void m(Object a, Object b) { }
    static  void m(int...a) {}

    public static void main(String... arg) {
        m(1,1);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;m(1,1) in this case going to execute m(Object, Object). Note that m(), m(1), m(1,1,1), though, will all call m(int...)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 4.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Example4 {
    static void m(float a, long b) { }
    static  void m(int a, Character b) {}

    public static void main(String... arg) {
        m(1,'a');
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Obviously, m(float, long) is going to be executed here. (widening beats Boxing)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 5.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Example5 {
    static void m(Serializable a, String...c) { }
    static  void m(String...c) { }

    public static void main(String... arg) {
        m();
        m("a");
        m("a","b");
        m("a","b", "c");
        m('a');
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All calls except the last one are going to m(String...). Both methods declared go into a varargs category, and m(String...) is a more specific on the first 4 calls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 6.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;public class Example6 {&lt;br&gt;
    static void m(int a, float b, double c) { }&lt;br&gt;
    static void m(int a, float b, Integer c) { }&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static void main(String... arg) {
    m(1,2,3);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;m(int, float, double). In this example the method with 3 primitives wins (widening vs Boxing). But if I change the last argument to be a vararg - not anymore.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Example6 {
    static void m(int a, float b, double... c) { }
    static void m(int a, float b, Integer c) { }

    public static void main(String... arg) {
        m(1,2,3);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we saw, overloading is resolved strictly at compile time. The compiler goes through the available methods, applies conversions if needed, and picks the most specific one it can find. Once the decision is made, it does not change at runtime. This explains why adding a new overload or slightly changing a signature may change which method is called without producing any errors or warnings.&lt;/p&gt;

&lt;p&gt;Even in the simple case of a single type, the rules can lead to non-obvious results. Private visibility, static versus instance methods, varargs, boxing and unboxing, widening, and reference conversions all play a role in which overload is chosen.&lt;/p&gt;

&lt;p&gt;This part only looked at concrete types in a single class, interface, or enum. In the next part we will move on to generics, where type inference, erasure, and unchecked conversions make the resolution rules even more subtle and much harder to predict.&lt;/p&gt;

</description>
      <category>java</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
