## Welcome

• if you are seeing these notes, you can already see all the course info on the course page
• NO QUESTIONS ARE DUMB!!!!!
• NEVER BE AFRAID TO ASK THEM!!!!
• DON’T STRUGGLE IN SILENCE ON YOUR PROJECTS/LABS!!!!!!!
• what is a university setting good for today?
• I trust you!
• I try to be accommodating re: extensions
• I don’t think most cheaters are being lazy

## Course goals

• To expand your problem-solving toolkit with important data structures
• These are ways of representing the data that your programs deal with
• To understand when/why to use each kind
• Be able to objectively evaluate them and be able to justify your decisions
• To deepen your programming ability
• New ways of expressing more complex ideas

## Java recap

### OOP

• Everything’s an object… even if it doesn’t make sense for it to be
• hey they were still figuring this stuff out in the early 90s
• Classes define the “archetype” for objects
• specify what data and methods they have
• that is, what they know and what they do
• When you use new Classname(), that instantiates (makes a new instance of) that class
• you can make as many instances as you want
• you can make constructors, special methods which are called as part of the new
• When you write inst.method(), that is a method call
• it runs the code of that method, with the thing to the left of the . as this
• method calls are really what make OOP… OOP
• everything else is just icing on top

### References

• Java’s instances are always accessed by reference
• like the keys to a car: you can carry and pass around the keys easily
• variables of type Classname can be null or refer to an instance
• When you write a = b, it does not make a copy of the object, it makes a copy of the reference
• multiple different variables can refer to the same instance - this is aliasing
• this applies to function arguments too:
• if you have int f(Classname a) and do f(b), it is like a = b

### Getters and Setters

• Data fields should usually be private and then accessed with getters and setters
• this feels like a weird arbitrary rule and a way to triple the amount of code you write
• in some cases, it is.
• What you might not have learned is that it is almost always better to access a variable/field in exactly one place than all over the place
• in this way, you can change how that variable is accessed by only changing one piece of code
• this is a form of abstraction: hiding the implementation of details
• Abstraction is a big part of data structure design
• so get used to it.

### Static class members

• they have nothing to do with classes and instances
• they just happen to come inside classes cause… uh……………………..
• cause Java.
• these are really “outside” of Java’s OOP framework
• they are commonly known in other languages as global variables and functions
• static fields are global variables
• there is exactly one copy of it throughout your program
• mutable (non-final) static fields are not usually a great practice
• but private ones, accessed through getters/setters can have their uses
• static methods are functions
• they have no this; all they can see are their arguments and other statics
• main is the one you’re most familiar with
• you could, if you tried really hard, write an entire Java program with only static methods, but it would be very un-Java-ful
• not to mention interacting with most libraries requires using OOP

### Packages

• Level of organization above classes
• Kinda like a directory in your file system
• you know about e.g. java.io package
• How to make one
• Make a directory named packagename
• Put your .java files in it, and put package packagename; at the top of each
• From parent dir, javac packagename/Whatever.java
• How to access one
• From parent dir, java packagename.Whatever
• to import, import packagename.Whatever or import packagename.* for all

## Making more complex objects

### Composition

• Stick together multiple simpler objects to build up a more complex one
• Every class you’ve written is composed (has fields)
• But of course you can have fields which are, themselves, objects
• Be careful!
• Try not to make “kitchen sink classes” out of simpler ones
• it’s easy to use a 2x4 lego piece in many situations; it’s much harder to use a front-of-a-boat piece

• you want to aim for composability: classes which can be put together with other objects in various flexible ways
• Existing classes don’t always fit your needs
• Poor/inconsistent names
• Don’t want all methods to be available
• Want to add better error reporting
• An adapter class is one which “wraps” an existing class to change or add functionality

### Subtyping

• Java has a few mechanisms for subtyping: making a new type which is a more specialized version of an existing type
• there are two types involved: the original type, called the supertype, and the new type being created, called the subtype
• the supertype is more general than the subtype
• the subtype “is a” supertype – anything that expects a supertype, you can use a subtype of it instead
• Subtyping creates a hierarchical relationship between types
• in Java, Object is the root of the class hierarchy
• all classes derive ultimately from Object - if you don’t “extend” another class, it implicitly extends Object
• all in all, you end up with a big tree
• but interfaces let you make other trees - we’ll get to that

### Class Inheritance (extends)

• You can make a class extend another class
• Essentially, you copy and paste the contents of the superclass into the subclass
• Then you can add or override functionality
• the subclass is a subtype of the superclass
• But class inheritance is not flexible
• a type hierarchy is only sometimes the right model of the data/behavior of a program
• using a hierarchy when you instead need e.g. “categories” of things can make your code harder to write and less flexible
• Class inheritance can also create “kitchen-sink base classes”
• as a program grows in complexity, it is tempting to shove more and more features into the base classes to reduce the amount of copying-and-pasting needed
• until you end up with something like JFrame - look at those “methods inherited from” sections!!!
• Unfortunately…
• Java has no mechanism for automatic code reuse besides class inheritance
• So this kind of kitchen-sink base class arises out of need
• Class inheritance also adds complexities to other class mechanisms
• constructors are “chained” up the class inheritance tree
• each subclass calls the superclass constructor at the beginning of its constructors
• subclasses can only access public and protected superclass members, even though they do inherit the private fields
• subclasses can override superclass methods… unless the superclass marked it as final!
• Finally there are abstract classes
• they cannot be instantiated - they must be extended
• they have abstract methods which have no code; the subclasses must implement them
• abstract classes tend to be used as “dumping grounds” for common code
• they can often be better expressed through interfaces and adapter classes

### Virtual methods (which some instructors didn’t teach in 401???)

• Why do we care about extending classes with new subclasses?
• So that the subclasses can have specialized behavior!
• One way we can have specialized behavior is with a virtual method
• This is a method defined in the base class, which the subclasses then re-implement
• If I said “go home”, you would all go home in different ways… but I don’t need to know how/where you go home, you just know how to do it.
• Very common virtual method: String toString()
• Defined in Object; this is what Java calls when you e.g. concatenate an object with a string or print it out on the console (System.out.println("My object: " + someObject))
• Object gives you a default implementation, so if you print out a SomeClass, it’ll show something like SomeClass@8004FA80
• But you can define your own String toString() in your classes, and it’ll use your implementation instead.
• Consider a Vehicle class, where we want to have an accelerate() method
• We could have a Car class, a Plane class, a Bicycle class which all extend Vehicle
• And each one could implement accelerate() differently
• So if we had an array of Vehicle, and called accelerate() on each one…
• How does it know which implementation of accelerate() to call?
• This is the magic of virtual methods: it decides which one to call while the program is running, by looking at the underlying type of the object.
• If I have Vehicle v = new Car();, and then call v.accelerate()
• It looks at the REAL type of v at runtime, and sees that it’s really a Car
• Then it calls the Car.accelerate() method with v as this.
• How does this happen?
• Every class has an associated virtual method table (“vtable” or “vtbl” for short).
• Every instance has a hidden field which is a reference to its class’s vtable.
• When you write a method call like v.accelerate()
• It gets v’s vtable, then gets the accelerate() method from there, and calls that.
• This way, it doesn’t matter what type v really is: it will always get the “right” version of accelerate() for it!
• There is one vtable for each class, and all instances of that class refer to that vtable.