Lecture 28: Generic Extended Visitors and Data Packets

Concepts

  • Dr. Wong has redesigned the Java Resources page on his website so that it is easier to navigate. Dr. Wong finds it unlikely that he will be able to discuss all of the minute but important details of some of the topics that weĺl be doing soon, and therefore encourages everybody to visit the Java Resources page for in depth information.
  • What is the “transient” modifier that is applied to the taskView instance variable inside of tasks? During serialization, an objects fields will be encoded into some stream of bytes, which will then be sent across the network. On the other end, Java will instantiate a new class of the same type, then insert all of the values that it finds in the serialized stream.
    • Well, the taskView field is a reference to some other object; at some level just a number that identifies the other object. What would that number mean if we serialized it and sent it somewhere else? It would be meaningless outside the context in which it was created. /* This seems somewhat off-topic to me, because, as discussed below, this won’t happen. Java will attempt to serialize the entire referenced object. */ Transient indicates that the serializer should ignore the so-marked field.
    • Note that normally, during serialization, the serializer will follow references (If Object A references Object B, and A is serialized, B will also be serialized). Be careful, therefore, not to serialize anonymous inner classes that close over other variables, as you can easily end up serializing and transmitting your entire system.
    • Don’t confuse volatile and transient! volatile indicates to the Java Compiler that the value of some variable is not safe to cache (because the variable changes in parallel ways (?)) and that it shouldn’t try to optimize any code that uses the volatile variable.
    • You can override (some interface…).readObject(…) (Something in Pi2.java…) if you need to do some sort of re-initialization whenever your Object is deserialized. You can call stream.defaultReadObject() to perform the normal deserialization, then take the opportunity to initialize your transient fields to some well-defined value.

Now we’re going to talk about generic list frameworks.

  • Let’s take a generic list: IList<E>. What does it mean to run an algorithm on it?
  • public abstract <R, P> R execute(IListAlgo<? super E, R, P> algo, P …)
  • We declare that execute will return a type R: whatever the algorithm returns.
  • We make a generic parameter P for whatever parameters the algorithm takes.
  • ? super E: any algorithm that works on a supertype of E can work on this list of E‘s.
  • Thus, we have a method, with generic parameters R and P (inside of an IList with generic parameter E), which accepts an algorithm that operates on a supertype of E, accepts parameters of type P, and returns a type R, and some number of parameters, each of type P.
  • public abstract R emptyCase(IMTList<? extends E> host, P … inp);
  • Declares a case in a visitor (the algorithm), that operates on any subtype of E.

Quotes

  • “If you want a glass of water, there’s two components, right? The glass, and then the water! You only transmit the water from one glass to another; the glass is like the class, and the water is like the data.”
  • “Never trust another programmer, especially not the one in the mirror.”
  • “This is like the most intensely generic statement I’ve ever seen!” — Caleb
    • “This is the easy one.” — Dr. Wong

Resources