Merikanto

一簫一劍平生意,負盡狂名十五年

Core Java Overview

Today we will walk through some syntax & features in core Java. Note that the version we use here is Java 8.



Intro

Notes

OpenJDK: open source version of Java


JVM:

  • OS process that provides the Java runtime environment

  • Interpreter for the bytecode form (with JIT compilation to give a huge performance boost)

  • Other languages can also run in JVM, as long as they have valid class files

  • Makes use of runtime information self-manageable

Research: Programs’ runtime behavior has a large amount of interesting & useful patterns that cannot be deduced at compile time.

JVM was the 1st platform to utilize this research, collects info to make better decisions about how to execute the code.


JIT:

  • HotSpot VM improved by detecting hot methods (methods used most often), then JVM compiles the hot methods directly to machine code.
  • Old days, Javac produces heavily optimized machine code. But then it’s better to just optimize JIT itself

Class file is the smallest unit of functionality the platform will deal with.


Javac:

  • Produces bytecode, while compilers produce machine code

  • Javac creates the intermediate representation (bytecode)

  • Compilation: JIT (it actually produces machine code)


Bytecode:

  • The instruction code (opcode) is just a single byte, only 256 possibilities
  • Byte ordering: big-endian

Comparison

Java & C

  • Java is object-oriented; C is not
  • Java is portable as class files; C need to be recompiled
  • Java has no pointers & pointer arithmetic,
  • Java provides automatic memory management via garbage collection
  • Java has no ability to lay out memory at low level (no structs)
  • Java has no pre-processor

Java & C++

  • Java is always pass by value (object references are values)
  • Java does not support full multiple inheritance
  • Java has no operator overloading

Java & JS

  • Java uses class-based objects; JS is prototype-based
  • Java has namespaces; JS does not
  • Java is multi-threaded; JS is not

Syntax

Note: strictfp & assert keywords are almost never used.

Overview

Classes are collections of methods & fields.

Reference types:

  • Fields
  • Methods
  • Constructors

Structure:

  • Primitives

  • Operators

  • Expressions

  • Statements

  • Methods

  • Classes

  • Packages

  • Programs / Applications


Lexical Structure

Java programs are written using Unicode.


const & goto are reserved keywords, but aren’t actually used in the language.


Literals

  • Definition: Literals are values that appear directly in Java source code.
  • Include: ints, floats, chars with single & double quotes, reserved words (true / false / null)
  • Each primitive type has a literal syntax for including type values literally in the code

Primitives

Eight types:

  • 1 boolean type
  • 1 character type
  • 2 floating-point type
  • 4 integer type
Type Size Comments
boolean 1 bit true / false
char 16 bits Unicode
byte 8 bits signed int
short 16 bits signed int
int 32 bits signed int
long 64 bits signed int
float 32 bits
double 64 bits

boolean: A boolean is neither an integral nor an object type. It cannot be widened / narrowed.


char:

  • Java 8 uses Unicode 6.2
  • Recent release of Unicode includes chars whose encoding / codepoints do not fit in 16 bits (use 21 bits instead)
    • Use int to hold codepoint of a supplementary char, or encode in surrogate pair of 2 char values
  • String literals: String type is class (a reference type)

Ints (4):

  • All int types represent signed numbers
  • Ints can be expressed in hex, binary, or octal notation (use underscore for binary literal)
  • Integer arithmetic in Java never produces overflow / underflow (numbers just wrap around)

Floats (2):

  • Floating-point literals are double by default
  • Cannot be expressed in hex, binary, octal
  • float & double values are only approximation of the represented numbers
  • 4 special values: Positive & negative infinity, zero, NaN (not a number)
    • Differentiate between positive & negative zero
  • Arithmetic Never throws exceptions, even when performing illegal operations (NaN)

Type Conversion

  • Only boolean cannot be converted

  • Widening: Value converted to a wider type

  • Narrowing: Value converted to a narrower type

    • Not always safe, may lose data
  • cast: Force type conversion (often used to convert floats to ints)

    1
    2
    3
    int i = 13;
    byte b = (byte) i; // (byte) is a cast
    i = (int) 13.1; // (int) another cast

Expressions & Operators

Operators

  • Precedence:
    • Operators with higher precedence are performed first
    • Default precedence is compatible with rules in C
  • Associativity:
    • Most are left-to-right associative
    • A reference is an object / array

Comparison, equality, Boolean operators always return boolean values.


Post-increment: a++

1
2
3
4
a[i++]++;

a[i++] = a[i++] + 1;
// Adds 1 to an array element, and stores new value in another element

Pre-increment: ++a first increments a, then returns the incremented value.

