Software I - EDV1

¡Supera tus tareas y exámenes ahora con Quizwiz!

Q: Given the following classes, which of the following can independently replace INSERT IMPORTS HERE to make the code compile? (Choose all that apply.) package aquarium; public class Tank {} package aquarium.jellies; public class Jelly {} package visitor; INSERT IMPORTS HERE public class AquariumVisitor { public void admire(Jelly jelly) {} } A. import aquarium.jellies.Jelly; B. import aquarium.jellies.*; C. import aquarium.jellies.Jelly.*; D. None of these can make the code compile. E. import aquarium.*; F. import aquarium.*.Jelly;

A. import aquarium.jellies.Jelly; B. import aquarium.jellies.*; Option A is correct because it imports Jelly by classname. Option B is correct because it imports all the classes in the jellies package, which includes Jelly. Option E is incorrect because it only imports classes in the aquarium package-Tank in this case-and not those in lower-level packages. Option F is incorrect because you cannot use wildcards anyplace other than the end of an import statement. Option C is incorrect because you cannot import parts of a class with a regular import statement. Option D is incorrect because options A and B do make the code compile.

Q: Given the following classes, which of the following can independently replace INSERT IMPORTS HERE to make the code compile? (Choose all that apply.) package aquarium; public class Tank {} package aquarium.jellies; public class Jelly {} package visitor; INSERT IMPORTS HERE public class AquariumVisitor { public void admire(Jelly jelly) {} } A. import aquarium.jellies.Jelly; B. import aquarium.jellies.*; C. import aquarium.jellies.Jelly.*; D. None of these can make the code compile. E. import aquarium.*; F. import aquarium.*.Jelly;

A. import aquarium.jellies.Jelly; B. import aquarium.jellies.*; Option A is correct because it imports Jelly by classname. Option B is correct because it imports all the classes in the jellies package, which includes Jelly. Option E is incorrect because it only imports classes in the aquarium package-Tank in this case-and not those in lower-level packages. Option F is incorrect because you cannot use wildcards anyplace other than the end of an import statement. Option C is incorrect because you cannot import parts of a class with a regular import statement. Option D is incorrect because options A and B do make the code compile.

Q: Which of the following are legal entry point methods that can be run from the command line? A. public static void main(String[] args) B. public static void test(String[] args) C. public void main(String[] args) D. public static final main(String[] args) E. private static void main(String[] args) F. None of these are correct. G. public static main(String[] args)

A. public static void main(String[] args) Option A is the canonical main() method signature. You need to memorize it. Option E is incorrect because the main() method must be public. Options D and G are incorrect because the main() method must have a void return type. Option C is incorrect because the main() method must be static. Option B is incorrect because the main() method must be named main.

Manipulating Dates and Times

Adding to a date is easy. The date and time classes are immutable, just like String was. This means that we need to remember to assign the results of these methods to a reference variable so they are not lost. LocalDate date = LocalDate.of(2014, Month.JANUARY, 20); System.out.println(date); // 2014-01-20 date = date.plusDays(2); System.out.println(date); // 2014-01-22 date = date.plusWeeks(1); System.out.println(date); // 2014-01-29 date = date.plusMonths(1); System.out.println(date); // 2014-02-28 date = date.plusYears(5); System.out.println(date); // 2019-02-28 This code is nice because it does just what it sounds like. We start out with January 20, 2014. On line 14, we add two days to it and reassign it to our reference variable. On line 16, we add a week. This method allows us to write clearer code than plusDays(7). Now date is January 29, 2014. On line 18, we add a month. This would bring us to February 29, 2014. However, 2014 is not a leap year. (2012 and 2016 are leap years.) Java is smart enough to realize February 29, 2014 does not exist and gives us February 28, 2014 instead. Finally, line 20 adds five years. There are also nice easy methods to go backward in time. This time, let's work with LocalDateTime. LocalDate date = LocalDate.of(2020, Month.JANUARY, 20); LocalTime time = LocalTime.of(5, 15); LocalDateTime dateTime = LocalDateTime.of(date, time); System.out.println(dateTime); // 2020-01-20T05:15 dateTime = dateTime.minusDays(1); System.out.println(dateTime); // 2020-01-19T05:15 dateTime = dateTime.minusHours(10); System.out.println(dateTime); // 2020-01-18T19:15 dateTime = dateTime.minusSeconds(30); System.out.println(dateTime); // 2020-01-18T19:14:30 Line 25 prints the original date of January 20, 2020 at 5:15 a.m. Line 26 subtracts a full day, bringing us to January 19, 2020 at 5:15 a.m. Line 28 subtracts 10 hours, showing that the date will change if the hours cause it to and brings us to January 18, 2020 at 19:15 (7:15 p.m.). Finally, line 30 subtracts 30 seconds. We see that all of a sudden the display value starts displaying seconds. Java is smart enough to hide the seconds and nanoseconds when we aren't using them. It is common for date and time methods to be chained. For example, without the print statements, the previous example could be rewritten as follows: LocalDate date = LocalDate.of(2020, Month.JANUARY, 20); LocalTime time = LocalTime.of(5, 15); LocalDateTime dateTime = LocalDateTime.of(date, time) .minusDays(1).minusHours(10).minusSeconds(30); When you have a lot of manipulations to make, this chaining comes in handy. There are two ways the exam creators can try to trick you. What do you think this prints? LocalDate date = LocalDate.of(2020, Month.JANUARY, 20); date.plusDays(10); System.out.println(date); It prints January 20, 2020. Adding 10 days was useless because we ignored the result. Whenever you see immutable types, pay attention to make sure the return value of a method call isn't ignored. The exam also may test to see if you remember what each of the date and time objects includes. Do you see what is wrong here? LocalDate date = LocalDate.of(2020, Month.JANUARY, 20); date = date.plusMinutes(1); // DOES NOT COMPILE LocalDate does not contain time. This means you cannot add minutes to it. This can be tricky in a chained sequence of additions/subtraction operations, so make sure you know which methods in Table 3.4 can be called on which of the three objects.

Parameter List

Although the parameter list is required, it doesn't have to contain any parameters. This means you can just have an empty pair of parentheses after the method name, such as void nap(){}. If you do have multiple parameters, you separate them with a comma. public void walk1() { } public void walk2 { } // DOES NOT COMPILE public void walk3(int a) { } public void walk4(int a; int b) { } // DOES NOT COMPILE public void walk5(int a, int b) { } walk1() is a valid method declaration without any parameters. walk2() doesn't compile because it is missing the parentheses around the parameter list. walk3() is a valid method declaration with one parameter. walk4() doesn't compile because the parameters are separated by a semicolon rather than a comma. Semicolons are for separating statements, not parameter lists. walk5() is a valid method declaration with two parameters.

Static vs. Instance

(Remember that "member" means field or method.) A static member cannot call an instance member. This shouldn't be a surprise since static doesn't require any instances of the class to be around

Access Modifiers

- public: The method can be called from any class. - private: The method can only be called from within the same class. - protected: The method can only be called from classes in the same package or subclasses. You'll learn about subclasses in Chapter 5. - Default (Package Private) Access: The method can only be called from classes in the same package. This one is tricky because there is no keyword for default access. You simply omit the access modifier. public void walk1() {} default void walk2() {} // DOES NOT COMPILE void public walk3() {} // DOES NOT COMPILE void walk4() {} walk1() is a valid method declaration with public access. walk4() is a valid method declaration with default access. walk2() doesn't compile because default is not a valid access modifier. walk3() doesn't compile because the access modifier is specified after the return type.

Optional Specifiers

- static: Covered later in this chapter. Used for class methods. - abstract: Covered in Chapter 5. Used when not providing a method body. - final: Covered in Chapter 5. Used when a method is not allowed to be overridden by a subclass. - synchronized: On the OCP but not the OCA exam. - native: Not on the OCA or OCP exam. Used when interacting with code written in another language such as C++. - strictfp: Not on the OCA or OCP exam. Used for making floating-point calculations portable. public void walk1() {} public final void walk2() {} public static final void walk3() {} public final static void walk4() {} public modifier void walk5() {} // DOES NOT COMPILE public void final walk6() {} // DOES NOT COMPILE final public void walk7() {} walk1() is a valid method declaration with no optional specifier. This is okay; it is optional, after all. walk2() is a valid method declaration, with final as the optional specifier. walk3() and walk4() are valid method declarations with both final and static as optional specifiers. The order of these two keywords doesn't matter. walk5() doesn't compile because modifier is not a valid optional specifier. walk6() doesn't compile because the optional specifier is after the return type. walk7() does compile. Java allows the optional specifiers to appear before the access modifier. This is a weird case and not one you need to know for the exam. We are mentioning it so you don't get confused when practicing.

Prefix

0b is the prefix for a binary value 0x is the prefix for a hexadecimal value (This value can be assigned to many primitive types, including int and double)

Order of Initialization

1. If there is a superclass, initialize it first. 2. Static variable declarations and static initializers in the order they appear in the file. 3. Instance variable declarations and instance initializers in the order they appear in the file. 4. The constructor. Let's try the first example: public class InitializationOrderSimple { private String name = "Torchie"; { System.out.println(name); } private static int COUNT = 0; static { System.out.println(COUNT); } static { COUNT += 10; System.out.println(COUNT); } public InitializationOrderSimple() { System.out.println("constructor"); } } public class CallInitializationOrderSimple { public static void main(String[] args) { InitializationOrderSimple init = new InitializationOrderSimple(); } } The output is: 0 10 Torchie constructor Let's look at why. Rule 1 doesn't apply because there is no superclass. Rule 2 says to run the static variable declarations and static initializers-in this case, lines 5 and 6, which output 0 and 10. Rule 3 says to run the instance variable declarations and instance initializers- here, lines 2 and 3, which output Torchie. Finally, rule 4 says to run the constructor- here, lines 7-9, which output constructor. The next example is a little harder. Keep in mind that the four rules apply only if an object is instantiated. If the class is referred to without a new call, only rules 1 and 2 apply. The other two rules relate to instances and constructors. They have to wait until there is code to instantiate the object. What do you think happens here? public class InitializationOrder { private String name = "Torchie"; { System.out.println(name); } private static int COUNT = 0; static { System.out.println(COUNT); } { COUNT++; System.out.println(COUNT); } public InitializationOrder() { System.out.println("constructor"); } public static void main(String[] args) { System.out.println("read to construct"); new InitializationOrder(); } } The output looks like this: 0 read to construct Torchie 1 constructor Again, rule 1 doesn't apply because there is no superclass. Rule 2 tells us to look at the static variables and static initializers-lines 4, 5 and 6, in that order. Line 5 outputs 0. Now that the statics are out of the way, the main() method can run. Next, we can use rule 3 to run the instance variables and instance initializers. Here that is lines 2 and 3, which output Torchie. Line 6 then outputs 1. Finally, rule 4 says to run the constructor-in this case, lines 7-9, which output constructor. We are going to try one more example. This one is as hard as it gets. If you understand the output of this next one, congratulations on a job well done; if not, don't worry. Write some programs to play with this. Try typing in the examples in this section and making minor changes to see what happens. For example, you might try commenting out part of the code. This will give you a better feel for what is going on. Then come back and reread this section to try the examples. Ready for the tough example? Here it is: public class YetMoreInitializationOrder { static { add(2); } static void add(int num) { System.out.print(num + " "); } YetMoreInitializationOrder() { add(5); } static { add(4); } { add(6); } static { new YetMoreInitializationOrder(); } { add(8); } public static void main(String[] args) { } } The correct answer is 2 4 6 8 5. Let's walk through why that is. There is no superclass, so we jump right to rule 2-the statics. There are three static blocks: on lines 2, 5, and 7. They run in that order. The static block on line 2 calls the add() method, which prints 2. The static block on line 5 calls the add() method, which prints 4. The last static block, on line 7, calls new to instantiate the object. This means we can go on to rule 3 to look at the instance variables and instance initializers. There are two of those: on lines 6 and 8. They both call the add() method and print 6 and 8, respectively. Finally, we go on to rule 4 and call the constructor, which calls the add() method one more time and prints 5. This example is tricky for a few reasons. There's a lot to keep track of. Also, the question has a lot of one-line code blocks and methods, making it harder to visualize which is a block. Luckily, questions like this are rare on the exam. If you see one, just write down what is going on as you read the code.

Numeric Promotion Rules

1. If two values have different data types, Java will automatically promote one of the values to the larger of the two data types. 2. If one of the values is integral and the other is floating-point, Java will automatically promote the integral value to the floating-point value's data type. 3. Smaller data types, namely byte, short, and char, are first promoted to int any time they're used with a Java binary arithmetic operator, even if neither of the operands is int. 4. After all promotion has occurred and the operands have the same data type, the resulting value will have the same data type as its promoted operands. The last two rules are the ones most people have trouble with, and the ones likely to trip you up on the exam. For the third rule, note that unary operators are excluded from this rule. For example, applying ++ to a short value results in a short value. We'll discuss unary operators in the next section.

Q: What is the output of the following program? public class WaterBottle { private String brand; private boolean empty; public static void main(String[] args) { WaterBottle wb = new WaterBottle(); System.out.print("Empty = " + wb.empty); System.out.print(", Brand = " + wb.brand); } } A Empty = false, Brand = null B There is no output. C Line 7 generates a compiler error. D Line 6 generates a compiler error. E Empty = null, Brand = null F Empty = false, Brand =

A Empty = false, Brand = null Boolean fields initialize to false and references initialize to null, so empty is false and brand is null. Brand = null is output.

Q: Which of the following are true? (Choose all that apply.) 4: short numPets = 5; 5: int numGrains = 5.6; 6: String name = "Scruffy"; 7: numPets.length(); 8: numGrains.length(); 9: name.length(); A Line 7 generates a compiler error. B Line 8 generates a compiler error. C Line 9 generates a compiler error. D The code compiles as is. E Line 4 generates a compiler error. F Line 5 generates a compiler error. G Line 6 generates a compiler error.

A Line 7 generates a compiler error. B Line 8 generates a compiler error. F Line 5 generates a compiler error. Option E (line 4) compiles because short is an integral type. Option F (line 5) generates a compiler error because int is an integral type, but 5.6 is a floating-point type. Option G (line 6) compiles because it is assigned a String. Options A and B (lines 7 and 8) do not compile because short and int are primitives. Primitives do not allow methods to be called on them. Option C (line 9) compiles because length() is defined on String.

Hiding Static Methods

