Head First Java, 2nd Edition

Chapter 1 – Breaking the Surface

  • Java is alluring because of the “write-once, run anywhere” principle
  • Java works by compiling source code into bytecode, which the Java Virtual Machine (JVM) runs
  • Java 1.02 (applets) -> Java 1.1 (better GUI code) -> Java 2 (includes MicroEdition J2ME, Standard Edition J2SE, and Enterprise Edition J2EE) -> Java 5 (more power and easier to develop with) -> Java 6 (more features to J2SE and J2EE) -> Java 7 (improvements like using String in switch statement, multiple exception catching) -> Java 8 (forEach method in Iterable interface, functional interfaces and lambda expressions)

Chapter 2 – Classes and Objects

  • The benefits of object-oriented programming include flexibility and extensibility
  • When classes share a common functionality, the features can be put into a superclass and then be inherited by the subclasses (Shape can be your superclass, and then Square, Circle, and Triangle are all subclasses of Shape)
  • Subclasses can override methods in the superclass, defining a unique behavior that is specific to that particular class
  • When designing classes, think of what the object should know (instance variables) and what the object should do (methods)
  • A class is not an object, but is used to construct them; a class is a blueprint for an object

Chapter 3 – Primitives and References

  • Variables must have a type, and can be primitive or object reference
  • Local variables are declared within a method
  • Arguments are values sent to a method and return types are values sent back to the caller
  • Primitive types are byte, short, int, long, float, double, boolean, and char
  • There is no such thing as an object variable, only an object reference variable; which doesn’t hold the object itself, but rather something like a pointer or address that represents a way to access the object
  • When writing “Dog myDog = new Dog();” the JVM allocates space for a reference variable of type Dog, creating an object on the heap, and assigns the Dog object to the reference variable
  • “Book book2 = book1;” declares a new Book reference variable, but not a new object, which assigns the value of the variable book2 to the value of variable book1 (assuming objects book1 and book2 already exist)
  • When an object has no references, it is eligible for garbage collection
  • Arrays are always objects

Chapter 4 – Methods Use Instance Variables

  • Objects have states (instance variables) and behaviors (methods)
  • A method uses parameters and a caller passes arguments
  • Java is pass-by-value, that means pass-by-copy
  • A method doesn’t change the original variable that was passed in, rather the method manipulates a copy of the variable
  • Encapsulation is where data is secured in classes, which is done by declaring instance variables as private, and then using getter and setter methods to access them
  • Instance variables always get a default value if one is not explicitly assigned to them: 0, false, or null
  • Instance variables are declared inside a class but not within a method, while local variables are declared within a method
  • To compare two primitives (check for same value) and two references (check for same object), use the “==” operator

Chapter 5 – Writing a Program

  • A for loop initializes, does a boolean test, and then iterates
  • A while loop is good for when you don’t know how many times to loop but have to keep going until a condition is met
  • “int x = 0;       int z = ++x” results in x and z being 1
  • “int x = 0;       int z = x++” results in x being 1 and z being 0, because z gets assigned the value of x and then x is incremented
  • An enhanced for loop can be written as “for (String name : nameArray)” to iterate through all items in the nameArray collection

Chapter 6 – Get to Know the Java API

  • The Java library is known as the Java API
  • To use a Java API you need to know which package the class is in and then import it
  • Boolean operators are && (AND), || (OR), and != (not equals)
  • && and || are short circuit operators, meaning once it’s determined if the left side of a && is false, the JVM won’t bother checking the right side, and in a similar fashion if with a || comparison the left hand side is true, then the JVM won’t bother checking the right side because the condition was satisfied already
  • The & and | operators are non short circuit operators, meaning they force the JVM to check both sides of the expression

Chapter 7 – Inheritance and Polymorphism

  • When you use inheritance you put common code in a class (superclass) and then have subclasses extend the functionality (using the extends keyword) so that the subclasses can inherit methods of the superclass
  • The subclass inherits members of the superclass, including instance variables and methods
  • To design a superclass, look for what all objects have in common and how they are related
  • Use the “IS-A” relationship to check if one item should extend another, Triangle IS-A Shape, thus verifying that Triangle can be a subclass of Shape
  • Use the “HAS-A” relationship to organize related classes, since Bathroom HAS-A Tub, then you should create a Bathroom class with a Tub instance variable and a separate Tub class, keep in mind that Bathroom DOES NOT extend the Tub class
  • To call the methods of a superclass from a subclass, use the “super” keyword
  • public members are inherited, but private members are not inherited
  • Inheritance allows you to avoid duplicate code by defining a common protocol for a group of classes
  • With polymorphism, the reference and the object can be different, such as Animal myDog = new Dog(); which is a reference variable of type Animal but the object created is a Dog
  • Polymorphism allows the reference type to be a superclass of the object type, since Animal is the superclass of Dog, the above example works
  • Methods can define the superclass as a parameter, and then any subclass can be passed in as an argument
  • Polymorphism lets you write code that doesn’t have to change when a new subclass is introduced
  • When overriding methods of a superclass from a subclass, the arguments must be the same and the return types must be compatible
  • When overloading methods, you can make multiple versions of a method with different argument lists and the compiler will know which method to call based on how you call the method
  • Overloading allows the return type to be different, but you can’t only change the return type, the method parameters must be changed