1
2
int a = 2;
int b = ++a + ++a * ++a; // Equals: b = 3 + 4 * 5 = 23

Java has built-in string conversion for all primitive types ( use toString() )


==:

  • For reference types, it only compares the content (if refers to the same object)
  • If == is used to compare different types of numeric / character values, the narrower type will be first converted to the wider type

Boolean operator

  • A && B: To increase efficiency, only evaluate B, if A is true
  • A || B: If A is true, then skip B. (since it will always be true)
  • A & B, A | B:
    • Always evaluate both A & B
    • Used as a bitwise operator with integer operands
  • A ^ B: Must always evaluate both

Bitwise & Shift Operators

  • <<: left shift
  • >>: signed right shift
  • >>>: unsigned right shift

Other operators

  • instanceof
  • . : object member access
  • [] : array element access
  • () : method invocation / type conversion / casting
  • -> : lambda expression
  • new : object creation
    • Objects are created with new
    • A constructor is a special block of code that initializes a newly created object

Statements

Many statements defined by Java are flow-control statements.


Compound statement: Statements grouped together with { }


Labeled statement: pre-pend an identifier, used by break & continue

1
2
3
loop1: for (int i = 0; i < n; ++i)
loop2: for (int j = 0; j < i; ++j)
break loop1;

Local var declaration statement:

  • Since Java is a statically typed language, only values of that type can be stored in the variable
  • Local vars can be used only within the method / block in which they’re defined (lexical scope)

Boolean: wrapper type (the wrapper object is auto unboxed)

boolean: primitive type


else

Without { }, else is associated with the nearest if.


switch

Use break after each case. Each case must be a constant or a constant expression that the compiler can evaluate.

1
2
3
4
5
6
7
8
9
10
11
12
13
switch(n) {
case 1:
// code block
break;

case 2:
// code block
break;

default:
// code block
break;
}

do-while

  • loop expression is tested at the boom of the loop
  • Execute at least once

for

  • Three things at the top : initialize, test, and update steps

    1
    2
    3
    4
    5
    6
    7
    8
    for (init; test; update)

    // Equal to the while below:
    init;
    while (test) {
    statement;
    update;
    }
  • Use comma to separate multiple init. / update:

    1
    for (int i = 0, j = 0; i < 10; ++i, -j)
  • Can be used for iterating through a linked list:

    1
    2
    for ( node n = head; n != null; n = n.next() )
    process(n);
  • Infinite loop:

    1
    for(;;)    // All three expressions are optional

  • foreach loop: Iterate collections

    • Hides loop counter (iterator)
    • Cannot get the array index
    1
    for (element: collection)

break

  • Exit innermost loop
  • Use label to choose exit

continue

  • continue quits the current iteration, and starts the next one
  • Only used within while / for loops

synchronized

  • Prevent multiple threads from modifying an object simultaneously (might corrupt the object’s state)

    1
    2
    3
    synchronized (expression) {
    // code block
    }
  • Before executing the code block, the Java interpreter first obtain an exclusive lock on the object specified by expression. The lock is held until finish running the code block. While a thread holds the lock, other threads cannot obtain the lock.

  • synchronized as a method modifier: The entire method is locked


throw

  • An exception: A signal that indicates exceptional condition / error has occurred

  • throw signals the exceptional condition, catch handles that exception. When there’s a throw, the interpreter stops normal program execution, and starts looking for an exception handler that can catch / handle the exception

    顺序:

    • 先看 method 里有没有 exception handler
    • 再看 code 里有没有处理 exception
    • 如果都没有就 print error message & stack trace

  • An exception is represented by an object


try / catch / finally

  • Every try must be followed by a catch / finally (to do the exception handling and cleanup)
  • finally: close files / shut down network connections
  • Exit try before finally: System.exit()

assert

  • Rarely used, inflexible for testing applications

  • Never attempt to catch AssertionError from your own code (might have unexpected results in future versions)


Methods

A method invocation is an expression that’s evaluated by the Java interpreter.


Method Signature

A method signature contains:

  • Method name
  • Parameters (number, order, type, name)
  • Returned value type
  • Checked exceptions to throw
  • Method modifiers

Method signature can also include type variable declarations (generic methods).


Abstract methods only have specification, but no implementation (no method body).


A method signature is the method specification, and defines the API for the method.

1
modifiers type name (paramlist) [throws exception]

