Many applications require lists of data that cannot be changed (e.g. one cannot add tothe list, remove anything from the list or change the sequence of the list). Forexample, one can provide a list of customers, without the ability to change the list inany way. Effectively one can only observe the data in these lists.In this lab, you must enhance the mutable ListADT classes and interfaces with theability for such a list to return an immutable counterpart of itself. This immutable listcontains the same data in the same sequence as the original list, but it cannot bechanged. Conversely you must implement the immutable list such that it can return amutable counterpart of itself. Again, this mutable list contains the same data in thesame sequence as the original list, but it can be mutated.It is important to note that immutable lists are different from unmodifiable lists (Javahas unmodifiable lists, but not immutable). The difference is that while anunmodifiable list cannot be modified directly, it can be modified by mutating theunderlying mutable list. That is, unmodifiable lists merely create a wrapper around aregular list. In contrast, it is not possible to mutate an immutable list.The ListADT classes and interfaces have been provided to you. You may rely ontheir correctness (i.e. the implementation works correctly and has been tested, you donot need to test it).You are free to design your own classes and interfaces for immutable lists. Howeveryour work must obey the following constraints:
1. Your mutable list should have an operation to return an immutablecounterpart of itself.2. Your immutable list should have an operation to return a mutablecounterpart of itself.3. Your immutable list should offer all the non-mutating operations that yourmutable list offers.4. It should not be possible to mutate an immutable list through the mutablecounterpart it returns (see note about immutable vs unmodifiable listsabove).5. A user of ListADT<T> and ListADTImpl<T> should be able to usethem exactly as they are. That is, there should be no public-facing changesto them.6. Because this is a generic implementation, immutability extends only to thelist structure and not to the data contained in the list. It may be possible tomutate the data in the list (because there is no easy way to guarantee that thiswill not happen without assuming something about the data).7. Your mutable lists must use the ListADT way of implementation. That is,you are not allowed to start implementing a list from scratch just to supportthis enhanced functionality.8. Your guarantee of immutability should be stronger than “document clearlythat some methods should not be called”.9. The map function, which is part of the ListADT implementation, shouldreturn a list of the appropriate kind. That is, the map of an immutable listshould return an immutable list, while that of a mutable list should return amutable list.10.The enhancement (and this entire lab) should be on top of the nodes. That is,you should not modify the nodes at all.
Write tests that thoroughly test your implementations. As the design is left up to you,you should have at least one test that clearly demonstrates (through code andcomments) how your classes can be used. You should expect a client to look at testslike this as examples of how to use your design and code.