Anyway, my question is this, why can Java app's be decompiled ?
Any app, in any language, can be decompiled. That should be obvious to anyone with a smattering of programming experience in a compiled programming language.
A compiler takes bytes and creates a different set of bytes that represents the same set of instructions. A decompiler takes bytes and creates a different set of bytes that represents the same set of instructions. The difference is merely in what those bytes are. A compiler takes bytes that are (relatively) human readable and creates bytes that are (relatively) machine readable. A decompiler does the reverse.
How well a given decompiler can do its job, though, depends on the programming language and the implementation of the decompiler itself.
In the case of a language like C, the compiler generates machine instructions for a CPU. Those can be readily decompiled into assembly language, as assembler instructions map fairly closely 1:1 to machine instructions. A sufficiently sophisticated decompiler can emit C as output, though probably not C that would be natural to write. More importantly, the decompiled output will largely use decompiler-generated names for functions and variables, unless the compiled C code has debug symbols, in which case the decompiler might be able to use those.
A language like Java is not significantly different in concept. While Java or Dalvik bytecode is for a VM rather than a CPU, the basic approach is the same. Obfuscation helps to ensure that the minimum number of human-readable symbols exist in the resulting bytecode, to reduce the legibility of any decompiled results. Also, the mapping of VM bytecode to language statements tends to be far closer than the mapping of machine code to C statements, which makes it easier to write a decompiler that gives you closer to Java syntax back (e.g., smali/baksmali).
It is the degree of difficulty in interpreting decompiled machine code that results in recommendations to move license management logic into native code via the NDK, for example. However, that is not to say that the results of a C compiler cannot be decompiled at all.