The signature is followed by the method body ( = method implementation = bunch of Java statements).

  • modifiers: public / protected / private, final, native,  static, synchronized / volatile, abstract, strictfp

  • type: specifies the return type

  • Constructor: initialize newly created objects (constructor’s signature does not include the type specification)

  • name: follows the specification of its modifier & type (method names & variable names are Java identifiers)

    • Method overloading: Define more than one method with the same name (each method has a different param list)
  • Param list: empty is ( ). Java does not regard void as a type

  • throw:

    • Checked exceptions:

      • Category of exception classes that must be listed in the throw clause of methods that can throw them
      • Must use throw clause to declare the exception in the method signature
      • Java compiler checks to make sure they’re declared in the method signature, hence the name “checked”
    • Unchecked exceptions:

      • Failures that cannot be predicted, due to runtime conditions. (e.g. OutOfMemoryError, NullPointerException)

      • Murphy’s law: Anything that can go wrong, will go wrong.

    • Exceptions are throwable objects. 2 categories:

      • Error (Any exception object that is an Error is unchecked)
      • Exception (checked)
      • 特例: RuntimeException is unchecked

Method Modifiers

abstract

  • An abstract method is a specification without an implementation

  • A class that includes an abstract method must also be abstract. Such class cannot be instantiated

    Need implementation of specification, to instantiate the class.


final

  • A final method may not be overridden or hidden by a subclass
  • All private methods are implicitly final

native

  • Indicates method implementation is written in “native” languages such as C
  • Provided externally to the Java program, platform-dependent
  • All native & abstract methods have no body
  • Used to interface Java code to existing C / C++ libraries

static

A method with static is a class method associated with the class itself, but not associated with the instance of the class


strictfp

  • fp: floating point
  • Only perform fp arithmetic using 32 / 64 bit floating-point formats, even this is less accurate

synchronized

  • Makes a method thread safe, prevents 2 thread from executing the method at the same time

    Before a thread invokes a synchronized method, it must obtain a lock on the method’s class, or on relevant instance of the class.

  • synchronized modifier is an implementation detail (because methods can make themselves thread safe in other ways)


Annotations: intermediary between method modifier & supplementary type information.


Class & Objects

A class is a named collection of fields that hold data values & methods

  • One of the 5 reference types

  • 流程: define a class, instantiate it, and use the resulting object

  • Classes define new data types.

    Important to distinguish between data type & the value data type represents.

  • A class is data type, and class value is called the object. Each class defines a type of objects.


Define a class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Point {

public double x, y;

// Constructor, initialize the field
public Point(double x, double y) {
this.x = x;
this.y = y;
}

public double distance() {
return Math.sqrt(x*x + y*y);
}
}

Create an object

1
2
// New object p, of the class Point
Point p = new Point(2.0, -3.5);
  • Dynamic loading mechanism: Java allows programs to load classes & create instances of classes dynamically
  • Objects can also be created by deserializing them

Object literals

  • String literal: strings are objects; the data type to represent text is the String class

  • Type literal: a Class class. Instances of Class class represent a Java data type

    1
    2
    // Include a Class object literally in the code
    Class<?> typeIntArray = int[].class;
  • Null reference: reference to nothing / absence of a reference . Null is a member of every reference type.


Lambda Expressions

A lambda expression is a function that does not have a name.

  • Can be treated as a value

  • Java does not allow code to run on its own outside of class: Lambda is an anonymous method that is defined on some class

  • Syntax: (paramlist) -> (statements)

    1
    Runnable r = () -> System.out.println("hello");
  • When lambda is used as a value, it is automatically converted to a new object of the correct type .

    Auto conversion & Type inference is essential to Java’s lambda expressions.


Arrays

Array type are reference types, and instances of arrays are objects.

  • Arrays inherit the methods of java.lang.Object
  • Arrays implement the Cloneable interface, and override the clone() method to ensure arrays can be cloned
  • Arrays also implement Serializable, so it can be serialized, if its elements are serialized
  • All arrays have a public final int field called length

Type conversion

  • Since arrays extend Object and implement Clonable & Serializable interfaces, an array type can be widened to any of these 3 types.
  • Ability to widen array type (array covariance): Array’s compile-time type is not same as runtime type
  • Compilers need runtime checks, to ensure runtime value type match runtime array element type

Init. Arrays

  • Array types don’t have constructors

  • Init. value: 0 / false / null

  • Use anonymous array literals (apply to multi-dimensional array as well):

    1
    String response = Question( "Exit?", new String[] {"Yes", "No"} );
  • As part of variable declaration: (Array literals are created & initialized at runtime)

    1
    String[] response = {"Yes", "No"};

    Java does all array initialization at runtime:

    Expressions in an array initializer may be computed at runtime, and need not be compile-time constants.


