This page contains the essential facts you should have learned in AP CSA. It is in some ways distilled and in some ways expanded from the “essential knowledge” items from the College Board’s AP CSA Course and Exam Description.
It is condensed insofar as I was able to combine topics that are spread out over several units in the curriculum now since we’ve now covered them all. But it is expanded in that I tried to add a bit of nuance or even just clarity to the individual items compared to how the College Board wrote them.
A type is a set of values (a domain) and a set of operations on them.
Data types in Java are either primitive or reference types.
The primitive data types used in this course, which represent numbers and logical values, are int
, double
, and boolean
.
The main reference types we use are String
, arrays, ArrayList
and other classes that we write ourselves all of which extend Object
.
The primitive data types and String
s each have a syntax for writing literal values in Java programs, e.g. 1234
, 9.876
, true
, and "foobar"
.
Integer values in Java are represented by the data type int
. int
s are stored using four bytes (32 bits) of memory. Therefore, an int
value must be in the range from Integer.MIN_VALUE
to Integer.MAX_ VALUE
inclusive.
If an int
expression would evaluate to a numeric value outside of the possible range for int
, an overflow occur resulting in a mathematically incorrect int
value. (For instance Integer.MAX_VALUE + 1
evaluates to Integer.MIN_VALUE
.)
Numbers with fractional parts are represented by the data type double
. A double
is stored in a 64-bit representation that encodes a significand, and exponent, and a sign, similar to the way scientific notation works.
Logical values (true and false) are represented by the boolean
data type. There are only two boolean
values: written as true
and false
.
All the other data types we will use are reference data types which means the values that are stored in variables and passed to and returned from methods are references to where the real value lives in memory.
null
is a special reference value that represents “no object”. It can be written as a literal value as null
. It is the default value for uninitialized member variables and the unitialized elements of arrays of reference types such as String[]
.
Using the dot operator to call a method or access an instance variable on a null
value causes a NullPointerException
to be thrown.
Each variable has associated memory that is used to hold its value.
The memory associated with a variable of a primitive type holds the actual representation of the primitive value while the memory associated with a variable holding a reference type holds a reference to the actual data which exists somewhere else in the computer’s memory.
A minimal variable declaration contains a type and a name.
The type of a variable determines what kind of values we can assign to the variable and what kind of value it produces when used as an expression.
The name of a variable allows us to refer to it in assignment expression and as a value.
Two variables can hold references to the same object which allows changes made to the object via one variable to be visible via the other variable.
When a variable is declared final
, its value cannot be changed once it is initialized.
There are two kinds of variables in Java: local and member. Member variables, are further divided into instance and static variables.
Local variables are declared in the body of methods and constructors. These variables may only be used within the method or constructor where they are declared. They are not marked as either public
or private
because they are not accessible at all outside the method or constructor.
Parameters declared in a method or constructor are also local variables.
When there is a local variable with the same name as a member variable, the name will refer to the local variable instead of the member variable. This is called “shadowing”.
When a instance member variable is shadowed by a local variable it can be referred to with an explicit this.
as in this.x
. A static member variable can referred to with an explicit ClassName.
as in ClassName.SOME_VARIABLE
.
Member variable are declared at the top-level of a class and can be marked as public
or private
. Usually variables will be marked private
though sometimes classes define important constants as public static final
variables, for instance Math.PI
.
An expression is any part of a program that can be evaluated to produce a value:
Literal values, e.g. 10
or "foo"
, evaluate to the value they denote.
Variables, e.g. x
or Math.PI
, evaluate to the current value of of the variable.
Method calls to non-void
methods, e.g. s.substring(1)
or Math.sqrt(2)
, evaluate to the value returned by the method when called with the given arguments.
Object instantiations via the new
keyword, e.g. new ArrayList<>()
, evaluate to a reference to a newly created object that has been initialized by running the appropriate constructor.
Array access expressions, e.g xs[0]
, evaluate to the value stored at the given position in the array.
Compound expressions made up of expressions and operators, e.g. x + 2
, evaluate to a value determined by the operator and its operands.
Each expression has a type which is determined by the types of its sub-expressions and the operators involved. The type describes the kind of values it can produce.
Anywhere a value of a given type is needed we can use any expression that produces values of that type.
Arithmetic expressions are expressions that produce an or int
and double
value.
The arithmetic operators consist of +
, −
, *
, /
, and %
.
An arithmetic operation on two int
s will evaluate to an int
.
An arithmetic operation with at least one double
value will evaluate to a double
.
Operators can be used to construct compound expressions.
During evaluation, operands are associated with operators according to operator precedence to determine how they are grouped.
An attempt to divide an integer by zero will result in an ArithmeticException
to occur.
The casting operators (int)
and (double)
produce numeric values of the specified type.
Casting a double
to an int
produces an int
with any fractional part (the digits to the right of the decimal point) truncated.1
Casting an int
to double
produces a double with the same mathematical value since all int
values are exactly representable as a double
.
Using an int
where a double
is expected, without a cast, causes the int
value to be automatically converted to a double
value.
Values of type double
can be rounded to the nearest int
by (int)(x +
0.5)
or (int)(x – 0.5)
for negative numbers.
A boolean expression is any expression that results in a boolean
value. The values used in the expression may be boolean
s or other kinds of values. For instance, x > 10
is a boolean
expression even though x
must be a number and a == b
always evaluates to a boolean
even though a
and b
could be any type of values.
Boolean expressions are made from boolean
literals, boolean
variables, methods that return boolean
, and expressions involving logical operators, equality operators, relational operators.
Logical operators operate on boolean
values and produce a boolean
value.
The logical operators in Java are !
(not), &&
(and), and ||
(or).
!
is the highest precedence, followed by &&
, followed by ||
.2
When the result of a logical expression using &&
or ||
can be determined by evaluating only the first operand, the second is not evaluated. This is known as short-circuited evaluation.3
De Morgan’s Laws allows us to transform some boolean expressions into equivalent expressions.
!a && !b = !(a || b)
!a || !b = !(a && b)
Truth tables can be used to prove boolean
identities, i.e. different expressions that are equivalent in the sense that for all possible combinations of values for the variables in the expressions they evaluate to the same value. A trivial example of a pair of equivalent expressions is: a
&& true
and a
. More complex identities include things like De Morgan’s Laws. For more details see Boolean algebra summary
Both primitive and reference values can be compared for equality using the equality operators ==
and !=
.
However two object references are only ==
when they both reference the same object or when they are both null
. This may not, however, be the notion of “the same” that you care about when you are comparing two objects.
All classes have an equals
method inherited from Object
and often overridden by classes to provide a way to determine if two instances of the class are equivalent. For example, two String
objects with the same character content are equals
even when they are not ==
.4
The ==
operator is sometimes pronounced “equals equals” to distinguish it from the equals
method.
Relational operators operate on numeric values and produce a boolean
value.
Numeric values can be compared using the relational operators <
, >
, <=
, and >=
which evaluate to true
if their left hand operand is less than, greater than, less than or equal to, or greater than or equal to the right hand operand. E.g. 10 < 20
evaluates to true
.
You can’t chain relational operators in Java the way you can in math. So rather than writing 0 <= x < 10
you have to combine two relational expressions with the logical operator &&
, writing instead 0 <= x && x <
10
.
Assignments in Java are technically expressions that produce a value but normally we care more about their side effect, namely changing the value the variable or array element being assigned to.
The only assignable places in Java are variables (local or member) and array access expressions, e.g. x
, obj.someField
, and nums[0]
.
The assignment operator =
allows a program to initialize or change the value stored in a variable or an array element. The value of the expression on the right of the =
is stored in the variable or array element referenced on the left. The value of of an assignment expression is the value that was assigned.
Compound assignment operators (+=
, −=
, *=
, /=
, %=
) can be used to assign a new value to a variable or array element computed from the old value. For instance x += 2
is equivalent to x = x + 2
. The value of a compound assignment expression is the new value of the variable or array element.
The increment operator (++
) and decrement operator (−−
) are used to add 1 or subtract 1 from the value of a variable or an array element. For instance x++
equivalent to x += 1
or x = x + 1
. The value of a ++
or --
is the value of the variable or array element before it was incremented or decremented.5
Note that =
(one equals sign) is the assignment operator and ==
(two equals signs) is the equality comparison operator. If you mix them up, you’ll get either compiler errors or incorrect and confusing behavior from your program.
Procedural abstraction means hiding how a value is computed or how an effect is achieved allowing a programmer to use a method without needing to know exactly how the method is written.
In Java the unit of procedural abstraction is the method.
Methods allow us to “decompose” or break down a large problem into smaller sub-problems by writing methods that call other methods that each solve various sub-problems.
We can use methods provided to us by Java (as in the Math
methods such as Math.sqrt
) and also methods that we write ourselves.
We can use methods without knowing exactly how they are implemented but it is also useful to write our own method to hide details in one part of our code even though we have to deal with those details elsewhere.
The code in one method can call other methods, allowing us to build layers of abstractions.
Method signatures must specify three things: the return type, the name of the method, and the method’s parameters.
The return type specifies the kind of value the method returns. The special return type void
indicates that a method does not return any value. All non-void
methods must return a value of the specified type.
Methods with void
as their return type are called “void
methods” and are called only for the effects they have, such as printing to the screen or changing the state of an object.
Method parameters are variables and thus must be specified with a type and a name.
Methods that take no arguments are written with an empty parameter list consisting of just a pair of parentheses.
The body of the method follows the signature and is enclosed in a pair of {}
s.
Code within the body of a method can refer to the parameters declared in the method signature as well as any local variables declared in the method and any static
variables declared in the class. Code in instance methods can also refer to any instance variables defined in the class and the special variable this
which refers to the object on which the method was invoked.
Method calls consist of a reference to the method and a possibly empty argument list consisting of a comma-separated list of expressions, e.g. foo(10, "some string")
.
The expressions in the argument list are evaluated to get the values that are passed as the arguments to the method. When the method runs the parameters declared in the method signature are initialized to the values of the corresponding arguments, with the first parameter getting the value of the first argument, and so on.
The arguments passed to a constructor or method call must be compatible with the types identified in the parameter list.
Arguments are passed to methods by copying values. This means that there is no way for code in a method to change the value of local variable in the method that called it.
Recall, however, that the value of a reference type is the reference itself; this means code in a method or constructor that is passed a reference to a mutable object can use the reference to alter the state of the object and those changes will be visible to other code that also has a reference to that object. As a matter of good coding practice, methods should not modify mutable objects passed as arguments unless doing so is an inherent part of the method’s purpose.
Calling a method causes the flow of control to jump to the start of the method after initializing the parameters. When the method returns, the flow of control returns to the point where the method was called. No code executes in a method after a return
statement.6
Values are returned from a method using a return
statement consisting of the keyword return
followed by an expression that evaluates to a value of the correct type which is then returned from the method. (In a void
method return
is only used with no following expression to return early from a method.7)
The value returned by a method is copied, just like method arguments. Again, this means a reference returned by a method can be used to modify object it references.
A method call to a non-void
method is a kind of expression whose value is the value returned by the method.
A call to a void
method can only be for effect and not part of an expression since the method doesn’t return any value. They typically do not need a return
statement and simply return when execution reaches the end of the method.
Within a class, code can reference other methods in the same class simply by their name with the exception that static
methods cannot call instance methods without an explicit object to invoke the method on. But in non-static
methods, invoking a method by its simple name is the same as invoking it on this
, i.e. on the same object the current method was invoked on.
Outside a class, static
methods are typically referenced using the class name, the dot operator, and the name of the method, e.g. Math.sqrt(2)
to invoke the static
sqrt
method in the class Math
.
Instance methods in other classes are invoked on a particular object using an expression that evaluates to a reference to the object, the dot operator, and the name of the method, e.g. s.substring(1)
to invoke the substring
method on an instance of String
referenced by the variable s
.
Control constructs allow us to control the flow of execution other than by calling and returning from methods. They fall into to two kinds: conditional control constructs and and looping control constructs.
Conditional statements interrupt the normal sequential flow of control from one statement to the next by allowing some code to execute or not depending on the values of a boolean
condition.
A simple if
statement affect the flow of control by executing the statements in the if
’s body only if the if
’s boolean
condition evaluates to true
. This provides a one-way selection where a set of statements either is or is not executed, depending on the condition.
A two-way selection, written with an if
/else
, causes either one set of statements or another to be executed, one when the boolean condition is true and the other when it is false.
A multi-way selection, written with an if
, one ore more else if
s, and optionally a final else
, chooses one of several sets of statements to execute based on a number of different boolean
conditions. The code that executes is the body of the first if
or else if
whose condition is true
or the body of the else
if all the conditions are false
.
Any code can go in the body of an if
or else
including other if
, if
/else
, and if
/else if
/else
statements, producing nested conditional statements.
Technically if
/else if
/else
statements are just regular if
/else
statements with a nested if
/else
statement but we write them chained together when we want to express a multi-way selection.
Looping control constructs, also called iteration constructs, change the normal flow of control by repeating a sequence of statements zero or more times.
In both while
and for
loops, a boolean
expression is evaluated before each iteration of the loop’s body, including the first. When the expression evaluates to true
, the loop body is executed. Then the loop repeats this process until the boolean
expression evaluates to false..
If the boolean
expression evaluates to false the first time it is evaluated, the loop body is not executed at all. Conversely, if the boolean
expression always evaluates to true
, the loop is an infinite loop.
A while
loop consists of just two parts: the condition and the body.
A while
loop executes by evaluating the condition. If the condition is true
it then executes the body and repeats, back at the condition. Otherwise the loop ends.
Both the condition and the body will usually refer to variables defined before the loop. If the condition depends on the values of one or more variables and the body contains code that changes those variables, the condition can eventually become false
and the loop will stop.
while
loops are most useful when you do not know, before the loop starts, exactly how many times it needs to run.
A for
loop consists of a header and a body.
The header of a for
loop consists of three parts, enclosed in parentheses and separated by semicolons:
the initialization clause
the condition
the update clause
The initialization clause is run once, before anything else in the loop. Typically the initialization clause declares and initializes a variable called the loop variable.
The condition is evaluated before each iteration of the loop and the loop only continues if it evaluates to true
. Usually the condition is some expression involving the loop variable.
The update clause runs after the body of the loop and just before the next evaluation of the condition. The update clause usually updates the loop variable, typically by incrementing or decrementing it.
The body of the for
loop is executed after the condition is evaluated and before the update clause. Code within the body can refer to the loop variable declared in the loop header.
for
loops are typically used when we know, before the loop starts, how many times we want to iterate, e.g. once for every character in a string or element of an array.
A for
loop can be rewritten into an equivalent while
loop and vice versa, though the while
loop will need some code before the loop proper to perform the role of the for
loop’s initialization clause and the update clause will need to appear in the body of the while
loop.
The enhanced for
loop provides a concise way to traverse an array or an ArrayList
in the common case when we only need to deal with one element at a time and don’t care about the index.
The enhanced for
loop consists of a simplified header consisting of just a variable declaration, a colon, and an expression that evaluates to an array or an ArrayList
, and a body.
The body of an enhanced for
loop is executed once for each element of the array or ArrayList
with the variable assigned the value of each element in turn.
The loop variable in an enhanced for
loop is just a regular variable. Assigning a new value to it has no effect on the array itself.
The body of a loop can contain any statements including other loops.
Nested loops are just loops that appear in the body of another loop.
When a loop is nested inside another loop, the inner loop must complete before the outer loop can continue.
Since executing a return
statement always immediately returns from the current method, it can be used to break out of a loop.8
“Off by one” errors occur when the iteration statement loops one time too many or one time too few, for instance for (int i = 0; i <= s.length(); i++) rather than for (int i = 0; i < s.length(); i++) when iterating over the characters of a string.
Unintended infinite loops occur when the condition never becomes false, often due to a bug in the update code.
See counting loops for another summary of different kinds of loops.
Arrays are a reference type that collects multiple values of a given type into a single value.
The values in an array are called the elements of the array or sometimes the components.
Array elements can be either primitive or reference values.
The size of an array is established at the time of its creation and cannot be changed.
When an array is created using the keyword new
and a size (e.g. new
int[10]
) all of its elements are initialized with the standard zero value for the element type: 0 for int
s, 0.0
for double
s, false
for boolean
s, and null
for all reference types.
Initializer lists can be used to create arrays containing specific values, e.g. new int[] { 42, 52, 103 }
. Arrays created this way have their length set to the number of elements provided.
Arrays have a read-only instance variable length
which gives the number of elements in the array.
The elements of an array are accessed using square brackets ([]) and an index, e.g. xs[0]
accesses the 0th element of the array xs
.
The valid indices for an array are 0 through length - 1, inclusive.
Using an invalid index (less than 0 or greater than length - 1) will cause an ArrayIndexOutOfBoundsException
.
An array access expression is like a variable in that it can be used to obtain a value or as a place that can be assigned a value with = or any applicable compound assignment operator (e.g. +=
or ++
on on an array of numbers).
Looping over the individual elements of an array is also called traversing the array.
Traversing an array with a standard for
or while
loop requires using an index to access each element of the array.
2d arrays are stored as arrays of arrays. Therefore, the way 2d arrays are created and indexed is similar to 1d array objects.
It is equally correct to think of a 2d array as a 1d array whose elements happen to be arrays.
The square brackets [row][col]
are used to access and modify an element in a 2d array.
2d arrays can be initialized with specific values by writing a nested initialization expression like { { 1, 2, 3 }, { 4, 5, 6 } }
2d arrays are typically traversed using nested loops.
Since 2d arrays are stored as arrays of arrays, the outer loop iterates over the array whose elements are 1d arrays and the inner loop iterates over the elements of the 1d array.
In the outer loop of nested enhanced for
loops used to traverse a 2d array, the type of the loop variable must be the type of each row, i.e. a 1d array. In the inner loop, the type of the loop variable is the actual element type.
Typically, and always on the AP exam, 2d arrays are arranged with the outer array holding 1d array representing the rows of the 2d array. Thus to access the element at row r
and column c
, we use arr[r][c]
. This form is called “row-major order”.
It is, however, possible to think of a 2d array as representing an array of columns in which case to get the element at row r
and column c
you would write arr[c][r]
. This is called “column-major order”.
All algorithms that work with 1d arrays will work with 2d arrays, as long as they apply to arrays whose elements are arrays.
A class defines a common structure for many objects. The structure is made up of variables, constructors, and methods which, collectively, are called the “members” of a class.
Defining a class also defines a new type that can be used anywhere a type is needed: in variable declarations, as the return type of a method, or as the type of element on an array or ArrayList
.
An object is a single instance of a class whose data lives somewhere in memory distinct from all other objects.
static
membersVariables and methods can be either static, marked with the static
keyword, or non-static, also known as “instance” variables and methods.
Static variables and methods can be marked as either public
or private
and then marked with the static
keyword before the variable type or the return type of a method, e.g. public static int
.
Each static variable represents a single value stored in the class itself and shared by all instances of the class.
Static methods can only access static variables and call other static methods.9
Static members are typically accessed with the class name and the dot operator, e.g. Math.PI
and Math.abs()
.
An object’s state is stored in its instance variables and each object has its own values its instance variable.
Instance variables create a “has-a” relationship between the object and the values stored in its instance variables, as in a Point
has an x and y value. (This is often contrasted to the “is-a” relationship created when one class extends
another.)
Instance variables can be marked as either public
or private
before the variable type, e.g private int n
. Typically they are made private
.
Constructors are invoked to create objects. A constructor’s signature consists of the constructor name, which always matches the class name, and a parameter list.
Every object is created by calling a constructor using the keyword new
followed by the class name and an argument list that corresponds to one of the class’s constructors.10
The job of a constructor is to initialize the state of an object and leave it in a usable state. Often constructors assign the values passed as arguments to the constructor to the object’s instance variables.
Constructors have parameter lists that work just like method parameter lists, defining local variables that are initialized with the values of the arguments passed to a call to the constructor. The arguments should provide the data needed to initialize the object’s state.
When no constructor is written, Java provides a no-argument constructor and all instance variables are set to the default value for their type. (0 for int, 0.0 for double, false for boolean, and null for all reference types.)
When a mutable object is passed as an argument to a constructor and stored in an instance variable, any mutations made to that object by code in the class will change the state for all code that has a reference to that object. Sometimes it’s necessary to instead store a copy of the argument to avoid changing the original object out from under other code. Other times that’s the whole point of being passed the object.
An object’s behavior—what we can do with the object—is defined by the methods in its class.
Instance methods are called on objects of the class while static
methods are called on the class itself.
Instance methods have access to all an object’s instance variables.
Methods that take no arguments and simply return the value of an instance variable are called “getters” or, more formally, “accessors”. They are used to give code outside the class access to the object’s state without making instance variables public.
Methods that return void
, take a single argument, and assign it to the value of an instance variable are called “setters”. More generally, methods that change any part of an object’s state are called “mutators”.
The keywords public
and private
control what code can access class members.
The keyword private
restricts access to only code within the declaring class, while the keyword public
allows access from any code.
Classes cannot be marked private
and are typically marked public
.11
Access to variables should usually be kept internal to the class. Therefore, instance variables are usually made private
.
Constructors are typically made public
but sometimes classes will have private
constructors that are only used within the class, either from other constructors or from methods that construct new instances of the class.
Methods are equally likely to be public
or private
. The public
methods define what we can do with instances of a class but private
methods are useful for breaking up big methods into sub-methods that are only useful within a class.
Code within a class can access the private
variables and methods of any instance of the class.
Encapsulation is a technique in which implementation details of a class are kept hidden from code outside the class.
When designing a class, programmers make decisions about what parts of its state to make accessible and modifiable from an external class. Data can be either accessible, modifiable, both, or neither.
State can be encapsulated by storing it in private
instance variables and access controlled by what getter, setter, and other mutator methods are provided.
toString
The toString
method is inherited from java.lang.Object
and is frequently overridden to provide a concise, human-readable representation of an object.
If System.out.print or System.out.println is passed an object, that object’s toString
method is called, and the returned String
is printed.
toString
is also used when a reference type is include in a String
concatenation expression.
this
Within a non-static
method or a constructor, the keyword this
is a name for the reference to the current object—the object on which the method was called or the object being constructed.
The keyword this
can be used to pass a reference to the current object as an argument to a method or constructor or as a value to be assigned anywhere a value of the type of the current class is needed.
Comments are ignored by the compiler and are not executed when the program is run.
Three types of comments in Java include /* */
, which generates a block of comments, //
, which generates a comment on one line, and /** */
, which are Javadoc comments and are used to create API documentation.
Invariants are things that must be true if the program is working correctly. They help us think about how different parts of a program work together.
A precondition is a kind of invariant that defines a condition that must be true before a method is called.
A postcondition is kind of invariant that defines a condition that must always be true after a method returns successfully. Postconditions describe the outcome of the execution in terms of the value returned and/or any changes to the state of the world.
The job of a method is to satisfy its postconditions assuming its preconditions have been met. If the preconditions are not met, it is a bug in the code that called the method. If the preconditions were met and the postconditions are not satisfied it is a bug in the method. Methods may or may not actually check that their preconditions have been met.
Constructors are said to be overloaded when there are multiple constructors in the same class with different numbers or types of parameters.
Methods are said to be overloaded when there are multiple methods in the same class (or inheritance hierarchy) with the same name but different numbers or types of parameters.
When an overloaded constructor or method is called, which one is invoked is determined by finding the constructor or method whose parameter types match the types of the arguments in the call.
Overloading of methods doesn’t allow you to do anything you couldn’t do by just giving the different methods different names.
A class hierarchy can be developed by putting common attributes and behaviors of related classes into a single class called a superclass.
The keyword extends
is used to establish an inheritance relationship between a subclass and a superclass. A class can extend only one superclass.
Classes that extend
a superclass, called subclasses, can draw upon the existing variables and behaviors of the superclass without repeating these in the code.
Class S
should only extend T
if there is an “is-a” relationship between S and T. (If an S
isn’t a T
but they’re related it may be that there should be a “has-a” relationship expressed by one class having an instance variable that holds a reference to an instance of the other class.)
The Object
class in the java.lang
package is the direct or indirect superclass of all other classes in Java.
Classes that do not explicitly extend another class, implicitly extend Object
.
All classes inherit from Object
the methods boolean equals(Object other)
and String toString()
which are described in the AP Java Quick Reference.
Subclasses of Object
often override the equals
and toString
methods with class-specific implementations.12
Constructors are not inherited.
Every constructor must call a superclass constructor as the first thing it does. This can either be explicit, using the keyword super
and passing appropriate arguments, or implicit by letting the compiler insert a call to the superclass’s no-argument constructor, if there is one.
Regardless of whether the superclass constructor is called implicitly or explicitly, the process of calling superclass constructors continues until java.lang.Object
’s no-arg constructor is called. At this point, all of the constructors within the hierarchy execute, beginning with the Object
constructor. This ensures that before any code runs in a class all of it’s inherited instance variables have been properly initialized.
The actual parameters passed in the call to the superclass constructor provide values that the constructor can use to initialize the instance variables defined in the superclass.
A subclass inherits all the public
methods of its superclass as public
methods in the subclass.
A public
method written in a subclass with the same method signature as a public method in the superclass overrides the parent class method.
Subclasses can extend the behavior of their superclass by overriding existing methods or by adding additional methods or instance variables that are not present in the superclass.
In a subclass, the superclass version of an overridden method, say foo
can be called as super.foo()
passing appropriate parameters as in any method call.
The compiler will only allow method calls to non-static
methods that exist in the compile-time type of object on which the method is being called, either because the method is defined in that class or inherited from a superclass.
At run-time, the actual type of the object on which a non-static
method is invoked determines exactly what method is run.
Anywhere an instance of type T
is required (assigning to a variable declared to be of type T
, as a method argument that requires a T
, as an element of a T[]
array or an ArrayList<T>
, etc.) we can also use an instance of S
if S
is a direct or indirect subclass of T
.
Using an instance of a subclass in the place of the superclass is what allows for the possibility of polymorphism, where the actual class of an object determines what version of an overridden method is invoked.
Classes in Java are grouped into packages. The classes String
, Math
, System
, Integer
, Double
, Boolean
, and Object
are all from the java.lang
package which is always available in all Java programs.
The only class we use from another package is ArrayList
which needs to be imported from java.util
.
Application program interfaces (APIs) and libraries provide classes we can use in our programs.
A class’s documentation describes the attributes, constructors and methods defined in the class.
String
objects are typically created with String
literals but can be constructed via constructors defined in the String
class.
String
objects are immutable; many methods on String
s produce new String
s that are related to the original (such as the original converted to all upper case) but the original String
cannot be changed.
String
objects can be concatenated using the +
or +=
operator, resulting in a new String
object.
Non-String
values can also be concatenated with a String
object. This causes an implicit conversion of the values to String
objects. Primitive values and null
are converted to their standard literal form and reference types are converted using their toString
method.
Escape sequences in Strings start with a \
and have a special meaning in Java. Escape sequences used in this course include \”
, \\
, and \n
.
A String
object has index values from 0 to length – 1. Attempting to access indices outside this range (i.e. less than 0 or greater than or equal to the length of the String) will result in an StringIndexOutOfBoundsException
.
You can think of the index as the number that tells you how far from the front of the string a given character is. Thus the second character in a String
has index 1 because there is one character ahead of it. And the first character has index 0 because there are zero characters ahead of it. The length of the string is not a valid index because there is no character in an n-character string that has n characters in front of it.
The following String
methods and constructors—including what they do and when they are used—are part of the AP Java Quick Reference:
String(String str)
— Constructs a new String object that represents the same sequence of characters as str. There is almost no reason to ever use this constructor.
int length()
— Returns the number of characters in a String object
String substring(int from, int to)
— Returns the substring beginning at index from
and ending at index to − 1
String substring(int from)
— Equivalent to substring(from, length())
int indexOf(String str)
— Returns the index of the first occurrence of str; returns -1
if not found
boolean equals(Object other)
— Returns true
if other is a String and its text is the same as the text of the String
equals
was called on. Otherwise returns false
.13
int compareTo(String other)
— Returns a value < 0 if the String
is alphabetically less than other
; returns zero if it is equals
to other
; and returns a value > 0 if it is greater than other
.
A one-character String
at index i
in the String
s
can be obtained by calling s.substring(i, i + 1)
.
System
classSystem.out.print
and System.out.println
display information on the computer monitor.
System.out.println
moves the cursor to a new line after the information has been displayed, while System.out.print
does not.
Math
classThe Math
class is part of Java and is available in all Java programs.
The Math
class contains only static methods.
You should know how to use the methods Math.abs
, Math.pow
, Math.sqrt
, and Math.random
. (You should also know about the variable—not a method—Math.PI
whose value is the double value that best approximates the value of π.)
The following static Math methods—including what they do and when they are used—are part of the AP Java Quick Reference:
int abs(int x)
— Returns the absolute value of an int value
double abs(double x)
— Returns the absolute value of a double value
double pow(double base, double exponent)
— Returns the value of the first parameter raised to the power of the second parameter
double sqrt(double x)
— Returns the positive square root of a double value
double random()
— Returns a double value greater than or equal to 0.0 and less than 1.0.
Values returned from Math.random
are in the range 0.0 to 1.0 but can be manipulated to produce a random int or double in any desired range by scaling (multiplying) and shifting (adding).
The ArrayList
class is part of the java.util
package and needs to be imported to be used in a class.
An ArrayList
object is mutable and contains object references.
The no-argument ArrayList
constructor constructs an empty list.
Indices for an ArrayList
start at 0
and end at size() − 1
, inclusive.
Trying to access an index outside the valid range (e.g. with the get
, set
or remove
method) will cause an IndexOutOfBoundsException
to be thrown.
Changing the size of an ArrayList
while traversing it using an enhanced for
loop will cause a ConcurrentModificationException
to be thrown. When using an enhanced for
loop to traverse an ArrayList
, you should not add or remove elements.
ArrayList
is a generic type which means we can write the type ArrayList<E>
to mean an ArrayList
that can only contain values of the type E
. E.g. ArrayList<String>
is a list of String
s.
E
is called a “type parameter” because it is filled in with a specific type like String
. Type parameters have to be reference types.
When ArrayList<E>
is specified, the types of the parameters in methods that accept elements, e.g. add
, and the return types of methods that return elements, e.g. get
, will be E
.
The type ArrayList<E>
is preferred over the so-called “raw” type ArrayList
because it allows the compiler to find errors that would otherwise be found at run-time.
Typically you invoke the ArrayList
constructor as ArrayList<>()
, i.e. with nothing between the <>
s as the Java compiler will infer the correct element type.
Iteration statements can be used to access all the elements in an ArrayList
. This is called traversing the ArrayList
.
There are standard ArrayList
algorithms that utilize traversals to insert and delete elements.
Deleting elements during a traversal of an ArrayList
requires using special techniques to avoid skipping elements.
Most algorithms that work with arrays work equally well with ArrayList
s after switching .length
to .size()
and array accesses and assignments to get
and set
calls.
Some algorithms require multiple String
, array, or ArrayList
objects to be traversed simultaneously.
The following ArrayList
methods—including what they do and when they are used—are part of the AP Java Quick Reference:
int size()
— Returns the number of elements in the list
boolean add(E obj)
— Appends obj
to end of list; returns true
void add(int index, E obj)
— Inserts obj
at position index
which must be a valid index or the current size of the list, increasing the size of the list by one.
E get(int index)
— Returns the element at position index
in the list
E set(int index, E obj)
— Replaces the element at position index
with obj
; returns the element formerly at position index.
E remove(int index)
— Removes the element from position index
, moving elements at position index + 1
and higher to the left, and decreases the size of the list by one. Returns the element formerly at position index
.
The College Board is weirdly obsessed with wrapper classes.
The Integer
, Double
, and Boolean
classes exist primarily because generic types like ArrayList
can only use reference types as their type parameters. The wrapper classes exist to “wrap” a primitive value in an object so it can be put into an ArrayList
or used with another generic class.
In general you do not need to explicitly use wrapper classes because the Java compiler will automatically wrap a primitive type used in a context where its wrapper type is expected. This is called “autoboxing”. Conversely, if a wrapper type is used in a context where the corresponding primitive type is expected it will be automatically “unboxed” and converted to the primitive value.
You will almost never write code where you declare the type of a variable or parameter or the return type of a method to be one of the wrapper types; just use primitive types and let autoboxing take care of things.
Then one place you will have to use Integer
and Double
is when you declare an ArrayList
: You have to write ArrayList<Integer>
rather than ArrayList<int>
, ArrayList<Double>
rather than ArrayList<double>
and ArrayList<Boolean>
rather than ArrayList<boolean>
.
The following Integer
constructors, methods, and variables—including what they do and when they are used—are part of the AP Java Quick Reference:
Integer(int value)
— Constructs a new Integer object that represents the specified int value14. This is roughly equivalent to what happens when an int is autoboxed.
int intValue()
— Returns the value of an Integer as an int. This is equivalent to what happens when an Integer is unboxed.
Integer.MAX_VALUE
— The maximum value that can be represented by an int.
Integer.MIN_VALUE
— The minimum value that can be represented by an int.
The following Double
constructor and method—including what they do and when they are used—are part of the AP Java Quick Reference:
Double(double value)
— Constructs a new Double object that represents the specified double value15. This is roughly equivalent to what happens when a double is autoboxed.
double doubleValue()
— Returns the value of a Double as a double. This is equivalent to what happens when a Double is unboxed.
The College Board does not expect you to know about any methods from the Boolean
class.
We can compare algorithms informally by counting statement executions. For instance, sometimes it’s useful to analyze a loop to determine either exactly or approximately how many times it will execute its body. More rigorously we can characterize algorithms by how their run time grows as the size of the problem grows.
There are standard algorithms to:
Compute statistics about numbers in an array or ArrayList
such as the sum, average, minimum, and maximum value.
Determine if at least one element of an array or ArrayList
has a particular property
Determine if all elements of an array or ArrayList
have a particular property
Access all consecutive pairs of elements of an array or ArrayList
.
Determine the presence or absence of duplicate elements in an array or ArrayList
.
Determine the number of elements in an array or ArrayList
meeting specific criteria
Shift or rotate elements of an array or ArrayList
left or right.
Reverse the order of the elements of an array or ArrayList
.
Determine the frequency with which a specific criterion is met by elements within an array or ArrayList
Identify the individual digits in an integer
There are standard algorithms that utilize String
traversals to:
Find if one or more substrings has a particular property
Determine the number of substrings that meet specific criteria
Create a new String
with the characters reversed
Sequential/linear search algorithms check each element in order until the desired value is found or all elements in the array or ArrayList
have been checked. You should be able to write code that performs a linear search.
Binary search algorithms can search sorted lists much more efficiently than linear search, finding elements in log N time where N is the size of the list. You are unlikely to need to write a binary search yourself for the exam.
The binary search algorithm starts at the middle of a sorted array or ArrayList
and on average eliminates half of the elements in each iteration until the desired value is found or all elements have been eliminated.
The binary search algorithm can be written either iteratively or recursively.
Selection sort and insertion sort are iterative sorting algorithms that can be used to sort elements in an array or ArrayList. You should be able to recognize them but will not have to write them yourself.
Merge sort is a recursive sorting algorithm that can be used to sort elements in an array or ArrayList. You will not have to be able to write a merge sort.
A recursive method is a method that calls itself.16
Recursive methods contain at least one base case, which halts the recursion, and at least one recursive call.
Each recursive call has its own set of local variables, including its parameters.
Parameter values capture the progress of a recursive process, much like loop control variable values capture the progress of a loop.
Recursion can be used to traverse linear structures like String
s, arrays, and ArrayList
s but it is most useful for traversing tree structures which are difficult to traverse with simple loops.
Any recursive solution can be replicated through the use of an iterative approach. However some recursions, such as tree recursions, will require maintaining extra data structures to keep track of the information that would otherwise be managed by the process of recursion.
System reliability is limited. Programmers should make an effort to maximize system reliability.
Legal issues and intellectual property concerns arise when creating programs.
The creation of programs has impacts on society, economies, and culture. These impacts can be beneficial and/or harmful.
When using the computer, personal privacy is at risk. Programmers should attempt to safeguard personal privacy.
1 The AP curriculum does not touch on this but Casting a double
value outside the range that can be represented by an int
results in either Integer.MAX_VALUE
or Integer.MIN_VALUE
.
2 One way to remember the relative precedence is to note that if you think of boolean
s as a kind of numbers with false
analogous to 0 and true
analogous to 1, then !
is equivalent to a single negation as in -x
, which flips the sign of its value, &&
is analogous to multiplication since true && x
is x
for all boolean
x
just like 1 * x
is x
for all numeric x
and ||
is like addition since false || x
is x
for all boolean x
, just like 0 + x
is x
for all numeric x
.)
3 This can be useful when the second expression would not be safe to evaluate in some circumstances. For instance: s.length() >= 3 && s.substring(0, 3).equals(“abc”)
evaluates to false
if the string is less than three characters long without trying to extract a substring which would throw an exception if the string is not that long.
4 The equals
method is not an operator; just a method that returns a boolean
.
5 The AP curriculum does not cover it but these operators can also be used in prefix form, like ++x
in which case the value of the expression is the new value of the variable rather than the old value.
6 Technically, that’s not quite true; there are constructs that are not covered in the AP curriculum that allow us to guarantee that certain bits of code execute just before returning from a method.
7 It is legal but unusual to use an empty return
statement in a constructor. It can be used to exit from a constructor early but constructors do not return a value; they merely initialize the object that will be the value of the new expression that invoked the constructor.
8 There are other constructs, not covered in the AP curriculum for controlling loop behavior. A break
statement causes the current loop to exit immediately while a continue
statement causes the current loop to jump immediately to its next iteration.
9 Static methods can, like any code, access instance variables and invoke instance methods if they have a reference to an instance of a class such as by being passed one as an argument or having one stored in a static variable.
10 String objects can also be created by writing a literal string in your program. They are the only class that gets special treatment from the Java compiler. And autoboxing of primitive types can cause new instances of the wrapper types to be created without explicitly calling a constructor.
11 There are other access levels than public and private but they are not covered in the AP curriculum. Occasionally you will see a class with neither a public nor private modifier. One rule of Java is that there can be only one public class per .java file so if you have more than one top-level class in a file all but one of them will have to leave off the public modifier.
12 Correctly implementing an overridden version of equals
is actually surprisingly hard but how to do so is not part of the AP curriculum.
13 In the AP Java Quick Reference they list this method as boolean equals(String other)
. That is not correct but the difference doesn’t matter for anything on the exam.
14 The Integer constructor has been deprecated since Java 9. According to the Javadocs “It is rarely appropriate to use this constructor. The static factory valueOf(int)
is generally a better choice, as it is likely to yield significantly better space and time performance.”
15 The Double constructor has been deprecated since Java 9. According to the Javadocs: “It is rarely appropriate to use this constructor. The static factory valueOf(double)
is generally a better choice, as it is likely to yield significantly better space and time performance.”
16 Technically a method doesn’t have to call itself directly. There can also be “mutual recursions” where method a calls b which then calls a. But in the AP curriculum we are only concerned with simple one-method recursions.