Chapter 8 – Interfaces and Abstract Classes

  • You can use an abstract class to prevent a class from being instantiated, so that a new object of that type cannot be created
  • Concrete classes are specific enough to be instantiated
  • The main value of an abstract class is to be extended
  • An abstract method means that the method must be overridden, and it has no body so that subclasses can define their own unique implementation
  • An abstract method must be defined in an abstract class
  • Every class in Java extends the Object class
  • The Object class has the following methods: equals (compare objects), getClass (return class of object), hashcode (prints unique object hash, a sort of id that every object has), and toString (prints a String pertaining to the object’s memory)
  • You can cast the class type onto an Object so that you can use the methods of that class, you can ensure the correct class by using the instanceof operator
  • The way aninterfaceworks in Java is like a 100% pure abstract class, you can think of all the methods in an interface to be abstract, meaning any subclass thatimplementsthe interface has to implement all methods defined in the interface
  • Since all interface methods are abstract, they have no body
  • A class can implement multiple interfaces, separated by commas
  • When your class doesn’t pass the IS-A test for any type, make a class that doesn’t extend anything…but when you need to make a more specific version of a class, make a subclass
  • When you want to define a template for a group of subclasses with implementation code that all subclasses can call, use an abstract class
  • When you want to define a role that other classes can play, use an interface
  • One way to design an abstract class is to have methods with some set-up code defined…then the subclasses that will extend this abstract class can use the super keyword to call that initial setup in their overridden method, and then follow up with code for their own implementation

Chapter 9 – Constructors and Garbage Collection

  • The stack is where method calls and local variables live
  • The heap is where all objects live
  • Instance variables are variables declared inside a class, but not within any method
  • Local variables are declared inside a method, including method parameters
  • When you call a method, the method lands on the top of the stack…the method at the top of the stack is the one currently running
  • All objects live on the heap, regardless whether the reference is a local or instance variable
  • When a new object has instance variables that are object references rather than primitives, Java makes space only for the reference variable, until the actual instance variable object is created
  • An object is declared (the reference variable type and name, “Dog dog”), created (“new Dog()”), and assigned (“=”)
  • A constructor is code that runs when you create a new object, which instantiates the object
  • If you don’t have a no-argument constructor, Java supplies a default one, however if you do have a constructor that has arguments, then you must make the no-argument constructor yourself
  • If you have multiple constructors (overloaded), then the argument list must differ in order and/or types of the variables
  • When a new sub-class object is created, then one object on the heap is created but it contains instance variables of the subclass and of all superclass instance variables
  • All constructors in an object’s inheritance tree must run when you create a new object
  • When a constructor runs, it calls its superclass constructor all the way up to class Object constructor, known as constructor chaining
  • The compiler always puts a call to super() in every constructor, but it has to be the first statement in your constructor if written explicitly
  • You can use the keyword this() to call a constructor from another overloaded constructor in the same class
  • “this” refers to the current object
  • A constructor can have a call to super() or this(), butnot both
  • A local variable lives only within a method, and an instance variables lives as long as the object does
  • Garbage collection automatically destroys eligible objects when your program gets low on memory
  • An object becomes eligible for garbage collection when its last live reference disappears, which is when the reference goes out of scope (a local variable’s method ends), when the reference is assigned to another object, or when explicitly set to null

Chapter 10 – Numbers and Statics

  • The Math class doesn’t have any instance variables, and because the methods are “static”, you don’t need to have an instance of Math
  • A static method means “behavior is not dependent on the instance variable, so no instance/object is required”
  • You can prevent instantiating a class by marking the constructor as private
  • Static methods can’t use non-static instance variables and non-static methods
  • A variable declared as static instance variable has the same value for all instances of the classes
  • A variable declared as final is a constant, its value cannot change
  • A final method means you can’t override the method, and a final class means you can’t extend the class

Chapter 11 – Exception Handling

  • One method can catch what another method throws, the method that throws has to declare that it might throw the exception
  • Put the throws keyword on the same line as the method declaration
  • Catch the exception by using a try-catch block
  • The compiler cares about ‘checked exceptions’, which are basically anything other than RuntimeExceptions
  • A finally block runs regardless of an exception
  • You can run exception prone code without a try-catch block by declaring that the method throws an exception