Copy Arrays

  • Since all array types implement Cloneable, hence any array can be copied by the clone() method

  • A cast is required to convert return value to the appropriate array type

    1
    2
    int[] a = {1, 2, 3};
    int[] b = (int[]) a.clone();
  • Two ways to copy arrays

    • clone() : shallow copy

      If array element type is a reference type, then only the references are copied. Any array can be cloned even if element type is not Clonable.

    • System.arraycopy()

      1
      2
      3
      // arraycopy(source, s[i], destination, d[j], #-of-elements)
      System.arraycopy(a, 1, a, 0, n);
      // Shift elements in [1, n] one index down

      ​ Works even for overlapping copies within the same array.


Array Utilities

  • java.util.Arrays contains a number of static utility methods
  • Most of the methods are heavily overloaded, with versions for arrays of primitive types & arrays of objects
  • sort() & binarySearch() for sort, search arrays
  • Arrays.toString(), convert array content to string output

Multi-dimensional Arrays

1
2
3
4
5
6
int[][] a = new int[10][10];

// The statement above equals to:
int[][] a = new int[10][];
for (int i = 0; i < 10; ++i) // Loop 10 times
a[i] = new int[10];

Line 1 does three things:

  • Declare the variable a
  • Creates a 10-element array, to hold 10 arrays of int
  • Creates 10 more arrays with a loop

When using the new keyword, only need to specify the leftmost dimension of the array.

1
2
3
4
5
// 1-D array
float[][][] a = new float[10][][];

// 2-D array
float[][][] a = new float[10][10][];

Reference Types

Five reference types

  • Annotation: Associate metadata with program elements
  • Array
  • Enumeration: Reference for a set of objects that represents a related set of choices
  • Class: Provide inheritance, polymorphism, and encapsulation
  • Interface: Provide public API and is implemented by Java classes

Object: value / instance of any reference type.


Reference & Primitive Types

  • User cannot define new primitive types, but reference types are user-defined

  • Primitive types represent single values; Reference types are aggregate types that hold zero / more primitive values or objects

  • Primitive types only require 1 - 8 bytes of memory. For reference types, only the reference to that memory is stored

  • Imagine a reference as a pointer or a memory address (Java cannot manipulate references)

    Memory for storing a object is dynamically allocated on the heap, and it’s auto garbage-collected when the object is no longer needed .


Pass arguments to methods

  • Primitive: The method is given a copy of the argument used to invoke the method
  • Reference: Method pass a private copy of a reference to the object

Compare Objects

Reference types, 2 kinds of equality:

  • Equality of reference
    • .equals(): 判断内容是否一致
  • Equality of object
    • == : Whether 2 references refer to the same object

Arrays always inherit the default equals() method the compares references, rather than array content.


Boxing & Unboxing

  • Treat primitive values as objects: wrapper class for each of the 8 primitive types (Immutable, final classes)

    Boolean, Byte, Short, Character, Integer, Long, Float, Double

  • Use wrapper class when you want to store primitive values in collections

  • Boxing convert primitives to wrapper objects, and Unboxing converts wrapper class back to primitives

  • Autoboxing: Java performs boxing & unboxing automatically

    • Autoboxing makes dealing with collections much easier.
    1
    List<Integer> n = new ArrayList<>();   // Box into integer

Packages & Namespaces

A package is a named collection of classes , interfaces & other reference types.


javax: Extension to the Java Platform.


Each class has a simple name & fully qualified name.

E.g. class String & java.lang.String


Use globally unique package name to partition the Java namespace, and prevent name collisions between classes


Static Imports

On-demand import does not apply to subpackages.

1
2
// On-demand import 
import java.io.*;

Import static members

1
import static java.lang.Math.*;

Important use: Import the name of constants into your code.

1
2
3
4
5
6
// Enumerated type
package hello;
enum Names {ALICE, BOB, CHARLIE}

// import in another file
import static hello.Names.*;

Using static member import declarations for constants is generally better than implementing an interface that defines the constants.


It is legal to import static methods with the same name from more than 2 different types, as long as the method signatures are different.

1
2
3
// Legal Import
import static java.util.Arryas.sort;
import static java.util.Collections.sort;

File Structure

All Java statements must appear within methods;

All methods must appear within type definition.

A Java file consists of:

  • package directive (optional)
  • import / import static directives
  • Type definitions

Restriction for Java files:

  • Each file contain at most one top-level public class
  • A public class is designed for use by other classes in other packages
  • File name & class name must be the same

Tell the interpreter to look in locations other than the current directory:

Specify java -classpath in Terminal


Run Programs

The main() method is the main entry point for your program. This method is passed an array of strings, and returns no value.

When main() returns, the Java interpreter exits.