A hidden method occurs when a child class defines a static method with the same name and signature as a static method defined in a parent class. Method hiding is similar but not exactly the same as method overriding. First, the four previous rules for overriding a method must be followed when a method is hidden. In addition, a new rule is added for hiding a method, namely that the usage of the static keyword must be the same between parent and child classes. The following list summarizes the five rules for hiding a method: The method in the child class must have the same signature as the method in the parent class. The method in the child class must be at least as accessible or more accessible than the method in the parent class. The method in the child class may not throw a checked exception that is new or broader than the class of any exception thrown in the parent class method. If the method returns a value, it must be the same or a subclass of the method in the parent class, known as covariant return types. The method defined in the child class must be marked as static if it is marked as static in the parent class (method hiding). Likewise, the method must not be marked as static in the child class if it is not marked as static in the parent class (method overriding). Note that the first four are the same as the rules for overriding a method. Let's review some examples of the new rule: public class Bear { public static void eat() { System.out.println("Bear is eating"); } } public class Panda extends Bear { public static void eat() { System.out.println("Panda bear is chewing"); } public static void main(String[] args) { Panda.eat(); } } In this example, the code compiles and runs without issue. The eat() method in the child class hides the eat() method in the parent class. Because they are both marked as static, this is not considered an overridden method. Let's contrast this with examples that violate the fifth rule: public class Bear { public static void sneeze() { System.out.println("Bear is sneezing"); } public void hibernate() { System.out.println("Bear is hibernating"); } } public class Panda extends Bear { public void sneeze() { // DOES NOT COMPILE System.out.println("Panda bear sneezes quietly"); } public static void hibernate() { // DOES NOT COMPILE System.out.println("Panda bear is going to sleep"); } } In this example, sneeze() is marked as static in the parent class but not in the child class. The compiler detects that you're trying to override a method that should be hidden and generates a compiler error. In the second method, hibernate() is an instance member in the parent class but a static method in the child class. In this scenario, the compiler thinks that you're trying to hide a method that should be overridden and also generates a compiler error. Note As you saw in the previous example, hiding static methods is fraught with pitfalls and potential problems and as a practice should be avoided. Though you might see questions on the exam that contain hidden static methods that are syntactically correct, avoid hiding static methods in your own work, since it tends to lead to confusing and difficult-to-read code. You should not reuse the name of a static method in your class if it is already used in the parent class.

lambda expression

A lambda expression is a block of code with parameters that you can pass so it can be executed later. It allows functionality to be passed as argument to a method and helps us avoid unnecessary syntax. You can think of a lambda expression as an anonymous method. It has parameters and a body just like full-fledged methods do, but it doesn't have a name like a real method. Lambda expressions are often referred to as lambdas for short. Lambda Syntax a -> a.canHop(); The syntax of lambdas is tricky because many parts are optional. These two lines do the exact same thing: a -> a.canHop(); (Animal a) -> { return a.canHop(); } Let's look at what is going on here. The first example, shown in Figure 4.5, has three parts: Specify a single parameter with the name a The arrow operator to separate the parameter and body A body that calls a single method and returns the result of that method The second example also has three parts; it's just more verbose (see Figure 4.6): Specify a single parameter with the name a and stating the type is Animal The arrow operator to separate the parameter and body A body that has one or more lines of code, including a semicolon and a return statement The parentheses can only be omitted if there is a single parameter and its type is not explicitly stated. Java does this because developers commonly use lambda expressions this way and they can do as little typing as possible. It shouldn't be news to you that we can omit braces when we only have a single statement. We did this with if statements and loops already. What is different here is that the rules change when you omit the braces. Java doesn't require you to type return or use a semicolon when no braces are used. This special shortcut doesn't work when we have two or more statements. At least this is consistent with using {} to create blocks of code elsewhere. Let's look at some examples of valid lambdas. Pretend that there are valid interfaces that can consume a lambda with zero, one, or two String parameters. print(() -> true); // 0 parameters print(a -> a.startsWith("test")); // 1 parameter print((String a) -> a.startsWith("test")); // 1 parameter print((a, b) -> a.startsWith("test")); // 2 parameters print((String a, String b) -> a.startsWith("test")); // 2 parameters Notice that all of these examples have parentheses around the parameter list except the one that takes only one parameter and doesn't specify the type. Line 3 takes 0 parameters and always returns the Boolean true. Line 4 takes one parameter and calls a method on it, returning the result. Line 5 does the same except that it explicitly defines the type of the variable. Lines 6 and 7 take two parameters and ignore one of them-there isn't a rule that says you must use all defined parameters. Now let's make sure you can identify invalid syntax. Do you see what's wrong with each of these? print(a, b -> a.startsWith("test")); // DOES NOT COMPILE print(a -> { a.startsWith("test"); }); // DOES NOT COMPILE print(a -> { return a.startsWith("test") }); // DOES NOT COMPILE The first line needs parentheses around the parameter list. Remember that the parentheses are only optional when there is one parameter and it doesn't have a type declared. The second line is missing the return keyword. The last line is missing the semicolon. You might have noticed all of our lambdas return a boolean. That is because the scope for the OCA exam limits what you need to learn. The trick is that they cannot access all variables. Instance and static variables are okay. Method parameters and local variables are fine if they are not assigned new values. There is one more issue you might see with lambdas. We've been defining an argument list in our lambda expressions. Since Java doesn't allow us to redeclare a local variable, the following is an issue: (a, b) -> { int a = 0; return 5;} // DOES NOT COMPILE We tried to redeclare a, which is not allowed. By contrast, the following line is okay because it uses a different variable name: (a, b) -> { int c = 0; return 5;} Lambdas work with interfaces that have only one method. These are called functional interfaces-interfaces that can be used with functional programming. (It's actually more complicated than this, but for the OCA exam this definition is fine.) You can imagine that we'd have to create lots of interfaces like this to use lambdas. We want to test Animals and Strings and Plants and anything else that we come across. Luckily, Java recognizes that this is a common problem and provides such an interface for us. It's in the package java.util.function and the gist of it is as follows: public interface Predicate<T> { boolean test(T t); } That looks a lot like our method. The only difference is that it uses this type T instead of Animal. That's the syntax for generics. It's like when we created an ArrayList and got to specify any type that goes in it. This means we don't need our own interface anymore and can put everything related to our search in one class: import java.util.*; import java.util.function.*; public class PredicateSearch { public static void main(String[] args) { List<Animal> animals = new ArrayList<Animal>(); animals.add(new Animal("fish", false, true)); print(animals, a -> a.canHop()); } private static void print(List<Animal> animals, Predicate<Animal> ↵ checker) { for (Animal animal : animals) { if (checker.test(animal)) System.out.print(animal + " "); } System.out.println(); } } This time, line 10 is the only one that changed. We expect to have a Predicate passed in that uses type Animal. Pretty cool. We can just use it without having to write extra code. Java 8 even integrated the Predicate interface into some existing classes. There is only one you need to know for the exam. ArrayList declares a removeIf() method that takes a Predicate. Imagine we have a list of names for pet bunnies. We decide we want to remove all of the bunny names that don't begin with the letter h because our little cousin really wants us to choose an H name. We could solve this problem by writing a loop. Or we could solve it in one line: List<String> bunnies = new ArrayList<>(); bunnies.add("long ear"); bunnies.add("floppy"); bunnies.add("hoppy"); System.out.println(bunnies); // [long ear, floppy, hoppy] bunnies.removeIf(s -> s.charAt(0) != 'h'); System.out.println(bunnies); // [hoppy] Line 8 takes care of everything for us. It defines a predicate that takes a String and returns a boolean. The removeIf() method does the rest. For the OCA exam, you only need to know how to implement lambda expressions that use the Predicate interface. Remember the one method in the interface called test()? It takes any one reference type parameter and returns a boolean. Functional programming is a large topic and just the basics are covered. On the OCP exam, you'll learn how to get rid of the loop entirely for more than just removeIf(). You'll also learn the rules for implementing your own functional interfaces as we did with CheckTrait.

Method Body

A method body is simply a code block. It has braces that contain zero or more Java statements. public void walk1() { } public void walk2(); // DOES NOT COMPILE public void walk3(int a) { int name = 5; } walk1() is a valid method declaration with an empty method body. walk2() doesn't compile because it is missing the braces around the empty method body. walk3() is a valid method declaration with one statement in the method body.

A value is assigned to a reference in one of two ways:

A reference can be assigned to another object of the same type. A reference can be assigned to a new object using the new keyword.

Be able to identify correct and incorrect method declarations.

A sample method signature is public static void method(String... args) throws Exception {}.

switch Statement

A switch statement, as shown in Figure 2.4, is a complex decision-making structure in which a single value is evaluated and flow is redirected to the first matching branch, known as a case statement. If no such case statement is found that matches the value, an optional default statement will be called. If no such default option is available, the entire switch statement will be skipped. Data types supported by switch statements include the following: int and Integer byte and Byte short and Short char and Character String enum values Note that Boolean and long, and their associated wrapper classes, are not supported by switch statements.https://s3.amazonaws.com/jigyaasa_content_static/1Z0-808/ch2/img5.png

Q: Given the following class, which of the following is true? (Choose all that apply.) public class Snake { public void shed(boolean time) { if (time) { } System.out.println(result); } } A. If String result = "done"; is inserted on line 4, the code will compile. B. If String result = "done"; is inserted on line 6, the code will compile. C. If String result = "done"; is inserted on line 9, the code will compile. D. None of these changes will make the code compile. E. If String result = "done"; is inserted on line 2, the code will compile.

A. If String result = "done"; is inserted on line 4, the code will compile. E. If String result = "done"; is inserted on line 2, the code will compile. Adding the variable at line 2 makes result an instance variable. Since instance variables are in scope for the entire life of the object, option E is correct. Option A is correct because adding the variable at line 4 makes result a local variable with a scope of the whole method. Adding the variable at line 6 makes result a local variable with a scope of lines 6-7. Since it is out of scope on line 8, the println does not compile and option B is incorrect. Adding the variable at line 9 makes result a local variable with a scope of lines 9 and 10. Since line 8 is before the declaration, it does not compile and option C is incorrect. Finally, option D is incorrect because the code can be made to compile.

Applying Class Access Modifiers

As discussed in Chapter 4, you can apply access modifiers (public, private, protected, default) to both class methods and variables. It probably comes as no surprise that you can also apply access modifiers to class definitions, since we have been adding the public access modifier to nearly every class up to now. Note For the OCA exam, you should only be familiar with public and default package-level class access modifiers, because these are the only ones that can be applied to top-level classes within a Java file. The protected and private modifiers can only be applied to inner classes, which are classes that are defined within other classes, but this is well out of scope for the OCA exam. The public access modifier applied to a class indicates that it can be referenced and used in any class. The default package private modifier, which is the lack of any access modifier, indicates the class can be accessed only by a subclass or class within the same package. As you know, a Java file can have many classes but at most one public class. In fact, it may have no public class at all. One feature of using the default package private modifier is that you can define many classes within the same Java file. For example, the following definition could appear in a single Java file named Groundhog.java, since it contains only one public class: class Rodent {} public class Groundhog extends Rodent {} If we were to update the Rodent class with the public access modifier, the Groundhog.java file would not compile unless the Rodent class was moved to its own Rodent.java file. The rules for applying class access modifiers are identical for interfaces. There can be at most one public class or interface in a Java file. Like classes, top-level interfaces can also be declared with the public or default modifiers. We'll discuss interfaces in detail later in this chapter.

Defining Constructors

As you may recall from Chapter 4, every class has at least one constructor. In the case that no constructor is declared, the compiler will automatically insert a default no-argument constructor. In the case of extending a class, though, things are a bit more interesting. In Java, the first statement of every constructor is either a call to another constructor within the class, using this(), or a call to a constructor in the direct parent class, using super(). If a parent constructor takes arguments, the super constructor would also take arguments. For simplicity in this section, we refer to the super() command as any parent constructor, even those that take an argument. Notice the use of both super() and super(age) in the following example: public class Animal { private int age; public Animal(int age) { super(); this.age = age; } } public class Zebra extends Animal { public Zebra(int age) { super(age); } public Zebra() { this(4); } } In the first class, Animal, the first statement of the constructor is a call to the parent constructor defined in java.lang.Object, which takes no arguments. In the second class, Zebra, the first statement of the first constructor is a call to Animal's constructor, which takes a single argument. The class Zebra also includes a second no-argument constructor that doesn't call super() but instead calls the other constructor within the Zebra class using this(4). Like the this() command that you saw in Chapter 4, the super() command may only be used as the first statement of the constructor. For example, the following two class definitions will not compile: public class Zoo { public Zoo() { System.out.println("Zoo created"); super(); // DOES NOT COMPILE } } public class Zoo { public Zoo() { super(); System.out.println("Zoo created"); super(); // DOES NOT COMPILE } } The first class will not compile because the call to the parent constructor must be the first statement of the constructor, not the second statement. In the second code snippet, super() is the first statement of the constructor, but it also used as the third statement. Since super() can only be used as the first statement of the constructor, the code will likewise not compile. If the parent class has more than one constructor, the child class may use any valid parent constructor in its definition, as shown in the following example: public class Animal { private int age; private String name; public Animal(int age, String name) { super(); this.age = age; this.name = name; } public Animal(int age) { super(); this.age = age; this.name = null; } } public class Gorilla extends Animal { public Gorilla(int age) { super(age,"Gorilla"); } public Gorilla() { super(5); } } In this example, the first child constructor takes one argument, age, and calls the parent constructor, which takes two arguments, age and name. The second child constructor takes no arguments, and it calls the parent constructor, which takes one argument, age. In this example, notice that the child constructors are not required to call matching parent constructors. Any valid parent constructor is acceptable as long as the appropriate input parameters to the parent constructor are provided.

Final Fields

As you saw earlier in the chapter, final instance variables must be assigned a value exactly once. We saw this happen in the line of the declaration and in an instance initializer. There is one more location this assignment can be done: in the constructor. public class MouseHouse { private final int volume; private final String name = "The Mouse House"; public MouseHouse(int length, int width, int height) { volume = length * width * height; } } The constructor is part of the initialization process, so it is allowed to assign final instance variables in it. By the time the constructor completes, all final instance variables must have been set.

Inheriting Variables

As you saw with method overriding, there were a lot of rules when two methods have the same signature and are defined in both the parent and child classes. Luckily, the rules for variables with the same name in the parent and child classes are a lot simpler, because Java doesn't allow variables to be overridden but instead hidden.

Q: Given the following class in the file /my/directory/named/A/Bird.java: INSERT CODE HERE public class Bird { } Which of the following replaces INSERT CODE HERE if we compile from /my/directory? (Choose all that apply.) A package named.a; B package named.A; C package a; D package A; E Does not compile. F package my.directory.named.a; G package my.directory.named.A;

B package named.A; D package A; G package my.directory.named.A;

Q: Suppose we have a class named Rabbit. Which of the following statements are true? (Choose all that apply.) public class Rabbit { public static void main(String[] args) { Rabbit one = new Rabbit(); Rabbit two = new Rabbit(); Rabbit three = one; one = null; Rabbit four = one; three = null; two = null; two = new Rabbit(); System.gc(); } } A. The Rabbit object from line 3 is first eligible for garbage collection immediately following line 6. B. The Rabbit object from line 3 is first eligible for garbage collection immediately following line 8. C. The Rabbit object from line 3 is first eligible for garbage collection immediately following line 12. D. The Rabbit object from line 4 is first eligible for garbage collection immediately following line 9. E. The Rabbit object from line 4 is first eligible for garbage collection immediately following line 11. F. The Rabbit object from line 4 is first eligible for garbage collection immediately following line 12.

B. The Rabbit object from line 3 is first eligible for garbage collection immediately following line 8. D. The Rabbit object from line 4 is first eligible for garbage collection immediately following line 9. The Rabbit object from line 3 has two references to it: one and three. The references are nulled out on lines 6 and 8, respectively. Option B is correct because this makes the object eligible for garbage collection after line 8. Line 7 sets the reference four to the now null one, which means it has no effect on garbage collection. The Rabbit object from line 4 only has a single reference to it: two. Option D is correct because this single reference becomes null on line 9. The Rabbit object declared on line 10 becomes eligible for garbage collection at the end of the method on line 12. Calling System.gc() has no effect on eligibility for garbage collection.

Q: Which represent the order in which the following statements can be assembled into a program that will compile successfully? (Choose all that apply.) A: class Rabbit {} B: import java.util.*; C: package animals; A. A, B B. A, C C. C, A D. B, A E. C, B, A F. B, C, A G.A, B, C

C. C, A D. B, A E. C, B, A package and import are both optional. If both are present, the order must be package, then import, then class. Option G is incorrect because class is before package and import. Option F is incorrect because import is before package. Option B is incorrect because class is before package. Option A is incorrect because class is before import.

static imports.

Can you figure out what is wrong with each one? import static java.util.Arrays; // DOES NOT COMPILE import static java.util.Arrays.asList; static import java.util.Arrays.*; // DOES NOT COMPILE public class BadStaticImports { public static void main(String[] args) { Arrays.asList("one"); // DOES NOT COMPILE } } Line 1 tries to use a static import to import a class. Remember that static imports are only for importing static members. Regular imports are for importing a class. Line 3 tries to see if you are paying attention to the order of keywords. The syntax is import static and not vice versa. Line 6 is sneaky. We imported the asList method on line 2. However, we did not import the Arrays class anywhere. This makes it okay to write asList("one"); but not Arrays.asList("one");.

compound assignment operators

Complex operators are really just glorified forms of the simple assignment operator, with a built-in arithmetic or logical operation that applies the left- and right-hand sides of the statement and stores the resulting value in a variable in the left-hand side of the statement. ex: "y *= x;"

Reviewing Constructor Rules

Constructor Definition Rules: 1. The first statement of every constructor is a call to another constructor within the class using this(), or a call to a constructor in the direct parent class using super(). 2. The super() call may not be used after the first statement of the constructor. 3. If no super() call is declared in a constructor, Java will insert a no-argument super() as the first statement of the constructor. 4. If the parent doesn't have a no-argument constructor and the child doesn't define any constructors, the compiler will throw an error and try to insert a default no-argument constructor into the child class. 5 If the parent doesn't have a no-argument constructor, the compiler requires an explicit call to a parent constructor in each child constructor. Make sure you understand these rules; the exam will often provide code that breaks one or many of these rules and therefore doesn't compile.

Constructor \ instantiation

Constructors are used when creating a new object. This process is called instantiation because it creates a new instance of the class. A constructor is called when we write new followed by the name of the class we want to instantiate. For example: new Bunny() When Java sees the new keyword, it allocates memory for the new object. Java also looks for a constructor and calls it. A constructor is typically used to initialize instance variables. The this keyword tells Java you want to reference an instance variable. Most of the time, this is optional. The problem is that sometimes there are two variables with the same name. In a constructor, one is a parameter and one is an instance variable. If you don't say otherwise, Java gives you the one with the most granular scope, which is the parameter. Using this.name tells Java you want the instance variable. Here's a common way of writing a constructor: public class Bunny { private String color; public Bunny(String color) { this.color = color; } } On line 4, we assign the parameter color to the instance variable color. The right side of the assignment refers to the parameter because we don't specify anything special. The left side of the assignment uses this to tell Java we want it to use the instance variable. Now let's look at some examples that aren't common but that you might see on the exam: 1 public class Bunny { 2 private String color; 3 private int height; 4 private int length; 5 public Bunny(int length, int theHeight) { 6 length = this.length; // backwards - no good! 7 height = theHeight; // fine because a different name 8 this.color = "white"; // fine, but redundant 9 } 10 public static void main(String[] args) { 11 Bunny b = new Bunny(1, 2); 12 System.out.println(b.length + " " + b.height + " " + b.color); 13 } } Line 6 is incorrect and you should watch for it on the exam. The instance variable length starts out with a 0 value. That 0 is assigned to the method parameter length. The instance variable stays at 0. Line 7 is more straightforward. The parameter theHeight and instance variable height have different names. Since there is no naming collision, this is not required. Finally, line 8 shows that it is allowed to use this even when there is no duplication of variable names. In this section, we'll look at default constructors, overloading constructors, final fields, and the order of initialization in a class.

Evaluate code involving constructors

Constructors can call other constructors by calling this() as the first line of the constructor. Recognize when the default constructor is provided. Remember the order of initialization is the superclass, static variables/initializers, instance variables/initializers, and the constructor.

Q: Which of the following are true? (Choose all that apply.) public class Bunny { public static void main(String[] args) { Bunny bun = new Bunny(); } } A. Bunny is a reference to an object. B. main is a class. C. bun is a class. D. Bunny is a class. E. None of these. F. main is a reference to an object. G. bun is a reference to an object.

D. Bunny is a class. G. bun is a reference to an object. Bunny is a class, which can be seen from the declaration: public class Bunny. bun is a reference to an object. main() is a method.

Given the following classes, what is the maximum number of imports that can be removed and have the code still compile? package aquarium; public class Water {} package aquarium; import java.lang.*; import java.lang.System; import aquarium.Water; import aquarium.*; public class Tank { public void print(Water water) { System.out.println(water); } } A. 2 B. 1 C. 0 D. Does not compile. E. 4 F. 3

E. 4 The first two imports can be removed because java.lang is automatically imported. The second two imports can be removed because Tank and Water are in the same package, making the correct answer E. If Tank and Water were in different packages, one of these two imports could be removed. In that case, the answer would be option F.

Creating Immutable Classes

Encapsulating data is helpful because it prevents callers from making uncontrolled changes to your class. Another common technique is making classes immutable so they cannot be changed at all.

fundamental concepts of object-oriented programming:

Encapsulation - Combining data and associated functions as a single unit. It is also referred to as data hiding. Inheritance - A reusability mechanism of acquiring features and behaviors of a class by another class. Information is made manageable in a hierarchical order in inheritance. Abstraction - Hiding lower-level details and exposing only essential and relevant details to users. It refers to the ability to make a class abstract in OOP. Polymorphism - Ability of an object to take on many forms.

Encapsulation & Methods overview

Encapsulation means we set up the class so only methods in the class with the variables can refer to the instance variables. Callers are required to use these methods. Let's take a look at our newly encapsulated Swan class: public class Swan { private int numberEggs; // private public int getNumberEggs() { // getter return numberEggs; } public void setNumberEggs(int numberEggs) { // setter if (numberEggs >= 0) // guard condition this.numberEggs = numberEggs; } } Note numberEggs is now private on line 2. This means on s ly code within the class can read or write the value of numberEggs. Since we wrote the class, we know better than to set a negative number of eggs. We added a method on lines 3-5 to read the value, which is called an accessor method or a getter. We also added a method on lines 6-9 to update the value, which is called a mutator method or a setter. The setter has an if statement in this example to prevent setting the instance variable to an invalid value. This guard condition protects the instance variable. On line 8, we used the this keyword that we saw in constructors to differentiate between the method parameter numberEggs and the instance variable numberEggs. For encapsulation, remember that data (an instance variable) is private and getters/setters are public. Java defines a naming convention that is used in JavaBeans. JavaBeans are reusable software components. JavaBeans call an instance variable a property. The only thing you need to know about JavaBeans for the exam is the naming conventions listed in Table 4.5. From the last example in Table 4.5, you noticed that you can name the method parameter to set anything you want. Only the method name and property name have naming conventions here. It's time for some practice. See if you can figure out which lines follow JavaBeans naming conventions: private boolean playing; private String name; public boolean getPlaying() { return playing; } public boolean isPlaying() { return playing; } public String name() { return name; } public void updateName(String n) { name = n; } public void setname(String n) { name = n; } Lines 12 and 13 are good. They are private instance variables. Line 14 doesn't follow the JavaBeans naming conventions. Since playing is a boolean, the getter must begin with is. Line 15 is a correct getter for playing. Line 16 doesn't follow the JavaBeans naming conventions because it should be called getName. Lines 17 and 18 do not follow the JavaBeans naming conventions because they should be named setName. Remember that Java is case sensitive, so setname is not adequate to meet the naming convention.

Default Constructor

Every class in Java has a constructor whether you code one or not. If you don't include any constructors in the class, Java will create one for you without any parameters. This Java-created constructor is called the default constructor. Sometimes we call it the default no-arguments constructor for clarity. Here's an example: public class Rabbit { public static void main(String[] args) { Rabbit rabbit = new Rabbit(); // Calls default constructor } } In the Rabbit class, Java sees no constructor was coded and creates one. This default constructor is equivalent to typing this: public Rabbit() {} The default constructor has an empty parameter list and an empty body. It is fine for you to type this in yourself. However, since it doesn't do anything, Java is happy to supply it for you and save you some typing. We keep saying generated. This happens during the compile step. If you look at the file with the .java extension, the constructor will still be missing. It is only in the compiled file with the. class extension that it makes an appearance. Remember that a default constructor is only supplied if there are no constructors present. Which of these classes do you think has a default constructor? class Rabbit1 { } class Rabbit2 { public Rabbit2() { } } class Rabbit3 { public Rabbit3(boolean b) { } } class Rabbit4 { private Rabbit4() { } } Only Rabbit1 gets a default no-argument constructor. It doesn't have a constructor coded so Java generates a default no-argument constructor. Rabbit2 and Rabbit3 both have public constructors already. Rabbit4 has a private constructor. Since these three classes have a constructor defined, the default no-argument constructor is not inserted for you. Let's take a quick look at how to call these constructors: 1 public class RabbitsMultiply { 2 public static void main(String[] args) { 3 Rabbit1 r1 = new Rabbit1(); 4 Rabbit2 r2 = new Rabbit2(); 5 Rabbit3 r3 = new Rabbit3(true); 6 Rabbit4 r4 = new Rabbit4(); // DOES NOT COMPILE } } Line 3 calls the generated default no-argument constructor. Lines 4 and 5 call the user-provided constructors. Line 6 does not compile. Rabbit4 made the constructor private so that other classes could not call it. Having a private constructor in a class tells the compiler not to provide a default noargument constructor. It also prevents other classes from instantiating the class. This is useful when a class only has static methods or the class wants to control all calls to create new instances of itself.

Recognize the correct overloaded method.

Exact matches are used first, followed by wider primitives, followed by autoboxing, followed by varargs. Assigning new values to method parameters does not change the caller, but calling methods on them does.

Order of Initialization

Fields and instance initializer blocks are run in the order in which they appear in the file. The constructor runs after all fields and instance initializer blocks have run. What do you think this code prints out? public class Egg { public Egg() { number = 5; } public static void main(String[] args) { Egg egg = new Egg(); System.out.println(egg.number); } private int number = 3; { number = 4; } } If you answered 5, you got it right. Fields and blocks are run first in order, setting number to 3 and then 4. Then the constructor runs, setting number to 5.

State the output of code involving methods.

Identify when to call static rather than instance methods based on whether the classname or object comes before the method.

Extending a Class

In Java, you can extend a class by adding the parent class name in the definition using the extends keyword. Because Java allows only one public class per file, we can create two files, Animal.java and Lion.java, in which the Lion class extends the Animal class. Assuming they are in the same package, an import statement is not required in Lion.java to access the Animal class. Here are the contents of Animal.java: public class Animal { private int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } } And here are the contents of Lion.java: public class Lion extends Animal { private void roar() { System.out.println("The "+getAge()+" year old lion says: Roar!"); } } Notice the use of the extends keyword in Lion.java to indicate that the Lion class extends from the Animal class. In this example, we see that getAge() and setAge() are accessible by subclass Lion, because they are marked as public in the parent class. The primitive age is marked as private and therefore not accessible from the subclass Lion, as the following would not compile: public class Lion extends Animal { private void roar() { System.out.println("The "+age+" year old lion says: Roar!"); // DOES NOT COMPILE } } Despite the fact that age is inaccessible by the child class, if we have an instance of a Lion object, there is still an age value that exists within the instance. The age value just cannot be directly referenced by the child class nor any instance of the class. In this manner, the Lion object is actually "bigger" than the Animal object in the sense that it includes all the properties of the Animal object (although not all of those properties may be directly accessible) along with its own set of Lion attributes.

Overriding vs. Hiding Methods

In our description of hiding of static methods, we indicated there was a distinction between overriding and hiding methods. Unlike overriding a method, in which a child method replaces the parent method in calls defined in both the parent and child, hidden methods only replace parent methods in the calls defined in the child class. At runtime the child version of an overridden method is always executed for an instance regardless of whether the method call is defined in a parent or child class method. In this manner, the parent method is never used unless an explicit call to the parent method is referenced, using the syntax ParentClassName.method(). Alternatively, at runtime the parent version of a hidden method is always executed if the call to the method is defined in the parent class. Let's take a look at an example: public class Marsupial { public static boolean isBiped() { return false; } public void getMarsupialDescription() { System.out.println("Marsupial walks on two legs: "+isBiped()); } } public class Kangaroo extends Marsupial { public static boolean isBiped() { return true; } public void getKangarooDescription() { System.out.println("Kangaroo hops on two legs: "+isBiped()); } public static void main(String[] args) { Kangaroo joey = new Kangaroo(); joey.getMarsupialDescription(); joey.getKangarooDescription(); } } In this example, the code compiles and runs without issue, outputting the following: Marsupial walks on two legs: false Kangaroo hops on two legs: true Notice that isBiped() returns false in the parent class and true in the child class. In the first method call, the parent method getMarsupialDescription() is used. The Marsupial class only knows about isBiped() from its own class definition, so it outputs false. In the second method call, the child executes a method of isBiped(), which hides the parent method's version and returns true. Contrast this first example with the following example, which uses an overridden version of isBiped() instead of a hidden version: class Marsupial { public boolean isBiped() { return false; } public void getMarsupialDescription() { System.out.println("Marsupial walks on two legs: "+isBiped()); } } public class Kangaroo extends Marsupial { public boolean isBiped() { return true; } public void getKangarooDescription() { System.out.println("Kangaroo hops on two legs: "+isBiped()); } public static void main(String[] args) { Kangaroo joey = new Kangaroo(); joey.getMarsupialDescription(); joey.getKangarooDescription(); } } This code also compiles and runs without issue, but it outputs slightly different text: Marsupial walks on two legs: true Kangaroo hops on two legs: true In this example, the isBiped() method is overridden, not hidden, in the child class. Therefore, it is replaced at runtime in the parent class with the call to the child class's method. Make sure you understand these examples as they show how hidden and overridden methods are fundamentally different. This example makes uses of polymorphism, which we'll discuss later in this chapter.

Increment and Decrement Operators

Increment and decrement operators, ++ and --, respectively, can be applied to numeric operands and have the higher order or precedence, as compared to binary operators. In other words, they often get applied first to an expression. ex> int counter = 0; System.out.println(counter); // Outputs 0 System.out.println(++counter); // Outputs 1 System.out.println(counter); // Outputs 1 System.out.println(counter--); // Outputs 1 System.out.println(counter); // Outputs 0

Inheriting Methods

Inheriting a class grants us access to the public and protected members of the parent class, but also sets the stage for collisions between methods defined in both the parent class and the subclass. In this section, we'll review the rules for method inheritance and how Java handles such scenarios.

finalize()

Java allows objects to implement a method called finalize() that might get called. This method gets called if the garbage collector tries to collect the object. Remember, finalize() is only run when the object is eligible for garbage collection. finalize() call could run zero or one time.

Binary search rules

Java also provides a convenient way to search-but only if the array is already sorted. The exam creators will not expect you to know what incorrect values come out. As soon as you see the array isn't sorted, look for an answer choice about unpredictable output.

Summary

Java begins program execution with a main() method. The most common signature for this method run from the command line is public static void main(String[] args). Arguments are passed in after the class name, as in java NameOfClass firstArgument. Arguments are indexed starting with 0. Java code is organized into folders called packages. To reference classes in other packages, you use an import statement. A wildcard ending an import statement means you want to import all classes in that package. It does not include packages that are inside that one. java.lang is a special package that does not need to be imported. Constructors create Java objects. A constructor is a method matching the class name and omitting the return type. When an object is instantiated, fields and blocks of code are initialized first. Then the constructor is run. Primitive types are the basic building blocks of Java types. They are assembled into reference types. Reference types can have methods and be assigned to null. In addition to "normal" numbers, numeric literals are allowed to begin with 0 (octal), 0x (hex), 0X (hex), 0b (binary), or 0B (binary). Numeric literals are also allowed to contain underscores as long as they are directly between two other numbers. Declaring a variable involves stating the data type and giving the variable a name. Variables that represent fields in a class are automatically initialized to their corresponding "zero" or null value during object instantiation. Local variables must be specifically initialized. Identifiers may contain letters, numbers, $, or _. Identifiers may not begin with numbers. Scope refers to that portion of code where a variable can be accessed. There are three kinds of variables in Java, depending on their scope: instance variables, class variables, and local variables. Instance variables are the nonstatic fields of your class. Class variables are the static fields within a class. Local variables are declared within a method. For some class elements, order matters within the file. The package statement comes first if present. Then comes the import statements if present. Then comes the class declaration. Fields and methods are allowed to be in any order within the class. Garbage collection is responsible for removing objects from memory when they can never be used again. An object becomes eligible for garbage collection when there are no more references to it or its references have all gone out of scope. The finalize() method will run once for each object if/when it is first garbage collected. Java code is object oriented, meaning all code is defined in classes. Access modifiers allow classes to encapsulate data. Java is platform independent, compiling to bytecode. It is robust and simple by not providing pointers or operator overloading. Finally, Java is secure because it runs inside a virtual machine.

Calling Inherited Class Members

Java classes may use any public or protected member of the parent class, including methods, primitives, or object references. If the parent class and child class are part of the same package, the child class may also use any default members defined in the parent class. Finally, a child class may never access a private member of the parent class, at least not through any direct reference. As you saw in the first example in this chapter, a private member age may be accessed indirectly via a public or protected method. To reference a member in a parent class, you can just call it directly, as in the following example with the output function displaySharkDetails(): class Fish { protected int size; private int age; public Fish(int age) { this.age = age; } public int getAge() { return age; } } public class Shark extends Fish { private int numberOfFins = 8; public Shark(int age) { super(age); this.size = 4; } public void displaySharkDetails() { System.out.print("Shark with age: "+getAge()); System.out.print(" and "+size+" meters long"); System.out.print(" with "+numberOfFins+" fins"); } } In the child class, we use the public method getAge() and protected member size to access values in the parent class. As you may remember from Chapter 4, you can use the keyword this to access a member of the class. You may also use this to access members of the parent class that are accessible from the child class, since a child class inherits all of its parent members. Consider the following alternative definition to the displaySharkDetails() method in the previous example: public void displaySharkDetails() { System.out.print("Shark with age: "+this.getAge()); System.out.print(" and "+this.size+" meters long"); System.out.print(" with "+this.numberOfFins+" fins"); } In Java, you can explicitly reference a member of the parent class by using the super keyword, as in the following alternative definition of displaySharkDetails(): public void displaySharkDetails() { System.out.print("Shark with age: "+super.getAge()); System.out.print(" and "+super.size+" meters long"); System.out.print(" with "+this.numberOfFins+" fins"); } In the previous example, we could use this or super to access a member of the parent class, but is the same true for a member of the child class? Consider this example: public void displaySharkDetails() { System.out.print("Shark with age: "+super.getAge()); System.out.print(" and "+super.size+" meters long"); System.out.print(" with "+super.numberOfFins+" fins"); // DOES NOT COMPILE } This code will not compile because numberOfFins is only a member of the current class, not the parent class. In other words, we see that this and super may both be used for methods or variables defined in the parent class, but only this may be used for members defined in the current class. As you'll see in the next section, if the child class overrides a member of the parent class, this and super could have very different effects when applied to a class member. super() vs. super As discussed in Chapter 4, this() and this are unrelated in Java. Likewise, super() and super are quite different but may be used in the same methods on the exam. The first, super(), is a statement that explicitly calls a parent constructor and may only be used in the first line of a constructor of a child class. The second, super, is a keyword used to reference a member defined in a parent class and may be used throughout the child class. The exam may try to trick you by using both super() and super in a constructor. For example, consider the following code: public Rabbit(int age) { super(); super.setAge(10); } The first statement of the constructor calls the parent's constructor, whereas the second statement calls a function defined in the parent class. Contrast this with the following code, which doesn't compile: public Rabbit(int age) { super; // DOES NOT COMPILE super().setAge(10); // DOES NOT COMPILE } This code looks similar to the previous example, but neither line of the constructor will compile since they are using the keywords incorrectly. When you see super() or super on the exam, be sure to check that they are being used correctly.

Java

Java puts source code in .java files and bytecode in .class files. It does not use a .bytecode file. When running a Java program, you pass just the name of the class without the .class extension.

primitive types

Keyword Type boolean true or false byte 8-bit (-128 to 127) short 16-bit integral value int 32-bit integral value long 64-bit integral value float 32-bit floating-point double 64-bit floating-point char 16-bit Unicode value float and double are used for floating-point (decimal) values. A float requires the letter f following the number so Java knows it is a float. byte, short, int, and long are used for numbers without decimal points. Each numeric type uses twice as many bits as the smaller similar type. For example, short uses twice as many bits as byte does. If bigger than int - add "L" to bumber to indicate long

Formating time Question

Let's do a quick review. Can you figure out which of these lines will throw an exception? DateTimeFormatter f = DateTimeFormatter.ofPattern("hh:mm"); f.format(dateTime); f.format(date); f.format(time); If you get this question on the exam, think about what the symbols represent. We have h for hour and m for minute. Remember M (uppercase) is month and m (lowercase) is minute. We can only use this formatter with objects containing times. Therefore, line 6 will throw an exception.

Sorting an ArrayList

List<Integer> numbers = new ArrayList<>(); numbers.add(99); numbers.add(5); numbers.add(81); Collections.sort(numbers); System.out.println(numbers); [5, 81, 99] As you can see, the numbers got sorted, just like you'd expect. Isn't it nice to have something that works just like you think it will?

Be able to recognize when a class is properly encapsulated.

Look for private instance variables and public getters and setters when identifying encapsulation.

Write simple lambda expressions.

Look for the presence or absence of optional elements in lambda code. Parameter types are optional. Braces and the return keyword are optional when the body is a single statement. Parentheses are optional when only one parameter is specified and the type is implicit. The Predicate interface is commonly used with lambdas because it declares a single method called test(), which takes one parameter.

method definition consists of the following parts:

Modifier name: Defines the access type of the method and is optional to use. Return type: A method may return a value. Method name: Method signature consists of the method name and the parameter list. Parameters: Defines the list of parameters, data type, order, and number of parameters of a method. A method may contain zero parameters. Method body: Defines what the method does with statements. The syntax of a method in Java is given below: Access modifier Return type Method name( Parameters) { // Method body; }

Calling Constructors

Now that we have covered how to define a valid constructor, we'll show you how Java calls the constructors. In Java, the parent constructor is always executed before the child constructor. For example, try to determine what the following code outputs: class Primate { public Primate() { System.out.println("Primate"); } } class Ape extends Primate { public Ape() { System.out.println("Ape"); } } public class Chimpanzee extends Ape { public static void main(String[] args) { new Chimpanzee(); } } The compiler first inserts the super() command as the first statement of both the Primate and Ape constructors. Next, the compiler inserts a default no-argument constructor in the Chimpanzee class with super() as the first statement of the constructor. The code will execute with the parent constructors called first and yields the following output: Primate Ape The exam creators are fond of questions similar to the previous one that try to get you to determine the output of statements involving constructors. Just remember to "think like the compiler" as much as possible and insert the missing constructors or statements as needed.

Parsing Dates and Times

Now that you know how to convert a date or time to a formatted String, you'll find it easy to convert a String to a date or time. Just like the format() method, the parse() method takes a formatter as well. If you don't specify one, it uses the default for that type. DateTimeFormatter f = DateTimeFormatter.ofPattern("MM dd yyyy"); LocalDate date = LocalDate.parse("01 02 2015", f); LocalTime time = LocalTime.parse("11:22"); System.out.println(date); // 2015-01-02 System.out.println(time); // 11:22 Here we show using both a custom formatter and a default value. This isn't common, but you might have to read code that looks like this on the exam. Parsing is consistent in that if anything goes wrong, Java throws a runtime exception. That could be a format that doesn't match the String to be parsed or an invalid date.

Benefits of Java

Object Oriented. Java is an object-oriented language, which means all code is defined in classes and most of those classes can be instantiated into objects. We'll discuss this more throughout the book. Many languages before Java were procedural, which meant there were routines or methods but no classes. Another common approach is functional programming. Java allows for functional programming within a class, but object oriented is still the main organization of code. Encapsulation Java supports access modifiers to protect data from unintended access and modification. Most people consider encapsulation to be an aspect of object-oriented languages. Since the exam objectives call attention to it specifically, so do we. Platform Independent Java is an interpreted language because it gets compiled to bytecode. A key benefit is that Java code gets compiled once rather than needing to be recompiled for different operating systems. This is known as "write once, run everywhere." On the OCP exam, you'll learn that it is possible to write code that does not run everywhere. For example, you might refer to a file in a specific directory. If you get asked on the OCA exam, the answer is that the same class files run everywhere. Robust One of the major advantages of Java over C++ is that it prevents memory leaks. Java manages memory on its own and does garbage collection automatically. Bad memory management in C++ is a big source of errors in programs. Simple Java was intended to be simpler than C++. In addition to eliminating pointers, it got rid of operator overloading. In C++, you could write a + b and have it mean almost anything. Secure. Java code runs inside the JVM. This creates a sandbox that makes it hard for Java code to do evil things to the computer it is running on.

Q: Which of the following legally fill in the blank so you can run the main() method from the command line? (Choose all that apply.) public static void main(____) A. None of these are correct. B. String names C. String... $n D. String _Names[] E. String abc[] F. String[] 123 G. String[] _names

Option G is correct because it is the traditional main() method signature and variables may begin with underscores. Options E and D are correct because the array operator may appear after the variable name. Option C is correct because varargs are allowed in place of an array. Option F is incorrect because variables are not allowed to begin with a digit. Option B is incorrect because the argument must be an array or varargs. Option B is a perfectly good method. However, it is not one that can be run from the command line because it has the wrong parameter type.

Constructor Chaining

Overloaded constructors often call each other. One common technique is to have each constructor add one parameter until getting to the constructor that does all the work. This approach is called constructor chaining. In this example, all three constructors are chained. public class Mouse { private int numTeeth; private int numWhiskers; private int weight; public Mouse(int weight) { this(weight, 16); // calls constructor with 2 parameters } public Mouse(int weight, int numTeeth) { this(weight, numTeeth, 6); // calls constructor with 3 parameters } public Mouse(int weight, int numTeeth, int numWhiskers) { this.weight = weight; this.numTeeth = numTeeth; this.numWhiskers = numWhiskers; } public void print() { System.out.println(weight + " " + numTeeth + " " + numWhiskers); } public static void main(String[] args) { Mouse mouse = new Mouse(15); mouse.print(); } } This code prints 15 16 6. The main() method calls the constructor with one parameter. That constructor adds a second hard-coded value and calls the constructor with two parameters. That constructor adds one more hard-coded value and calls the constructor with three parameters. The three-parameter constructor assigns the instance variables.

two ways of achieving polymorphism:

Overloading: Have multiple methods by same name but different parameters Overriding: Declared with the same signature and return type as the method in the parent class

Order of elements of a class

Package declaration Import statements Class declaration Field declaration Method declaration

Access Modifiers InDepth

Private Access: only code in the same class can call private methods or access private fields. package private access: When there is no access modifier, Java uses the default, which is package private access. lets other classes in the same package access members Protected Access: allows everything that default (package private) access allows and more. The protected access modifier adds the ability to access members of a parent class. Public Access: anyone can access the member from anywhere.

Identify when a method or field is accessible.

Recognize when a method or field is accessed when the access modifier (private, protected, public, or default access) does not allow it.

Diffrences between primitives and reference types

Reference types can be assigned null, which means they do not currently refer to an object. Primitive types will give you a compiler error if you attempt to assign them null. Reference types can be used to call methods when they do not point to null. Primitives do not have methods declared on them. Primitives do not have methods. all the primitive types have lowercase type names. All classes that come with Java begin with uppercase.

Recognize valid and invalid uses of static imports.

Static imports import static members. They are written as import static, not static import. Make sure they are importing static methods or variables rather than classnames.

String is immutable

String can't be changed once it's created

Binary

System.out.println(56); // 56 System.out.println(0b11); // 3 System.out.println(017); // 15 System.out.println(0x1F); // 31 First we have our normal base 10 value. We know you already know how to read that, but bear with us. The rightmost digit is 6, so it's "worth" 6. The second-to-rightmost digit is 5, so it's "worth" 50 (5 times 10.) Adding these together, we get 56. Next we have binary, or base 2. The rightmost digit is 1 and is "worth" 1. The second-torightmost digit is also 1. In this case, it's "worth" 2 (1 times 2) because the base is 2. Adding these gets us 3. Then comes octal, or base 8. The rightmost digit is 7 and is "worth" 7. The second-torightmost digit is 1. In this case, it's "worth" 8 (1 times 8) because the base is 8. Adding these gets us 15. Finally, we have hexadecimal, or base 16, which is also known as hex. The rightmost "digit" is F and it's "worth" 15 (9 is "worth" 9, A is "worth" 10, B is "worth" 11, and so forth). The second-to-rightmost digit is 1. In this case, it's "worth" 16 (1 times 16) because the base is 16. Adding these gets us 31.

Wildcards

The * is a wildcard that matches all classes in the package. Every class in the java.util package is available to this program when Java compiles it. It doesn't import child packages, fields, or methods; it imports only classes.

clear()

The clear() method provides an easy way to discard all elements of the ArrayList. The method signature is as follows: void clear() The following shows how to use this method: List<String> birds = new ArrayList<>(); birds.add("hawk"); // [hawk] birds.add("hawk"); // [hawk, hawk] System.out.println(birds.isEmpty()); // false System.out.println(birds.size()); // 2 birds.clear(); // [] System.out.println(birds.isEmpty()); // true System.out.println(birds.size()); // 0 After we call clear(), birds is back to being an empty ArrayList of size 0.

Ternary Operator, ? :,

The conditional operator, ? :, otherwise known as the ternary operator, is the only operator that takes three operands and is of the form: booleanExpression ? expression1 : expression2 The first operand must be a boolean expression, and the second and third can be any expression that returns a value.

contains()

The contains() method also looks for matches in the String. It isn't as particular as startsWith() and endsWith()-the match can be anywhere in the String. The method signature is as follows: boolean contains(String str) The following code shows how to use these methods: System.out.println("abc".contains("b")); // true System.out.println("abc".contains("B")); // false Again, we have a case-sensitive search in the String. The contains() method is a convenience method so you don't have to write str.indexOf(otherString) != -1.

contains()

The contains() method checks whether a certain value is in the ArrayList. The method signature is as follows: boolean contains(Object object) The following shows how to use this method: List<String> birds = new ArrayList<>(); birds.add("hawk"); // [hawk] System.out.println(birds.contains("hawk")); // true System.out.println(birds.contains("robin")); // false This method calls equals() on each element of the ArrayList to see whether there are any matches. Since String implements equals(), this works out well.

Formatting Dates and Times

The date and time classes support many methods to get data out of them: LocalDate date = LocalDate.of(2020, Month.JANUARY, 20); System.out.println(date.getDayOfWeek()); // MONDAY System.out.println(date.getMonth()); // JANUARY System.out.println(date.getYear()); // 2020 System.out.println(date.getDayOfYear()); // 20 We could use this information to display information about the date. However, it would be more work than necessary. Java provides a class called DateTimeFormatter to help us out. Unlike the LocalDateTime class, DateTimeFormatter can be used to format any type of date and/or time object. What changes is the format. DateTimeFormatter is in the package java.time.format. LocalDate date = LocalDate.of(2020, Month.JANUARY, 20); LocalTime time = LocalTime.of(11, 12, 34); LocalDateTime dateTime = LocalDateTime.of(date, time); System.out.println(date.format(DateTimeFormatter.ISO_LOCAL_DATE)); System.out.println(time.format(DateTimeFormatter.ISO_LOCAL_TIME)); System.out.println(dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); ISO is a standard for dates. The output of the previous code looks like this: 2020-01-20 11:12:34 2020-01-20T11:12:34 This is a reasonable way for computers to communicate, but probably not how you want to output the date and time in your program. Luckily there are some predefined formats that are more useful: DateTimeFormatter shortDateTime = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT); System.out.println(shortDateTime.format(dateTime)); // 1/20/20 System.out.println(shortDateTime.format(date)); // 1/20/20 System.out.println( shortDateTime.format(time)); // UnsupportedTemporalTypeException Here we say we want a localized formatter in the predefined short format. The last line throws an exception because a time cannot be formatted as a date. The format() method is declared on both the formatter objects and the date/time objects, allowing you to reference the objects in either order. The following statements print exactly the same thing as the previous code: DateTimeFormatter shortDateTime = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT); System.out.println(dateTime.format(shortDateTime)); System.out.println(date.format(shortDateTime)); System.out.println(time.format(shortDateTime)); There are two predefined formats that can show up on the exam: SHORT and MEDIUM. The other predefined formats involve time zones, which are not on the exam. LocalDate date = LocalDate.of(2020, Month.JANUARY, 20); LocalTime time = LocalTime.of(11, 12, 34); LocalDateTime dateTime = LocalDateTime.of(date, time); DateTimeFormatter shortF = DateTimeFormatter .ofLocalizedDateTime(FormatStyle.SHORT); DateTimeFormatter mediumF = DateTimeFormatter .ofLocalizedDateTime(FormatStyle.MEDIUM); System.out.println(shortF.format(dateTime)); // 1/20/20 11:12 AM System.out.println(mediumF.format(dateTime)); // Jan 20, 2020 11:12:34 AM If you don't want to use one of the predefined formats, you can create your own. For example, this code spells out the month: DateTimeFormatter f = DateTimeFormatter.ofPattern("MMMM dd, yyyy, hh:mm"); System.out.println(dateTime.format(f)); // January 20, 2020, 11:12 Before we look at the syntax, know you are not expected to memorize what different numbers of each symbol mean. The most you will need to do is recognize the date and time pieces. MMMM: M represents the month. The more Ms you have, the more verbose the Java output. For example, M outputs 1, MM outputs 01, MMM outputs Jan, and MMMM outputs January. dd: d represents the date in the month. As with month, the more ds you have, the more verbose the Java output. dd means to include the leading zero for a single-digit date. , Use , if you want to output a comma (this also appears after the year). yyyy: y represents the year. yy outputs a two-digit year and yyyy outputs a four-digit year. hh: h represents the hour. Use hh to include the leading zero if you're outputting a singledigit hour. : Use : if you want to output a colon. mm: m represents the minute.

Equality Operators

The equality operators are used in one of three scenarios: Comparing two numeric primitive types. If the numeric values are of different data types, the values are automatically promoted as previously described. For example, 5 == 5.00 returns true since the left side is promoted to a double. Comparing two boolean values. Comparing two objects, including null and String values.

equals() and equalsIgnoreCase()

The equals() method checks whether two String objects contain exactly the same characters in the same order. The equalsIgnoreCase() method checks whether two String objects contain the same characters with the exception that it will convert the characters' case if needed. The method signatures are as follows: boolean equals(String str) boolean equalsIgnoreCase(String str) The following code shows how to use these methods: System.out.println("abc".equals("ABC")); // false System.out.println("ABC".equals("ABC")); // true System.out.println("abc".equalsIgnoreCase("ABC")); // true This example should be fairly intuitive. In the first example, the values aren't exactly the same. In the second, they are exactly the same. In the third, they differ only by case, but it is okay because we called the method that ignores differences in case.

isEmpty() and size()

The isEmpty() and size() methods look at how many of the slots are in use. The method signatures are as follows: boolean isEmpty() int size() The following shows how to use these methods: System.out.println(birds.isEmpty()); // true System.out.println(birds.size()); // 0 birds.add("hawk"); // [hawk] birds.add("hawk"); // [hawk, hawk] System.out.println(birds.isEmpty()); // false System.out.println(birds.size()); // 2 At the beginning, birds has a size of 0 and is empty. It has a capacity that is greater than 0. However, as with StringBuilder, we don't use the capacity in determining size or length. After adding elements, the size becomes positive and it is no longer empty.

charAt()

The method charAt() lets you query the string to find out what character is at a specific index. The method signature is as follows: char charAt(int index) The following code shows how to use charAt(): String string = "animals"; System.out.println(string.charAt(0)); // a System.out.println(string.charAt(6)); // s System.out.println(string.charAt(7)); // throws exception

indexOf()

The method indexOf() looks at the characters in the string and finds the first index that matches the desired value. indexOf can work with an individual character or a whole String as input. It can also start from a requested position. The method signatures are as follows: int indexOf(char ch) int indexOf(char ch, int fromIndex) int indexOf(String str) int indexOf(String str, int fromIndex) The following code shows how to use indexOf(): String string = "animals"; System.out.println(string.indexOf('a')); // 0 System.out.println(string.indexOf("al")); // 4 System.out.println(string.indexOf('a', 4)); // 4 System.out.println(string.indexOf("al", 5)); // -1

length()

The method length() returns the number of characters in the String. The method signature is as follows: int length() The following code shows how to use length(): String string = "animals"; System.out.println(string.length()); // 7

toLowerCase() and toUpperCase()

The method signatures are as follows: String toLowerCase(String str) String toUpperCase(String str) The following code shows how to use these methods: String string = "animals"; System.out.println(string.toUpperCase()); // ANIMALS System.out.println("Abc123".toLowerCase()); // abc123 These methods do what they say. toUpperCase() converts any lowercase characters to uppercase in the returned string. toLowerCase() converts any uppercase characters to lowercase in the returned string. These methods leave alone any characters other than letters. Also, remember that strings are immutable, so the original string stays the same.

substring()

The method substring() also looks for characters in a string. It returns parts of the string. The first parameter is the index to start with for the returned string. As usual, this is a zero-based index. There is an optional second parameter, which is the end index you want to stop at. Notice we said "stop at" rather than "include." This means the endIndex parameter is allowed to be 1 past the end of the sequence if you want to stop at the end of the sequence. That would be redundant, though, since you could omit the second parameter entirely in that case. In your own code, you want to avoid this redundancy. Don't be surprised if the exam uses it though. The method signatures are as follows: String substring(int beginIndex) String substring(int beginIndex, int endIndex) The following code shows how to use substring(): String string = "animals"; System.out.println(string.substring(3)); // mals System.out.println(string.substring(string.indexOf('m'))); // mals System.out.println(string.substring(3, 4)); // m System.out.println(string.substring(3, 7)); // mals The substring() method is the trickiest String method on the exam. The first example says to take the characters starting with index 3 through the end, which gives us "mals". The second example does the same thing: it calls indexOf() to get the index rather than hard-coding it. This is a common practice when coding because you may not know the index in advance. The third example says to take the characters starting with index 3 until, but not including, the character at index 4-which is a complicated way of saying we want a String with one character: the one at index 3. This results in "m". The final example says to take the characters starting with index 3 until we get to index 7. Since index 7 is the same as the end of the string, it is equivalent to the first example. System.out.println(string.substring(3, 3)); // empty string System.out.println(string.substring(3, 2)); // throws exception System.out.println(string.substring(3, 8)); // throws exception The first example in this set prints an empty string. The request is for the characters starting with index 3 until you get to index 3. Since we start and end with the same index, there are no characters in between. The second example in this set throws an exception because the indexes can't be backward. Java knows perfectly well that it will never get to index 2 if it starts with index 3. The third example says to continue until the eighth character. There is no eighth position, so Java throws an exception. Granted, there is no seventh character either, but at least there is the "end of string" invisible position. Let's review this one more time since substring() is so tricky. The method returns the string starting from the requested index. If an end index is requested, it stops right before that index. Otherwise, it goes to the end of the string.

modulus operator %

The modulus, or remainder operator, is simply the remainder when two numbers are divided. For example, 9 divided by 3 divides evenly and has no remainder; therefore, the remainder, or 9 % 3, is 0

Redeclaring private Methods

The previous section defined the behavior if you override a public or protected method in the class. Now let's expand our discussion to private methods. In Java, it is not possible to override a private method in a parent class since the parent method is not accessible from the child class. Just because a child class doesn't have access to the parent method, doesn't mean the child class can't define its own version of the method. It just means, strictly speaking, that the new method is not an overridden version of the parent class's method. Java permits you to redeclare a new method in the child class with the same or modifi ed signature as the method in the parent class. This method in the child class is a separate and independent method, unrelated to the parent version's method, so none of the rules for overriding methods are invoked. For example, let's return to the Camel example we used in the previous section and show two related classes that define the same method: public class Camel { private String getNumberOfHumps() { return "Undefined"; } } public class BactrianCamel extends Camel { private int getNumberOfHumps() { return 2; } } This code compiles without issue. Notice that the return type differs in the child method from String to int. In this example, the method getNumberOfHumps() in the parent class is hidden, so the method in the child class is a new method and not an override of the method in the parent class. As you saw in the previous section, if the method in the parent class were public or protected, the method in the child class would not compile because it would violate two rules of overriding methods. The parent method in this example is private, so there are no such issues.

String sorting

The problem is that String sorts in alphabetic order, and 1 sorts before 9. (Numbers sort before letters and uppercase sorts before lowercase, in case you were wondering.)

remove()

The remove() methods remove the first matching value in the ArrayList or remove the element at a specified index. The method signatures are as follows: boolean remove(Object object) E remove(int index) This time the boolean return value tells us whether a match was removed. The E return type is the element that actually got removed. The following shows how to use these methods: List birds = new ArrayList<>(); birds.add("hawk"); // [hawk] birds.add("hawk"); // [hawk, hawk] System.out.println(birds.remove("cardinal")); // prints false System.out.println(birds.remove("hawk")); // prints true System.out.println(birds.remove(0)); // prints hawk System.out.println(birds); // [] Line 6 tries to remove an element that is not in birds. It returns false because no such element is found. Line 7 tries to remove an element that is in birds and so returns true. Notice that it removes only one match. Line 8 removes the element at index 0, which is the last remaining element in the ArrayList. Since calling remove() with an int uses the index, an index that doesn't exist will throw an exception. For example, birds.remove(100) throws an IndexOutOfBoundsException. There is also a removeIf() method. We'll cover it in the next chapter because it uses lambda expressions (a topic in that chapter).

replace()

The replace() method does a simple search and replace on the string. There's a version that takes char parameters as well as a version that takes CharSequence parameters. A CharSequence is a general way of representing several classes, including String and StringBuilder. It's called an interface, which we'll cover in Chapter 5, "Class Design." The method signatures are as follows: String replace(char oldChar, char newChar) String replace(CharSequence oldChar, CharSequence newChar) The following code shows how to use these methods: System.out.println("abcabc".replace('a', 'A')); // AbcAbc System.out.println("abcabc".replace("a", "A")); // AbcAbc The first example uses the first method signature, passing in char parameters. The second example uses the second method signature, passing in String parameters.

set()

The set() method changes one of the elements of the ArrayList without changing the size. The method signature is as follows: E set(int index, E newElement) The E return type is the element that got replaced. The following shows how to use this method: List<String> birds = new ArrayList<>(); birds.add("hawk"); // [hawk] System.out.println(birds.size()); // 1 birds.set(0, "robin"); // [robin] System.out.println(birds.size()); // 1 birds.set(1, "robin"); // IndexOutOfBoundsException Line 16 adds one element to the array, making the size 1. Line 18 replaces that one element and the size stays at 1. Line 20 tries to replace an element that isn't in the ArrayList. Since the size is 1, the only valid index is 0. Java throws an exception because this isn't allowed.

startsWith() and endsWith()

The startsWith() and endsWith() methods look at whether the provided value matches part of the String. The method signatures are as follows: boolean startsWith(String prefix) boolean endsWith(String suffix) The following code shows how to use these methods: System.out.println("abc".startsWith("a")); // true System.out.println("abc".startsWith("A")); // false System.out.println("abc".endsWith("c")); // true System.out.println("abc".endsWith("a")); // false Again, nothing surprising here. Java is doing a case-sensitive check on the values provided.

trim()

The trim() method removes whitespace from the beginning and end of a String. In terms of the exam, whitespace consists of spaces along with the \t (tab) and \n (newline) characters. Other characters, such as \n (carriage return), are also included in what gets trimmed. The method signature is as follows: public String trim() The following code shows how to use this method: System.out.println("abc".trim()); // abc System.out.println("\t a b c\n".trim()); // a b c The first example prints the original string because there are no whitespace characters at the beginning or end. The second example gets rid of the leading tab, subsequent spaces, and the trailing newline. It leaves the spaces that are in the middle of the string.

Working with Periods

There are five ways to create a Period class: Period annually = Period.ofYears(1); // every 1 year Period quarterly = Period.ofMonths(3); // every 3 months Period everyThreeWeeks = Period.ofWeeks(3); // every 3 weeks Period everyOtherDay = Period.ofDays(2); // every 2 days Period everyYearAndAWeek = Period.of(1, 0, 7); // every year and 7 days Period wrong = Period.ofYears(1).ofWeeks(1); // every week This tricky code is really like writing the following: Period wrong = Period.ofYears(1); wrong = Period.ofWeeks(7); The last thing to know about Period is what objects it can be used with. Let's look at some code: 3 LocalDate date = LocalDate.of(2015, 1, 20); 4 LocalTime time = LocalTime.of(6, 15); 5 LocalDateTime dateTime = LocalDateTime.of(date, time); 6 Period period = Period.ofMonths(1); 7 System.out.println(date.plus(period)); // 2015-02-20 8 System.out.println(dateTime.plus(period)); // 2015-02-20T06:15 9 System.out.println(time.plus(period)); // UnsupportedTemporalTypeException Lines 7 and 8 work as expected. They add a month to January 20, 2015, giving us February 20, 2015. The first has only the date, and the second has both the date and time. Line 9 attempts to add a month to an object that only has a time. This won't work. Java throws an exception and complains that we attempt to use an Unsupported unit: Months. As you can see, you'll have to pay attention to the type of date and time objects every place you see them.

Identifiers names

There are only three rules to remember for legal identifiers: The name must begin with a letter or the symbol $ or _. Subsequent characters may also be numbers. You cannot use the same name as a Java reserved word. As you might imagine, a reserved word is a keyword that Java has reserved so that you are not allowed to use it. Remember that Java is case sensitive, so you can use versions of the keywords that only differ in case. Please don't, though. Most Java developers follow these conventions for identifier names: Method and variables names begin with a lowercase letter followed by CamelCase. Class names begin with an uppercase letter followed by CamelCase. Don't start any identifiers with $. The compiler uses this symbol for some files.

Creating a New Package

This is a special unnamed package that you should use only for throwaway code. In Java you don't pass the extension when running a program.

Creating Java Objects

Throughout our discussion of Java in this book, we have thrown around the word object numerous times—and with good reason. In Java, all classes inherit from a single class, java.lang.Object. Furthermore, java.lang.Object is the only class that doesn't have any parent classes. You might be wondering, "None of the classes I've written so far extend java.lang .Object, so how do all classes inherit from it?" The answer is that the compiler has been automatically inserting code into any class you write that doesn't extend a specific class. For example, consider the following two equivalent class definitions: public class Zoo { } public class Zoo extends java.lang.Object { } The key is that when Java sees you define a class that doesn't extend another class, it immediately adds the syntax extends java.lang.Object to the class definition. If you define a new class that extends an existing class, Java doesn't add this syntax, although the new class still inherits from java.lang.Object. Since all classes inherit from java.lang.Object, extending an existing class means the child automatically inherits from java.lang.Object by construction. This means that if you look at the inheritance structure of any class, it will always end with java.lang.Object on the top of the tree, as shown in Figure 5.3. The figure shows Java object inheritance. The representation is a tree structure using a bottom-to-top approach. It has an object Ox, at the bottom, pointing to another object Mammal which extends the class java.lang.Object which is at the top of the tree. Figure 5.3: Java object inheritance

create an instance of a class

To create an instance of a class, all you have to do is write new before it. For example: Random r = new Random();

method chaining

To read code that uses method chaining, start at the left and evaluate the first method. Then call the next method on the returned value of the first method. Keep going until you get to the semicolon. Remember that String is immutable. What do you think the result of this code is? String a = "abc"; String b = a.toUpperCase(); b = b.replace("B", "2").replace('C', '3'); System.out.println("a=" + a); System.out.println("b=" + b); On line 5, we set a to point to "abc" and never pointed a to anything else. Since we are dealing with an immutable object, none of the code on lines 6 or 7 changes a. b is a little trickier. Line 6 has b pointing to "ABC", which is straightforward. On line 7, we have method chaining. First, "ABC".replace("B", "2") is called. This returns "A2C". Next, "A2C". replace('C', '3') is called. This returns "A23". Finally, b changes to point to this returned String. When line 9 executes, b is "A23".

Java operators follow order of operation

Unless overridden with parentheses, Java operators follow order of operation, listed in Table 2.1, by decreasing order of operator precedence. If two operators have the same level of precedence, then Java guarantees left-to-right evaluation. Post-unary operators expression++, expression-- Pre-unary operators ++expression, --expression Other unary operators +, -, !, ~ Multiplication/Division/Modulus *, /, % Addition/Subtraction +, - Shift operators <<, >>, >>> Relational operators <, >, <=, >=, instanceof Equal to/not equal to ==, != Logical operators &, ^, | Short-circuit logical operators &&, || Ternary operators boolean expression ? expression1 : expression2 Assignment operators =, +=, -=, *=, /=, %=, &=, ^=, |=, <<=, >>=, >>>=

Understanding Compiler Enhancements

Up to now, we defined numerous classes that did not explicitly call the parent constructor via the super() keyword, so why did the code compile? The answer is that the Java compiler automatically inserts a call to the no-argument constructor super() if the first statement is not a call to the parent constructor. For example, the following three class and constructor definitions are equivalent, because the compiler will automatically convert them all to the last example: public class Donkey { } public class Donkey { public Donkey() { } } public class Donkey { public Donkey() { super(); } } Make sure you understand the differences between these three Donkey class definitions and why Java will automatically convert them all to the last definition. Keep the process the Java compile performs in mind as we discuss the next few examples. What happens if the parent class doesn't have a no-argument constructor? Recall that the no-argument constructor is not required and only inserted if there is no constructor defined in the class. In this case, the Java compiler will not help and you must create at least one constructor in your child class that explicitly calls a parent constructor via the super() command. For example, the following code will not compile: public class Mammal { public Mammal(int age) { } } public class Elephant extends Mammal { // DOES NOT COMPILE } In this example no constructor is defined within the Elephant class, so the compiler tries to insert a default no-argument constructor with a super() call, as it did in the Donkey example. The compiler stops, though, when it realizes there is no parent constructor that takes no arguments. In this example, we must explicitly define at least one constructor, as in the following code: public class Mammal { public Mammal(int age) { } } public class Elephant extends Mammal { public Elephant() { // DOES NOT COMPILE } } This code still doesn't compile, though, because the compiler tries to insert the noargument super() as the first statement of the constructor in the Elephant class, and there is no such constructor in the parent class. We can fix this, though, by adding a call to a parent constructor that takes a fixed argument: public class Mammal { public Mammal(int age) { } } public class Elephant extends Mammal { public Elephant() { super(10); } } This code will compile because we have added a constructor with an explicit call to a parent constructor. Note that the class Elephant now has a no-argument constructor even though its parent class Mammal doesn't. Subclasses may define no-argument constructors even if their parent classes do not, provided the constructor of the child maps to a parent constructor via an explicit call of the super() command. You should be wary of any exam question in which the parent class defines a constructor that takes arguments and doesn't define a no-argument constructor. Be sure to check that the code compiles before answering a question about it.

Java identifiers

Valid identifiers : _helloWorld A$B Public " true" is not a valid identifier because true is a Java reserved word. " 1980_s" is not valid because the first character is not a letter, $, or _. " java.lang" is not valid because the dot (.) is not allowed in identifiers.

Instance and Class Variables

Variables that are not local variables are known as instance variables or class variables. Instance and class variables do not require you to initialize them.As soon as you declare these variables, they are given a default value. Variable type Default initialization value boolean = false byte, short, int, long = 0 (in the type's bit-length) float, double = 0.0 (in the type's bit-length) char = '\u0000' (NUL) All object references (everything else) = null Instance variables are also called fields. You can tell a variable is a class variable because it has the keyword static before it. Class variables are shared across multiple objects.

Creating final methods

We conclude our discussion of method inheritance with a somewhat self-explanatory rule: final methods cannot be overridden. If you recall our discussion of modifiers from Chapter 4, you can create a method with the final keyword. By doing so, though, you forbid a child class from overriding this method. This rule is in place both when you override a method and when you hide a method. In other words, you cannot hide a static method in a parent class if it is marked as final. Let's take a look at an example: public class Bird { public final boolean hasFeathers() { return true; } } public class Penguin extends Bird { public final boolean hasFeathers() { // DOES NOT COMPILE return false; } } In this example, the method hasFeathers() is marked as final in the parent class Bird, so the child class Penguin cannot override the parent method, resulting in a compiler error. Note that whether or not the child method used the final keyword is irrelevant—the code will not compile either way. Why Mark a Method as final? Although marking methods as final prevents them from being overridden, it does have advantages in practice. For example, you'd mark a method as final when you're defining a parent class and want to guarantee certain behavior of a method in the parent class, regardless of which child is invoking the method. For example, in the previous example with Birds, the author of the parent class may want to ensure the method hasFeathers() always returns true, regardless of the child class instance on which it is invoked. The author is confident that there is no example of a Bird in which feathers are not present. The reason methods are not commonly marked as final in practice, though, is that it may be difficult for the author of a parent class method to consider all of the possible ways her child class may be used. For example, although all adult birds have feathers, a baby chick doesn't; therefore, if you have an instance of a Bird that is a chick, it would not have feathers. In short, the final modifier is only used on methods when the author of the parent method wants to guarantee very precise behavior.

Overriding a Method

What if there is a method defined in both the parent and child class? For example, you may want to define a new version of an existing method in a child class that makes use of the definition in the parent class. In this case, you can override a method by declaring a new method with the signature and return type as the method in the parent class. As you may recall from Chapter 4, the method signature includes the name and list of input parameters. When you override a method, you may reference the parent version of the method using the super keyword. In this manner, the keywords this and super allow you to select between the current and parent version of a method, respectively. We illustrate this with the following example: public class Canine { public double getAverageWeight() { return 50; } } public class Wolf extends Canine { public double getAverageWeight() { return super.getAverageWeight()+20; } public static void main(String[] args) { System.out.println(new Canine().getAverageWeight()); System.out.println(new Wolf().getAverageWeight()); } } In this example, in which the child class Wolf overrides the parent class Canine, the method getAverageWeight() runs without issue and outputs the following: 50.0 70.0 You might be wondering, was the use of super in the child's method required? For example, what would the following code output if we removed the super keyword in the getAverageWeight() method of the Wolf class? public double getAverageWeight() { return getAverageWeight()+20; // INFINITE LOOP } In this example, the compiler would not call the parent Canine method; it would call the current Wolf method since it would think you were executing a recursive call. A recursive function is one that calls itself as part of execution, and it is common in programming. A recursive function must have a termination condition. In this example, there is no termination condition; therefore, the application will attempt to call itself infinitely and produce a stack overflow error at runtime. Overriding a method is not without limitations, though. The compiler performs the following checks when you override a nonprivate method: The method in the child class must have the same signature as the method in the parent class. The method in the child class must be at least as accessible or more accessible than the method in the parent class. The method in the child class may not throw a checked exception that is new or broader than the class of any exception thrown in the parent class method. If the method returns a value, it must be the same or a subclass of the method in the parent class, known as covariant return types. The first rule of overriding a method is somewhat self-explanatory. If two methods have the same name but different signatures, the methods are overloaded, not overridden. As you may recall from our discussion of overloaded methods in Chapter 4, the methods are unrelated to each other and do not share any properties. Overloading vs. Overriding Overloading a method and overriding a method are similar in that they both involve redefining a method using the same name. They differ in that an overloaded method will use a different signature than an overridden method. This distinction allows overloaded methods a great deal more freedom in syntax than an overridden method would have. For example, take a look at the following code sample: public class Bird { public void fly() { System.out.println("Bird is flying"); } public void eat(int food) { System.out.println("Bird is eating "+food+" units of food"); } } public class Eagle extends Bird { public int fly(int height) { System.out.println("Bird is flying at "+height+" meters"); return height; } public int eat(int food) { // DOES NOT COMPILE System.out.println("Bird is eating "+food+" units of food"); return food; } } The first method, fly(), is overloaded in the subclass Eagle, since the signature changes from a no-argument method to a method with one int argument. Because the method is being overloaded and not overridden, the return type can be changed from void to int without issue. The second method, eat(), is overridden in the subclass Eagle, since the signature is the same as it is in the parent class Bird—they both take a single argument int. Because the method is being overridden, the return type of the method in Eagle must be a subclass of the return type of the method in Bird. In this example, the return type int is not a subclass of void therefore, the compiler will throw an exception on this method definition. Any time you see a method on the exam with the same name as a method in the parent class, determine whether the method is being overloaded or overridden first; doing so will help you with questions about whether the code will compile. Let's review some examples of the last three rules of overriding methods so you can learn to spot the issues when they arise: public class Camel { protected String getNumberOfHumps() { return "Undefined"; } } public class BactrianCamel extends Camel { private int getNumberOfHumps() { // DOES NOT COMPILE return 2; } } In this example, the method in the child class doesn't compile for two reasons. First, it violates the second rule of overriding methods: the child method must be at least as accessible as the parent. In the example, the parent method uses the protected modifier, but the child method uses the private modifier, making it less accessible in the child method than in the parent method. It also violates the fourth rule of overriding methods: the return type of the parent method and child method must be covariant. In this example, the return type of the parent method is String, whereas the return type of the child method is int, neither of which is covariant with each other. Any time you see a method that appears to be overridden on the exam, first check to make sure it is truly being overridden and not overloaded. Once you have confirmed it is being overridden, check that the access modifiers, return types, and any exceptions defined in the method are compatible with one another. Let's take a look at some example methods that use exceptions: public class InsufficientDataException extends Exception {} public class Reptile { protected boolean hasLegs() throws InsufficientDataException { throw new InsufficientDataException(); } protected double getWeight() throws Exception { return 2; } } public class Snake extends Reptile { protected boolean hasLegs() { return false; } protected double getWeight() throws InsufficientDataException{ return 2; } } In this example, both parent and child classes define two methods, hasLegs() and getWeight(). The first method, hasLegs(), throws an exception InsufficientDataException in the parent class but doesn't throw an exception in the child class. This does not violate the third rule of overriding methods, though, as no new exception is defined. In other words, a child method may hide or eliminate a parent method's exception without issue. The second method, getWeight(), throws Exception in the parent class and InsufficientDataException in the child class. This is also permitted, as InsufficientDataException is a subclass of Exception by construction. Neither of the methods in the previous example violates the third rule of overriding methods, so the code compiles and runs without issue. Let's review some examples that do violate the third rule of overriding methods: public class InsufficientDataException extends Exception {} public class Reptile { protected double getHeight() throws InsufficientDataException { return 2; } protected int getLength() { return 10; } } public class Snake extends Reptile { protected double getHeight() throws Exception { // DOES NOT COMPILE return 2; } protected int getLength() throws InsufficientDataException { // DOES NOT COMPILE return 10; } } Unlike the earlier example, neither of the methods in the child class of this code will compile. The getHeight() method in the parent class throws an InsufficientDataException, whereas the method in the child class throws an Exception. Since Exception is not a subclass of InsufficientDataException, the third rule of overriding methods is violated and the code will not compile. Coincidentally, Exception is a superclass of InsufficientDataException. Next, the getLength() method doesn't throw an exception in the parent class, but it does throw an exception, InsufficientDataException, in the child class. In this manner, the child class defines a new exception that the parent class did not, which is a violation of the third rule of overriding methods. The last three rules of overriding a method may seem arbitrary or confusing at first, but as you'll see later in this chapter when we discuss polymorphism, they are needed for consistency of the language. Without these rules in place, it is possible to create contradictions within the Java language.

literal

When a number is present in the code, it is called a "literal". By default, Java assumes you are defining an int value with a literal. You can add underscores anywhere except at the beginning of a literal, the end of a literal, right before a decimal point, or right after a decimal point. A numeric, character, boolean, or String value that is typed into the code.

logical operators bitwise operators conditional operators

When they're applied to boolean data types Called bitwise operators - When they're applied to numeric data types The logical operators, (&), (|), and (^), may be applied to both numeric and boolean data types AND is only true if both operands are true. Inclusive OR is only false if both operands are false. Exclusive OR is only true if the operands are different. conditional operators, && and ||, which are often referred to as short-circuit operators. short-circuit operators are nearly identical to the logical operators, & and |, respectively, except that the right-hand side of the expression may never be evaluated if the final result can be determined by the left-hand side of the expression.

Creating Dates and Times

When working with dates and times, the first thing to do is decide how much information you need. The exam gives you three choices: LocalDate: Contains just a date-no time and no time zone. A good example of LocalDate is your birthday this year. It is your birthday for a full day regardless of what time it is. LocalTime: Contains just a time-no date and no time zone. A good example of LocalTime is midnight. It is midnight at the same time every day. LocalDateTime: Contains both a date and time but no time zone. A good example of LocalDateTime is "the stroke of midnight on New Year's." Midnight on January 2 isn't nearly as special, and clearly an hour after midnight isn't as special either. Each of the three classes has a static method called now() that gives the current date and time. System.out.println(LocalDate.now()); 2015-01-20 System.out.println(LocalTime.now()); 12:45:18.401 System.out.println(LocalDateTime.now()); 2015-01-20T12:45:18.401 Java uses T to separate the date and time when converting LocalDateTime to a String. Just remember that the month comes before the date. Also, Java tends to use a 24-hour clock The method signatures are as follows: public static LocalDate of(int year, int month, int dayOfMonth) public static LocalDate of(int year, Month month, int dayOfMonth) These three times are all different but within a minute of each other. The method signatures are as follows: LocalTime time1 = LocalTime.of(6, 15); // hour and minute LocalTime time2 = LocalTime.of(6, 15, 30); // + seconds LocalTime time3 = LocalTime.of(6, 15, 30, 200); // + nanoseconds public static LocalTime of(int hour, int minute) public static LocalTime of(int hour, int minute, int second) public static LocalTime of(int hour, int minute, int second, int nanos) static LocalTime of(int hour, int minute) public static LocalTime of(int hour, int minute, int second) public static LocalTime of(int hour, int minute, int second, int nanos) Finally, we can combine dates and times: LocalDateTime dateTime1 = LocalDateTime.of(2015, Month.JANUARY, 20, 6, 15, 30); LocalDateTime dateTime2 = LocalDateTime.of(date1, time1); This time there are a lot of method signatures since there are more combinations. The method signatures are as follows: public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute) public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second) public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanos) public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute) public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second) public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second, int nanos) public static LocalDateTime of(LocalDate date, LocalTime

Declaring and Initializing Variables

When you declare a variable, you need to state the variable type along with giving it a name To initialize a variable(Give it a value), you just type the variable name followed by an equal sign, followed by the desired value You can declare many variables in the same declaration as long as they are all of the same type. How many declared and initialized? int i1, i2, i3 = 0; As you should expect, three variables were declared: i1, i2, and i3. However, only one of those values was initialized: i3. The other two remain declared but not yet initialized. That's the trick. Each snippet separated by a comma is a little declaration of its own. The initialization of i3 only applies to i3. It doesn't have anything to do with i1 or i2 despite being in the same statement.

Hiding Variables

When you hide a variable, you define a variable with the same name as a variable in a parent class. This creates two copies of the variable within an instance of the child class: one instance defined for the parent reference and another defined for the child reference. As when hiding a static method, you can't override a variable; you can only hide it. Also similar to hiding a static method, the rules for accessing the parent and child variables are quite similar. If you're referencing the variable from within the parent class, the variable defined in the parent class is used. Alternatively, if you're referencing the variable from within a child class, the variable defined in the child class is used. Likewise, you can reference the parent value of the variable with an explicit use of the super keyword. Consider the following example: public class Rodent { protected int tailLength = 4; public void getRodentDetails() { System.out.println("[parentTail="+tailLength+"]"); } } public class Mouse extends Rodent { protected int tailLength = 8; public void getMouseDetails() { System.out.println("[tail="+tailLength +",parentTail="+super.tailLength+"]"); } public static void main(String[] args) { Mouse mouse = new Mouse(); mouse.getRodentDetails(); mouse.getMouseDetails(); } } This code compiles without issue and outputs the following when executed: [parentTail=4] [tail=8,parentTail=4] Notice that the instance of Mouse contains two copies of the tailLength variables: one defined in the parent and one defined in the child. These instances are kept separate from each other, allowing our instance of Mouse to reference both tailLength values independently. In the first method call, getRodentDetails(), the parent method outputs the parent value of the tailLength variable. In the second method call, getMouseDetails(), the child method outputs both the child and parent version of the tailLength variables, using the super keyword to access the parent variable's value. The important thing to remember is that there is no notion of overriding a member variable. For example, there is no code change that could be made to cause Java to override the value of tailLength, making it the same in both parent and child. These rules are the same regardless of whether the variable is an instance variable or a static variable. Don't Hide Variables in Practice Although Java allows you to hide a variable defined in a parent class with one defined in a child class, it is considered an extremely poor coding practice. For example, take a look at the following code, which uses a hidden variable length, marked as public in both parent and child classes. public class Animal { public int length = 2; } public class Jellyfish extends Animal { public int length = 5; public static void main(String[] args) { Jellyfish jellyfish = new Jellyfish(); Animal animal = new Jellyfish(); System.out.println(jellyfish.length); System.out.println(animal.length); } } This code compiles without issue. Here's the output: 5 2 Notice the same type of object was created twice, but the reference to the object determines which value is seen as output. If the object Jellyfish was passed to a method by an Animal reference, as you'll see in the section "Understanding Polymorphism," later in this chapter, the wrong value might be used. Hiding variables makes the code very confusing and difficult to read, especially if you start modifying the value of the variable in both the parent and child methods, since it may not be clear which variable you're updating. When defining a new variable in a child class, it is considered good coding practice to select a name for the variable that is not already a public, protected, or default variable in use in a parent class. Hiding private variables is considered less problematic because the child class did not have access to the variable in the parent class to begin with.

Overloading Constructors

You can have multiple constructors in the same class as long as they have different method signatures. When overloading methods, the method name should be same and parameter list should be different. With constructors, the name is always the same since it has to be the same as the name of the class. This means constructors must have different parameters in order to be overloaded. This example shows two constructors: public class Hamster { private String color; private int weight; public Hamster(int weight) { // first constructor this.weight = weight; color = "brown"; } public Hamster(int weight, String color) { // second constructor this.weight = weight; this.color = color; } } One of the constructors takes a single int parameter. The other takes an int and a String. These parameter lists are different, so the constructors are successfully overloaded. There is a problem here, though. There is a bit of duplication. In programming, even a bit of duplication tends to turn into a lot of duplication as we keep adding "just one more thing." What we really want is for the first constructor to call the second constructor with two parameters. You might be tempted to write this: public Hamster(int weight) { Hamster(weight, "brown"); // DOES NOT COMPILE } This will not work. Constructors can be called only by writing new before the name of the constructor. They are not like normal methods that you can just call. What happens if we stick new before the constructor name? public Hamster(int weight) { new Hamster(weight, "brown"); // Compiles but does not do what we want } This attempt does compile. It doesn't do what we want, though. When the constructor with one parameter is called, it creates an object with the default weight and color. It then constructs a different object with the desired weight and color and ignores the new object. That's not what we want. We want weight and color set on the object we are trying to instantiate in the first place. Java provides a solution: this-yes, the same keyword we used to refer to instance variables. When this is used as if it were a method, Java calls another constructor on the same instance of the class. public Hamster(int weight) { this(weight, "brown"); } Success! Now Java calls the constructor that takes two parameters. weight and color get set on this instance. this() has one special rule you need to know. If you choose to call it, the this() call must be the first noncommented statement in the constructor. public Hamster(int weight) { System.out.println("in constructor"); // ready to call this this(weight, "brown"); // DOES NOT COMPILE } Even though a print statement on line 4 doesn't change any variables, it is still a Java statement and is not allowed to be inserted before the call to this(). The comment on line 5 is just fine. Comments don't run Java statements and are allowed anywhere.

comment

a single-line comment (//), a multiline comment (/* */), and a Javadoc comment (/** */).

continue statement

a statement that causes flow to finish the execution of the current loop. the continue statement transfers control to the boolean expression that determines if the loop should continue.

Local Variables

a variable defined within a method. Local variables must be initialized before use. They do not have a default value and contain garbage data until initialized. The compiler will not let you read an uninitialized value.

add()

add() The add() methods insert a new value in the ArrayList. The method signatures are as follows: boolean add(E element) void add(int index, E element) Don't worry about the boolean return value. It always returns true. It is there because other classes in the collections family need a return value in the signature when adding an element. Since add() is the most critical ArrayList method you need to know for the exam, we are going to show a few sets of examples for it. Let's start with the most straightforward case: ArrayList list = new ArrayList(); list.add("hawk"); // [hawk] list.add(Boolean.TRUE); // [hawk, true] System.out.println(list); // [hawk, true] add() does exactly what we expect: it stores the String in the no longer empty ArrayList. It then does the same thing for the boolean. This is okay because we didn't specify a type for ArrayList; therefore, the type is Object, which includes everything except primitives. It may not have been what we intended, but the compiler doesn't know that. Now, let's use generics to tell the compiler we only want to allow String objects in our ArrayList: ArrayList<String> safer = new ArrayList<>(); safer.add("sparrow"); safer.add(Boolean.TRUE); // DOES NOT COMPILE This time the compiler knows that only Stringobjects are allowed in and prevents the attempt to add a boolean. Now let's try adding multiple values to different positions. List<String> birds = new ArrayList<>(); birds.add("hawk"); // [hawk] birds.add(1, "robin"); // [hawk, robin] birds.add(0, "blue jay"); // [blue jay, hawk, robin] birds.add(1, "cardinal"); // [blue jay, cardinal, hawk, robin] System.out.println(birds); // [blue jay, cardinal, hawk, robin] When a question has code that adds objects at indexed positions, draw it so that you won't lose track of which value is at which index. In this example, line 5 adds "hawk" to the end of birds. Then line 6 adds "robin"to index 1 of birds, which happens to be the end. Line 7 adds "blue jay" to index 0, which happens to be the beginning of birds. Finally, line 8 adds "cardinal" to index 1, which is now near the middle of birds.

Method Name

an identifier may only contain letters, numbers, $, or _. Also, the first character is not allowed to be a number, and reserved words are not allowed. public void walk1() { } public void 2walk() { } // DOES NOT COMPILE public walk3 void() { } // DOES NOT COMPILE public void Walk_$() { } public void() { } // DOES NOT COMPILE walk1() is a valid method declaration with a traditional name. 2walk() doesn't compile because identifiers are not allowed to begin with numbers. walk3() doesn't compile because the method name is before the return type. Walk_$() is a valid method declaration. While it certainly isn't good practice to start a method name with a capital letter and end with punctuation, it is legal. The final line of code doesn't compile because the method name is missing.

controlling the execution of the program

break statement: Transfers the flow of control out of the enclosing statement continue statement: Causes flow to finish the execution of the current loop

cmd command

cd C:\temp - To change the directory to the specified path javac filename - To compile a file java filename - To run a file

instance initializers

code blocks appear outside a method

Static Variables

constant - never change during the program. They useall uppercase letters with underscores between "words."

Static Methods and Fields

don't require an instance of the class. They are shared among all users of the class. The main() method is a static method. That means you can call it by the classname. Two main purposes: 1. For utility or helper methods that don't require any object state. - eliminates the need for the caller to instantiate the object just to call the method. 2. For state that is shared by all instances of a class, like a counter - All instances must share the same state.

Q: Which of the following lines of code compile? (Choose all that apply.) A. double d3 = 1_234.0_; B. double d4 = 1_234.0; C. None of these are correct. D. int i1 = 1_234; E. double d1 = 1_234_.0; F. double d2 = 1_234._0;

double d4 = 1_234.0; int i1 = 1_234; Underscores are allowed as long as they are directly between two other digits. This means options D and B are correct. Options E and F are incorrect because the underscore is adjacent to the decimal point. Option A is incorrect because the underscore is the last character.

equals()

equals() Finally, ArrayList has a custom implementation of equals() so you can compare two lists to see if they contain the same elements in the same order. boolean equals(Object object) The following shows an example: List<String> one = new ArrayList<>(); List<String> two = new ArrayList<>(); System.out.println(one.equals(two)); // true one.add("a"); // [a] System.out.println(one.equals(two)); // false two.add("a"); // [a] System.out.println(one.equals(two)); // true one.add("b"); // [a,b] two.add(0, "b"); // [b,a] System.out.println(one.equals(two)); // false On line 33, the two ArrayList objects are equal. An empty list is certainly the same elements in the same order. On line 35, the ArrayList objects are not equal because the size is different. On line 37, they are equal again because the same one element is in each. On line 40, they are not equal. The size is the same and the values are the same, but they are not in the same order.

Q: What is true about the following code? (Choose all that apply.) public class Bear { protected void finalize() { System.out.println("Roar!"); } public static void main(String[] args) { Bear bear = new Bear(); bear = null; System.gc(); } }

finalize() might or might not be called Garbage collection might or might not run. Calling System.gc() suggests that Java might wish to run the garbage collector. Java is free to ignore the request, making option E correct. finalize() runs if an object attempts to be garbage collected, making option B correct.

logical complement operator, !

flips the value of a boolean expression.

non-primitive/Primitive valuse

int primitives -> default to 0. boolean primitives -> default to false float and double primitives default to 0.0 all non-primitive values default to null

assignment operator

is a binary operator that modifies, or assigns, the variable on the left-hand side of the operator, with the result of the value on the right-hand side of the equation. The simplest assignment operator is the = assignment, which you have seen already:

Writing to a variable

is known as setting it.

StringBuilder class

is not immutable. 15 StringBuilder alpha = new StringBuilder(); 16 for(char current = 'a'; current <= 'z'; current++) 17 alpha.append(current); 18 System.out.println(alpha); On line 15, a new StringBuilder object is instantiated. The call to append() on line 17 adds a character to the StringBuilder object each time through the for loop and appends the value of current to the end of alpha. This code reuses the same StringBuilder without creating an interim String each time. StringBuilder changes its own state and returns a reference to itself! There are three ways to construct a StringBuilder: StringBuilder sb1 = new StringBuilder(); StringBuilder sb2 = new StringBuilder("animal"); StringBuilder sb3 = new StringBuilder(10); The first says to create a StringBuilder containing an empty sequence of characters and assign sb1 to point to it. The second says to create a StringBuilder containing a specific value and assign sb2 to point to it. For the first two, it tells Java to manage the implementation details. The final example tells Java that we have some idea of how big the eventual value will be and would like the StringBuilder to reserve a certain number of slots for characters. For StringBuilder, Java knows the size is likely to change as the object is used. When StringBuilder is constructed, it may start at the default capacity (which happens to be 16) or one of the programmer's choosing. In the example, we request a capacity of 5. At this point, the size is 0 since no characters have been added yet, but we have space for 5. Next we add four characters. At this point, the size is 4 since four slots are taken. The capacity is still 5. Then we add three more characters. The size is now 7 since we have used up seven slots. Because the capacity wasn't large enough to store seven characters, Java automatically increased it for us. charAt(), indexOf(), length(), and substring() These four methods work exactly the same as in the String class. Be sure you can identify the output of this example: StringBuilder sb = new StringBuilder("animals"); String sub = sb.substring(sb.indexOf("a"), sb.indexOf("al")); int len = sb.length(); char ch = sb.charAt(6); System.out.println(sub + " " + len + " " + ch); The correct answer is anim 7 s. The indexOf() method calls return 0 and 4, respectively. substring() returns the String starting with index 0 and ending right before index 4. length() returns 7 because it is the number of characters in the StringBuilder rather than an index. Finally, charAt() returns the character at index 6. Here we do start with 0 because we are referring to indexes. If any of this doesn't sound familiar, go back and read the section on String again. Notice that substring() returns a String rather than a StringBuilder. That is why sb is not changed. substring() is really just a method that inquires about where the substring happens to be. append() The append() method is by far the most frequently used method in StringBuilder. In fact, it is so frequently used that we just started using it without comment. Luckily, this method does just what it sounds like: it adds the parameter to the StringBuilder and returns a reference to the current StringBuilder. One of the method signatures is as follows: StringBuilder append(String str) Notice that we said oneof the method signatures. There are more than 10 method signatures that look similar but that take different data types as parameters. All those methods are provided so you can write code like this: StringBuilder sb = new StringBuilder().append(1).append('c'); sb.append("-").append(true); System.out.println(sb); // 1c-true Nice method chaining, isn't it? append() is called directly after the constructor. By having all these method signatures, you can just call append() without having to convert your parameter to a String first. insert() The insert() method adds characters to the StringBuilder at the requested index and returns a reference to the current StringBuilder. Just like append(), there are lots of method signatures for different types. Here's one: StringBuilder insert(int offset, String str) Pay attention to the offset in these examples. It is the index where we want to insert the requested parameter. StringBuilder sb = new StringBuilder("animals"); sb.insert(7, "-"); // sb = animals- sb.insert(0, "-"); // sb = -animals- sb.insert(4, "-"); // sb = -ani-mals- System.out.println(sb); Line 4 says to insert a dash at index 7, which happens to be the end of sequence of characters. Line 5 says to insert a dash at index 0, which happens to be the very beginning. Finally, line 6 says to insert a dash right before index 4. The exam creators will try to trip you up on this. As we add and remove characters, their indexes change. When you see a question dealing with such operations, draw what is going on so you won't be confused. delete() and deleteCharAt() The delete() method is the opposite of the insert() method. It removes characters from the sequence and returns a reference to the current StringBuilder. The deleteCharAt() method is convenient when you want to delete only one character. The method signatures are as follows: StringBuilder delete(int start, int end) StringBuilder deleteCharAt(int index) The following code shows how to use these methods: StringBuilder sb = new StringBuilder("abcdef"); sb.delete(1, 3); // sb = adef sb.deleteCharAt(5); // throws an exception First, we delete the characters starting with index 1 and ending right before index 3. This gives us adef. Next, we ask Java to delete the character at position 5. However, the remaining value is only four characters long, so it throws a StringIndexOutOfBoundsException. reverse() After all that, it's time for a nice, easy method. The reverse() method does just what it sounds like: it reverses the characters in the sequences and returns a reference to the current StringBuilder. The method signature is as follows: StringBuilder reverse() The following code shows how to use this method: StringBuilder sb = new StringBuilder("ABC"); sb.reverse(); System.out.println(sb); As expected, this prints CBA. This method isn't that interesting. Maybe the exam creators like to include it to encourage you to write down the value rather than relying on memory for indexes. toString() The last method converts a StringBuilder into a String. The method signature is as follows: String toString() The following code shows how to use this method: String s = sb.toString(); Often StringBuilder is used internally for performance purposes but the end result needs to be a String. For example, maybe it needs to be passed to another method that is expecting a String. Here are the differences between the StringBuffer and StringBuilder Java String methods: StringBuffer: Thread-safe Provides methods to insert characters into the buffer Less efficient StringBuilder: Not thread-safe Provides methods to perform append and insert operations to accept data Less memory allocation

unary operator

is one that requires exactly one operand, or variable, to function.

Casting primitives

is required any time you are going from a larger numerical data type to a smaller numerical data type, or converting from a floating-point number to an integral value. ex: "short z = (short)(x * y);"

Inheritance

is the process by which the new child subclass automatically includes any public or protected primitives, objects, or methods defined in the parent class. Java supports single inheritance, by which a class may inherit from only one direct parent class. Java also supports multiple levels of inheritance, by which one class may extend another class, which in turn extends another class. You can extend a class any number of times, allowing each descendent to gain access to its ancestor's members. By design, Java doesn't support multiple inheritance in the language because studies have shown that multiple inheritance can lead to complex, often difficult-to-maintain code. Java does allow one exception to the single inheritance rule: classes may implement multiple interfaces, as you'll see later in this chapter.

Optional Exception List

it is optional and where in the method signature it goes if present. public void zeroExceptions() { } public void oneException() throws IllegalArgumentException { } public void twoExceptions() throws IllegalArgumentException, InterruptedException { }

Redundant Imports

java.lang - This package is special in that it is automatically imported. everything in java.lang is automatically considered to be imported.

Method

length()

[L

means it is an array,

Deferred execution

means that code is specified now but will run later. In this case, later is when the print() method calls it.

Method overloading

occurs when there are different method signatures with the same name but different type parameters. These are all valid overloaded methods: public void fly(int numMiles) { } public void fly(short numFeet) { } public boolean fly() { return false; } void fly(int numMiles, short numFeet) { } public void fly(short numFeet, int numMiles) throws Exception { }

Base 10

octal (digits 0-7), which uses the number 0 as a prefix-for example, 017 hexadecimal (digits 0-9 and letters A-F), which uses the number 0 followed by x or X as a prefix-for example, 0xFF binary (digits 0-1), which uses the number 0 followed by b or B as a prefix-for example, 0b10

Return Type

public void walk1() { } public void walk2() { return; } public String walk3() { return ""; } public String walk4() { } // DOES NOT COMPILE public walk5() { } // DOES NOT COMPILE String walk6(int a) { if (a == 4) return ""; } // DOES NOT COMPILE Since the return type of walk1() is void, the return statement is optional. walk2() shows the optional return statement that correctly doesn't return anything. walk3() is a valid method with a String return type and a return statement that returns a String. walk4() doesn't compile because the return statement is missing. walk5() doesn't compile because the return type is missing. walk6() is a little tricky. There is a return statement, but it doesn't always get run. If a is 6, the return statement doesn't get executed. Since the String always needs to be returned, the compiler complains.

Reference Types

refers to an object (an instance of a class) a reference "points" to an object by storing the memory address where the object is located, a concept referred to as a pointer.

Garbage Collection

refers to the process of automatically freeing memory on the heap by deleting objects that are no longer reachable in your program. An object is no longer reachable when one of two situations occurs: The object no longer has any references pointing to it. All references to the object have gone out of scope. Java provides a method called System.gc().

negation operator, -

reverses the sign of a numeric expression

Scope

rules on scope: Local variables-in scope from declaration to end of block Instance variables-in scope from declaration until object garbage collected Class variables-in scope from declaration until program ends

Converting Between array and List

turning an ArrayList into an array: String[] stringArray = list.toArray(new String[0]); The advantage of specifying a size of 0 for the parameter is that Java will create a new array of the proper size for the return value. If you like, you can suggest a larger array to be used instead. If the ArrayList fits in that array, it will be returned. Otherwise, a new one will be created. Converting from an array to a List is more interesting. The original array and created array backed List are linked. When a change is made to one, it is available in the other. It is a fixed-size list and is also known a backed List because the array changes with it. Pay careful attention to the values here: String[] array = { "hawk", "robin" }; // [hawk, robin] List<String> list = Arrays.asList(array); // returns fixed size list System.out.println(list.size()); // 2 list.set(1, "test"); // [hawk, test] array[0] = "new"; // [new, test] for (String b : array) System.out.print(b + " "); // new test list.remove(1); // throws UnsupportedOperation Exception Line 21 converts the array to a List. Note that it isn't the java.util.ArrayList we've grown used to. It is a fixed-size, backed version of a List. Line 23 is okay because set() merely replaces an existing value. It updates both array and list because they point to the same data store. Line 24 also changes both array and list. Line 25 shows the array has changed to new test. Line 26 throws an exception because we are not allowed to change the size of the list.

constructor

which is a special type of method that creates a new object.

conditional statements

while statement: Checks for the condition first and then executes the loop do-while statement: A condition will always be executed at least once, before the test is made to determine whether it should continue before it checks for the condition switch statement: Executes a section of code, depending on the value of an expression compared to a number of possible choices specified in the statement itself for statement: Repeatedly executes the loop while a condition is true and controls the number of times a loop will iterate if-else statement: Provides two possible sets of actions to perform depending on the outcome of the conditional expression

autoboxing

you can just type the primitive value and Java will convert it to the relevant wrapper class for you.


Conjuntos de estudio relacionados

Entrepreneurship Small Business Exam #1(Ch.5)

View Set

Project Management Professional (PMP) Exam

View Set

NOS 230 Final, Chapter 11, TNE 255 Final Exam

View Set

Autonomic Nervous System - Structure and Function

View Set

ISM3113 Chapter 10 Multiple and T/F

View Set

Chapter 2 organizational ethics and values

View Set