Chapter 12 Java Fundamentals Flashcards
Applying the final Modifier
- Marking a
variable
final means the value cannot be changed after it is assigned. - Marking a
method
orclass
final means it cannot be overridden or extended
DECLARING FINAL LOCAL VARIABLES
- don’t need to assign a value when a final variable is declared.
- The rule is only that it must be assigned a value before it can be used.
Just because a variable reference is marked final does not mean the object associated with it cannot be modified.
Consider the following code snippet:
final StringBuilder cobra = new StringBuilder(); cobra.append("Hssssss"); cobra.append("Hssssss!!!");
In the cobra example, the object reference is constant, but that doesn’t mean the data in the class is constant.
ADDING FINAL TO INSTANCE AND STATIC VARIABLES
- Instance and static class variables can also be marked final.
- If an instance variable is marked final, then it must be assigned a value when it is declared or when the object is instantiated.
- it cannot be assigned a value more than once
instance final variables
- declared
- instance initializers
- cosntructors
static final variables
- declared
- instance initializers
WRITING FINAL METHODS
- Methods marked final cannot be overridden by a subclass.
- This essentially prevents any polymorphic behavior on the method call
- ensures that a specific version of the method is always called.
MARKING CLASSES FINAL
final modifier can be applied to class declarations as well.
A final class is one that cannot be extended.
implicit modifier
a modifier that is inserted automatically by the compiler is referred to as an implicit modifier
Working with Enums
- a type that can only have a finite set of values, such as days of the week, seasons of the year, primary colors, etc.
- An enumeration is like a fixed set of constants.
- In Java, an enum, short for “enumerated type,”
- can be a top-level type like a class or interface,
- as well as a nested type like an inner class.
- enum provides type-safe checking
- Cannot extend and enum
- an enum is a type of class that mainly contains static members. It also includes some helper methods like name()
- An enum provides a values() method to get an array of all of the values.
- retrieving an enum value from a String using the valueOf() method.
CREATING SIMPLE ENUMS
~~~
public enum Season {
WINTER, SPRING, SUMMER, FALL
}
~~~
- To create an enum, use the enum keyword.
- Then list all of the valid types for that enum.
- semi-colon (;) is optional for this example (optional when our enum is composed solely of a list of values, it is required if there is anything in the enum besides the values.)
Enum values are considered constants and are commonly written using snake case, often stylized as snake_case.
snake_case
Season s = Season.SUMMER; System.out.println(Season.SUMMER); // SUMMER System.out.println(s == Season.SUMMER); // true
- enums print the name of the enum when
toString()
is called. -
can use
equals()
or==
to compare enums, since each enum value is initialized only once in the Java Virtual Machine (JVM).
for(Season season: Season.values()) { System.out.println(season.name() + " " + season.ordinal()); }
- An enum provides a
values()
method to get an array of all of the values. -
name()
return string, value name -
ordinal()
return int, the order of value declared
The output shows that each enum value has a corresponding int value, and the values are listed in the order in which they are declared.
WINTER 0 SPRING 1 SUMMER 2 FALL 3
if ( Season.SUMMER == 2) {} // DOES NOT COMPILE
You can’t compare an int and enum value directly anyway since an enum is a type, like a Java class, and not a primitive int.
Season s = Season.valueOf("SUMMER"); // SUMMER
retrieving an enum value from a String using the valueOf()
method.
Season t = Season.valueOf("summer"); // Throws an exception at runtime
There is no enum value with the lowercase name summer. Java throws an IllegalArgumentException.
Exception in thread "main" java.lang.IllegalArgumentException: No enum constant enums.Season.summer
public enum ExtendedSeason extends Season { } // DOES NOT COMPILE
One thing that you can’t do is extend an enum.
The values in an enum are all that are allowed.
You cannot add more by extending the enum.
USING ENUMS IN SWITCH STATEMENTS
Pay attention to the case values in this code:
Season summer = Season.SUMMER; switch (summer) { case WINTER: System.out.println("Get out the sled!"); break; case SUMMER: System.out.println("Time for the pool!"); break; default: System.out.println("Is it summer yet?"); }
switch (summer) { case Season.FALL: // DOES NOT COMPILE System.out.println("Rake some leaves!"); break; case 0: // DOES NOT COMPILE System.out.println("Get out the sled!"); break; }
- The first case statement does not compile because Season is used in the case value.
- the second case statement does not compile becuase can’t compare enums with int values,
ADDING CONSTRUCTORS, FIELDS, AND METHODS
1: public enum Season { 2: WINTER("Low"), SPRING("Medium"), SUMMER("High"), FALL("Medium"); 3: private final String expectedVisitors; 4: private Season(String expectedVisitors) { 5: this.expectedVisitors = expectedVisitors; 6: } 7: public void printExpectedVisitors() { 8: System.out.println(expectedVisitors); 9: } }
- On line 2, the list of enum values ends with a semicolon ( ;). While this is optional when our enum is composed solely of a list of values, it is required if there is anything in the enum besides the values.
- We mark the instance variable final on line 3 so that our enum values are considered immutable.
- Although this is certainly not required, it is considered a good coding practice to do so.
- Since enum values are shared by all processes in the JVM, it would be problematic if one of them could change the value inside an enum.
How do we call an enum method?
Season.SUMMER.printExpectedVisitors();
public enum OnlyOne { ONCE(true); private OnlyOne(boolean b) { System.out.print("constructing,"); } } public class PrintTheOne { public static void main(String[] args) { System.out.print("begin,"); OnlyOne firstCall = OnlyOne.ONCE; // prints constructing, OnlyOne secondCall = OnlyOne.ONCE; // doesn't print anything System.out.print("end"); } }
The first time that we ask for any of the enum values, Java constructs all of the enum values. After that, Java just returns the already constructed enum values.
This class prints the following:
begin,constructing,end
CREATING IMMUTABLE OBJECTS
The immutable objects pattern is an object-oriented design pattern
in which an object cannot be modified after it is created.
Instead of modifying an immutable object,
you create a new object that contains any properties from the original object you want copied over.
Immutable objects are invaluable in concurrent applications
since the state of the object cannot change or be corrupted by a rogue thread.
enum abstract method
- The enum itself has an abstract method.
- This means that each and every enum value is required to implement this method.
- If we forget to implement the method for one of the values, then we get a compiler error.
public enum Season { WINTER { public String getHours() { return "10am-3pm"; } }, SPRING { public String getHours() { return "9am-5pm"; } }, SUMMER { public String getHours() { return "9am-7pm"; } }, FALL { public String getHours() { return "9am-5pm"; } }; public abstract String getHours(); }
default implementation and override
If we don’t want each and every enum value to have a method, we can create a default implementation and override it only for the special cases.
public enum Season { WINTER { public String getHours() { return "10am-3pm"; } //override }, SUMMER { public String getHours() { return "9am-7pm"; } //override }, SPRING, FALL; public String getHours() { return "9am-5pm"; } //default implemenation }
> [!NOTE]
You might have noticed that in each of these enum examples, the list of values came first.
This was not an accident. Whether the enum is simple or contains a ton of methods, constructors, and variables, the compiler requires that the list of values always be declared first.
the compiler requires that the list of values always be declared first.
Creating Nested Classes
A nested class
is a class that is defined within another class. A nested class can come in one of four
flavors.
* Inner class
: A non-static type defined at the member level of a class
* Static nested class
: A static type defined at the member level of a class
* Local class
: A class defined within a method body
* Anonymous class
: A special case of a local class that does not have a name
> [!NOTE]
By convention and throughout this chapter, we often use the term inner or nested class to apply to other Java types, including interfaces and enums.
Although you are unlikely to encounter this on the exam, interfaces
and enums
can be declared as both inner classes and static nested classes, but not as local or anonymous classes.
interfaces
and enums
can be declared as both inner classes and static nested classes
, but not as local or anonymous classes.
DECLARING AN INNER CLASS
An inner class
, also called a member inner class
, is a non-static type defined at the member level of a class (the same level as the methods, instance variables, and constructors). Inner classes have the following properties:
- Can be declared
public, protected, package‐private (default), or private
- Can
extend
any class andimplement
interfaces - Can be marked
abstract
orfinal
- Cannot declare
static fields or methods
, except forstatic final
fields - Can access members of the outer class including
private
members
The last property is actually pretty cool. It means that the inner class can access variables in the outer class without doing anything special.
1: public class Outer { 2: private String greeting = "Hi"; 3: 4: protected class Inner { 5: public int repeat = 3; 6: public void go() { 7: for (int i = 0; i < repeat; i++) 8: System.out.println(greeting); 9: } 10: } 11: 12: public void callInner() { 13: Inner inner = new Inner(); 14: inner.go(); 15: } 16: public static void main(String[] args) { 17: Outer outer = new Outer(); 18: outer.callInner(); 19: } }
20: public static void main(String[] args) { 21: Outer outer = new Outer(); 22: Inner inner = outer.new Inner(); // create the inner class 23: inner.go(); 24: }
Inner classes can have the same variable names as outer classes
1: public class A { 2: private int x = 10; 3: class B { 4: private int x = 20; 5: class C { 6: private int x = 30; 7: public void allTheX() { 8: System.out.println(x); // 30 9: System.out.println(this.x); // 30 10: System.out.println(B.this.x); // 20 11: System.out.println(A.this.x); // 10 12: } } } 13: public static void main(String[] args) { 14: A a = new A(); 15: A.B b = a.new B(); 16: A.B.C c = b.new C(); 17: c.allTheX(); 18: }}
- Line 15 uses the awkward syntax to instantiate a B. Notice the type is A.B. We could have written B as the type because that is available at the member level of B. Java knows where to look for it.
- On line 16, we instantiate a C. This time, the A.B.C type is necessary to specify. C is too deep for Java to know where to look.
- Then line 17 calls a method on c.
- Lines 8 and 9 are the type of code that we are used to seeing. They refer to the instance variable on the current class–the one declared on line 6 to be precise.
- Line 10 uses this in a special way. We still want an instance variable. But this time we want the one on the B class, which is the variable on line 4.
- Line 11 does the same thing for class A, getting the variable from line 2.
.CLASS FILES FOR INNER CLASSES
test
INNER CLASSES REQUIRE AN INSTANCE
public class Fox { private class Den {} public void goHome() { new Den(); // COMPILE } public static void visitFriend() { new Den(); // DOES NOT COMPILE } } public class Squirrel { public void visitFox() { new Den(); // DOES NOT COMPILE } }
- The first constructor call compiles because
goHome()
is an instance method, and therefore the call is associated with the this instance. - The second call does not compile because it is called inside a static method. You can still call the constructor, but you have to explicitly give it a reference to a Fox instance.
- The last constructor call does not compile for two reasons. Even though it is an instance method, it is not an instance method inside the Fox class. Adding a Fox reference would not fix the problem entirely, though. Den is private and not accessible in the Squirrel class.