It's not possible to do that in Java, though it would work in C#. Retaining references really is not "fighting against automatic reference counting", it's the opposite: the reference clearly and unambiguously defines the lifetime of the object, including deallocation. This is by design and ARC can still be used for any shared references to the object. Forcing GC on the other hand, would be fighting against it because you're circumventing its usual operation.
I think technically you could achieve this by having multiple heaps, kind of like custom allocators in other languages.
If Java had a placement syntax like
new (HeapReference) SomeClass(); => allocate in custom Heap
Then you could just turn off GC for that heap, and then blow the whole thing away when it got full. Or, you could have a more fine grained API to allow GC on these custom heaps. Perhaps you could even allow copying objects back to the main heap. You'd have to ban cross heap references or have a smart API that lets users pin an object in the main heap while it is known to be referenced by an object in custom heap.
Most of the time in client applications, you only care about GC pauses on the main UI rendering thread, but GC pauses in other threads are less obvious because there's no jank, just that latency may go up for some operations.
You could have a kind of best of both worlds with languages that support non-GC allocation for your UI thread, but GC everywhere else.
It wouldn't work reliably in C# either. Both platforms allow you to inform the GC that now would be a good time to collect, but in both systems the GC can ignore your advice. C# has structs which will try to allocate on the stack, but that is potentially a big (or impossible) refactoring on your program (unless you plan ahead).