I'm a big fan of Java. It is nice to see the fan base for Java is still far above .Net (and outpacing .Net in growth); see http://www.tiobe.com/tpci.htm
One area I've found .Net outshines Java is the implementation of Generics. Java's Generics exist in source-code only. The Java compiler "Erases" the generic information after the compiler determines that everything is correct. This approach outshines C++ templates, but it creates a lot of other issues. See the Java Generics FAQ which lists pages of special rules and edge cases caused by Erasers. Java Generics is more complex than Java the language!
.Net Generics on the other hand are implemented at runtime. So the Generic type information is not lost and is available through reflection. When the .Net CLR encounters the usage of a Generic type for the first time, it instantiates a non-Generic type based on the type parameters. The Generic type is never executed, it is just used by the CLR to create concrete instances. So Array<string> and Array<float> are two seperate classes at runtime. Java would have just used Array. So .Net memory grows a little more (but not like the bloat of templates in C++), which is a great trade off since it avoids the problems and complexities of Erasures.