class A<T, S extends CharSequence> { T field1; S field2; A<String, String> a1 = new A<String, String>(); A<String, String> a2 = new A<String, String>(); A<Integer, String> a3 = new A<Integer, String>(); void foo(String s) {} void foo(Integer i){} void bar() { foo(a1.field1); foo(a3.field1); } S[] arrayErasure; class B<U> extends A<C<String>, String> { void fun() { field1 = null; } } class C<V> { S innerClassField; } S method1(S param) { return param; } <P> P method2(P plop) { } <P> P method3() { Object myObject = <String>method3(); } <Q> C<Q> method4() { Object myObject = <String>method4(); } class D<V> { V field; } D<D<T>> ddt; void ddt_method() { Object obj = a1.ddt.field.field; } class E { void method_of_e(){} } void e_method() { A.<E>methodStatic().method_of_e(); } static <T> T methodStatic(){}; void unknownSymbol() { Foo<String> foo; } } public class MyClass implements MyInterface<MyClass.B<Object>> { public static class B<T> extends C<T> { } } interface MyInterface<T> { } class C<T> { } class TypeParameterUsedInMethods<T, U> { Function<? super T, ? extends U> getter; void foo(T val, U wantedValue) { getter.apply(val); // these 2 calls do not compile but methods are resolved, as argument matching is based on erasure getter.apply(new Object()); getter.apply(wantedValue); // not valid call with different erasure, not resolved getter.apply("hello"); new TypeParameterUsedInMethods<Object, Object>().getter.apply(new Object()); } static class Function<X, Y> { Y apply(X from) { return null; } } } class ExtendedTypeParam { class MyClass {} interface I {} interface J {} class ParametrizedClass<W, X extends MyClass, Y extends I, Z extends MyClass & I & J> {} }