the type of s1 is SuperClass. So you can only call methods which are in SuperClass from s1. Compiler doesn't know that s1 actually points to a SubClass object. What it knows that s1's type is SuperClass...
At line 1, by using the narrowing conversion you are telling the compiler that the method is being invoked on the narrowing cast class i.e SubClass. Since funny() is present in SubClass hence no compile time error.
Had s1 not been poiniting to an instance of SubClass then it would have thrown ClassCastException at runtime.
At line 2, you are telling the compiler that s1 will be pointing to a SubClass instance which the compiler allows since it knows that SubClass is the child of s1 reference variable type i.e. SuperClass It in no ways is changing the reference type of s1 which remains SuperClass. Again, had s1 not been poiniting to an instance of SubClass then it would have thrown ClassCastException at runtime.
The line following line 2, is giving a compiler error because the compiler checks the type of the reference variable s2 which is SuperClass and it does not contain the method funny().