Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>This is the best possible code of second approach. It compiles without any warnings.</p> <pre><code>import static org.junit.Assert.fail; import org.junit.Test; import org.junit.internal.runners.JUnit4ClassRunner; import org.junit.runner.RunWith; @RunWith(JUnit4ClassRunner.class) public class TestGenerics { public static interface Copyable&lt;T&gt; { public void copy(T t); } public static class A&lt;T extends A&lt;T&gt;&gt; implements Copyable&lt;T&gt; { private String a = "--A--"; public void copy(T t) { System.out.println(t.a); } @SuppressWarnings("unchecked") public static Copyable&lt;Object&gt; getInstance() { return new A(); } } public static class B&lt;T extends B&lt;T&gt;&gt; extends A&lt;T&gt; { private String b = "--B--"; public void copy(T t) { super.copy(t); System.out.println(t.b); } @SuppressWarnings("unchecked") public static Copyable&lt;Object&gt; getInstance() { return new B(); } } @Test public void testCopy() { Copyable&lt;Object&gt; b1 = B.getInstance(); Copyable&lt;Object&gt; b2 = B.getInstance(); Copyable&lt;Object&gt; a = A.getInstance(); b1.copy(b2); // this works as intended try { b1.copy(a); // this throws ClassCastException fail(); } catch (ClassCastException cce) { } } } </code></pre> <p>And also i figured out all that happens in this program with help of reflection:</p> <pre><code> for (Method method : A.class.getMethods()) { if (method.getName().equals("copy")) { System.out.println(method.toString()); } } for (Method method : B.class.getMethods()) { if (method.getName().equals("copy")) { System.out.println(method.toString()); } } </code></pre> <p>Here is the output:</p> <pre><code>public void com.sbp.core.TestGenerics$A.copy(com.sbp.core.TestGenerics$A) public void com.sbp.core.TestGenerics$A.copy(java.lang.Object) public void com.sbp.core.TestGenerics$B.copy(com.sbp.core.TestGenerics$B) public void com.sbp.core.TestGenerics$B.copy(com.sbp.core.TestGenerics$A) public void com.sbp.core.TestGenerics$A.copy(java.lang.Object) </code></pre> <p>It means that:</p> <ol> <li><p>The copy(...) methods in A and B make compiler generate "bridges" - 2 different methods for each, one with reifed argument type from ancestor (reified T from Copyable becomes Object, reified "T extends A" from A becomes A) and that is why it's override and not overload, and the other one with reified argument type for defining class. First method (with autogenerated body) <em>downcasts</em> its argument to call the second (they call it a bridge). Because of this downcasting we get ClassCastException in runtime if we call b1.copy(a).</p></li> <li><p>It looks like direct type casting is cleaner and better tool for my problem and generics are better used in their direct purpose - to enforce compile time type checking.</p></li> </ol>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload