Java programs are multithreaded, with each thread allocated a separate stack. They therefore do not have a single stack that grows towards the heap, so Java programs themselves can not cause this collision.
If the stacks of the threads are stored at one end of memory, creation of additional threads could cause the total stack space to grow towards the heap.
The JVM itself will have some stack space, which probably does grow towards the heap space, and so in theory could collide. The JVM should be written to avoid deep (and especially infinite) recursion. If it's stack could grow towards the heap (rather than being finite), it should detect that problem and signal it to the program using a VirtualMachineError.
However, JVMs do not allow the heap to grow in an uncontrolled manner, but are configured with a maximum heap space , and have complete control over creation of new stacks for threads. It can therefore completely prevent collision. The only potential collision would be if creation of a new thread stack was impossible. The JVM would signal that condition using a VirtualMachineError (probably an OutOfMemoryError).