Chapter 14 – Serialization and File I/O

  • You can save an object’s state using serialization, by using the ObjectOutputStream package
  • Connection streams can represent a connection to a source or destination: files, network sockets, or the console
  • To serialize an object to a file, use FileOutputStream chained to an ObjectOutputStream
  • To serialize an object, call writeObject(Object), and to read objects use readObject()
  • The return type of readObject() is of type Object, so deserialized objects must be cast to their real type
  • An object must implement the Serializable interface to be eligible for serialization
  • Mark instance variables with the transient keyword to skip their serialization
  • Static variables are not serialized, because all objects of that type share only a single value

Chapter 15 – Networking and Threads

  • Client and server applications communicate over a Socket connection
  • A Socket represents a connection between two applications
  • A client must know the IP (or domain name) and TCP port number of the server
  • A TCP port is a 16-but unsigned number assigned to a server application, allowing for different clients to connect to the same server
  • The port numbers from 0 to 1023 are reserved for services such as HTTP, FTP, SMTP, etc.
  • Once connected, a client can get input and output streams from the socket
  • To read text data from the server, create a BufferedReader chained to an InputStreamReader
  • To write text data to the server, create a PrintWriter chained directly to the Socket’s output stream
  • Servers use a ServerSocket that waits for client requests on a particular port number
  • When a ServerSocket gets a request, it accepts the request by making a Socket connection with the client
  • Java has multi-threading built into the language, you can create a separate thread of execution with its own call stack
  • To launch a new thread make a Runnable object (the thread’s job), a thread object (the worker) that has the Runnable as an argument, and finally start the thread
  • The Runnable Interface has just a single method, run(), which goes on the bottom of the new call stack
  • A thread is in the NEW state when you have instantiated a Thread object, in the RUNNABLE state when you call the start method, and RUNNING when the JVM’s thread scheduler has selected it to be the currently running thread
  • A thread can be moved from RUNNING to BLOCKED due to: waiting for data, going to sleep, or waiting for an object’s lock
  • Thread scheduling is not guaranteed to work in a way where threads will take turns nicely, but you can influence turn-taking by putting threads to sleep periodically
  • You can have serious problems with threads if two or more threads have access to the same object on the heap, leading to data corruption
  • To make objects thread-safe, decide which methods run to completion before another thread enters the method on the same object
  • Use the keyword synchronized to modify a method declaration, to prevent two threads from entering that method
  • When a thread wants to enter a synchronized method, the thread must get the key for the object, if the key is not available (because another thread is using it) then the thread goes into a waiting mode until the key is available

Chapter 16 – Collections and Generics

  • Lists are for when sequence matters, Sets are for when uniqueness matters, and Maps are for when finding something by key matters
  • You can create generic classes, variables, and methods
  • A generic class is declared as “public class example_class<T>” , where <T> is the placeholder for the real type you use when you declare and create the class
  • A generic method is declared as “public void example_method(T data)”
  • If the type parameter was not declared in the class declaration you must do “public <T extends Animal> void example_method(T data)”, which says that T can be any type of Animal
  • Reference equality is when two reference variables refer to the same object on the heap
  • Object equality is when you have two references and two objects on the heap, so to treat them as equal you must override both the hashCode() and the equals() methods (which are inherited from class Object)
  • Array types are checked at runtime, but collection type checks happen only when you compile

Other Topics

  • Bit Manipulation
    • NOT (~) flips all bits, AND (&) makes bits 1 only if both bits were 1, OR (|) makes bits 1 if either bit was 1, XOR (^) makes bits 1 only if a single bit was 1
    • Left shift (<<) multiplies a number by a power of two and right shift (>>) divides by a power of two
    • Unsigned right shift (>>>) is like the right shift operator but ALWAYS fills the leftmost bits with zeros, so the sign bit may change
  • Immutability
    • When you make a new String, the JVM puts it into a special part of memory called the String Pool
    • If the String Pool contains the same String you’re trying to create, then the JVM refers your reference variable to the existing entry
    • The garbage collector doesn’t go into the String Pool, so you must be careful with memory management
  • Assertions
    • Add assert statements when you believe something must be true, which is used for debugging code
    • “assert (height >= 0);” means if height is a positive number then the program continues normally, but if not, then the program throws an AssertionError
  • Anonymous Inner Classes
    • When you create an inner class and instantiate it right away
    • Example: button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ev) {} }
  • Access Levels and Modifiers
    • public means code can be accessed from anywhere, protected means code in the same package has access and also subclasses outside the package can inherit the protected item, default means that only code within the same package can access, private means that only code within the same class has access
  • Strings
    • StringBuilder is a lot more efficient for manipulating a String
    • StringBuffer should only be used when you want your String manipulations to be thread-safe
  • Multidimensional Arrays
    • Declared as “int[][] array = new int [4][2]”, which creates an array with 4 elements, with each element being a reference variable referring to a newly created array with 2 elements
  • Enumerations
    • Enumerations are a set of constant values to represent the only valid values for a variable
    • Declared as “public enum Members { JERRY, BOBBY };”
    • If you declare “public Members bandMembers;” then bandMembers can only have a value of “JERRY” or “BOBBY”