Note that the zero-initialization done by the OS as a security feature is usually only done the first time memory is allocated. By that I mean any segment in the heap, stack, and data sections. The stack and data sections are typically of fixed size, and are initialized when the application is loaded into memory.
The data segment (containing static/global data and code) typically doesn't get "re-used", although that may not be the case if you dynamically load code at runtime.
The memory in the stack segment gets re-used all the time. Local variables, function stack frames, etc.. are all being constantly used and re-used and are not initialized every time - just when the application is first loaded.
However, when the application makes requests for heap memory, the memory manager will typically zero-initialize segments of memory before granting the request, but only for new segments. If you make a request for heap memory, and there is free space in a segment that was already initialized, the initialization isn't done a second time. Therefor, there is no guarantee that if that particular segment of memory is re-used by your application, it will get zero-initialized again.
So, for example, if you allocate a Foo on the heap, assign its field a value, delete the Foo instance, and then create a new Foo on the heap, there is a chance that the new Foo will be allocated in the same exact memory location as the old Foo, and so its field will initially have the same value as the old Foo's field.
If you think about it, this makes sense, because the OS is only initializing the data to prevent one application from accessing the data from another application. There is less risk in allowing an application access to its own data, so for performance reasons the initialization isn't done every time - just the first time a particular segment of memory is made available for use by the application (in any segment).
Sometimes when you run an application in debug mode, however, some debug mode runtimes initialize stack and heap data at every allocation (soo your Foo field will always be initialized). However, different debug runtimes initialize the data to different values. Some zero initialize, and some initialize to a "marker" value.
The point is - never ever use uninitialized values anywhere in your code. There is absolutely no guarantee that they will be zero initialized. Also, be sure to read the previously linked article regarding parens and default vs value initialization as this affects the definition of an "uninitialized" value.