In order to understand what's happening, you need to mentally separate the variable from the object it contains.
Initially, when you declare a variable, the variable is empty ("null"); this is an area of space that's traditionally on the "stack" and allocated at compile-time.
mylist -> mylist contains null
Next, when you create a new object, the runtime provides an empty space to store data:
new List<Integer>(); // Creates an object at address 123456
Then, when the value is assigned, the variable's setter is called:
mylist.set(Object<123456>) -> mylist contains Object<123456>
By default, it just assigns the value to that reference, but in this case, you've overridden it to call your custom method (set).
After that, when you want to use the object in the variable, it has to call "get", which returns the object:
(mylist.get() returns Object<123456>).add(Object<654321>)
This is why getters are called when you try to call a function on a variable.
Those things we call "variables" are allocated on the "stack" and do not consume memory. All variables have a get and set function, which can be overridden. The stack is of a limited, undocumented size. The stack also does other stuff, like remember which function to return to when the current function ends.
The objects that we create through "new" (either explicitly or implicitly) are stored in the "heap." This is the area that is limited to 6/12MB. When we have a non-null value in a variable, it is a reference to somewhere within this "heap" area. The underlying architecture is actually more complicated than that, but that's all you really to know about why getters and setters work they way they do.
You can't override any function in the standard library. They're all "final", meaning that they are read-only and cannot be redefined or extended.
You also don't ordinarily need to write an iterator for the List and Set objects, because they have a built-in one:
Iterator<Integer> iter = mylist.iterator();
Integer currentValue = iter.next();