Class Flashcards

1
Q

private constructors

A

> [!NOTE]
Having only private constructors in a class tells the compiler not to provide a default no-argument constructor.It also prevents other classes from instantiating the class.This is useful when a class has only static methods or the developer wants to have full control of all calls to create new instances of the class.Remember, static methods in the class, including a main() method, may access private members, including private constructors.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

ARE CLASSES WITH ONLY PRIVATE CONSTRUCTORS CONSIDERED FINAL?

A
  • only an inner class defined in the class itself can extend it.
  • An inner class is the only one that would have access to a private constructor and be able to call super().
  • Other top-level classes cannot extend such a class.
  • Don’t worry—knowing this fact is not required for the exam. We include it here for those who were curious about declaring only private constructors.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

REVIEWING CONSTRUCTOR RULES

A
  1. The first statement of every constructor is a call to an overloaded constructor via this(), or a direct parent constructor via super().
  2. If the first statement of a constructor is not a call to this() or super(), then the compiler will insert a no-argument super() as the first statement of the constructor.
  3. Calling this() and super() after the first statement of a constructor results in a compiler error.
  4. If the parent class doesn’t have a no-argument constructor, then every constructor in the child class must start with an explicit this() or super() constructor call.
  5. If the parent class doesn’t have a no-argument constructor and the child doesn’t define any constructors, then the child class will not compile.
  6. If a class only defines private constructors, then it cannot be extended by a top-level class.
  7. All final instance variables must be assigned a value exactly once by the end of the constructor. Any final instance variables not assigned a value will be reported as a compiler error on the line the constructor is declared.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

To override a method, you must follow a number of rules.

A

The compiler performs the following checks when you override a method:
1. The method in the child class must have the same signature as the method in the parent class.
2. The method in the child class must be at least as accessible as the method in the parent class.
3. The method in the child class may not declare a checked exception that is new or broader than the class of any exception declared in the parent class method.
4. If the method returns a value, it must be the same or a subtype of the method in the parent class, known as covariant return types.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

DEFINING SUBTYPE AND SUPERTYPE

A

When discussing inheritance and polymorphism, we often use the word subtype rather than subclass, since Java includes interfaces.
A subtype is the relationship between two types where one type inherits the other.
If we define X to be a subtype of Y, then one of the following is true :

  • X and Y are classes, and X is a subclass of Y.
  • X and Y are interfaces, and X is a subinterface of Y.
  • X is a class and Y is an interface, and X implements Y (either directly or through an inherited class).

Likewise, a supertype is the reciprocal relationship between two types where one type is the ancestor of the other. Remember, a subclass is a subtype, but not all subtypes are subclasses.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

> [!NOTE]
A simple test for covariance is the following:
Given an inherited return type A and an overriding return type B, can you assign an instance of B to a reference variable for A without a cast?
If so, then they are covariant.
This rule applies to primitive types and object types alike.
If one of the return types is void, then they both must be void, as nothing is covariant with void except itself.

A
  • covariance test
  • assing instance of B to a reference variable for A without cast
  • This rule applices to primitive types and object types
  • If one of the return types is void, then they both must be void, as nothing is covariant with void except itself.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Review of Overloading a Generic Method

A

Cannot overload methods by changing the generic type due to type erasure.
To review, only one of the two methods is allowed in a class because type erasure will reduce both sets of arguments to (List input).

public class LongTailAnimal {
    protected void chew(List<Object> input) {}
    protected void chew(List<Double> input) {} // DOES NOT COMPILE
}

For the same reason, you also can’t overload a generic method in a parent class.

public class LongTailAnimal {
    protected void chew(List<Object> input) {}
}
public class Anteater extends LongTailAnimal {
    protected void chew(List<Double> input) {} // DOES NOT COMPILE
}

Both of these examples fail to compile because of type erasure. In the compiled form, the generic type is dropped, and it appears as an invalid overloaded method.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Generic Method Parameters

A

Can override a method with generic parameters, but you must match the signature including the generic type exactly.

public class LongTailAnimal {
    protected void chew(List<String> input) {}
}
public class Anteater extends LongTailAnimal {
    protected void chew(List<String> input) {}
}
public class LongTailAnimal {
    protected void chew(List<Object> input) {}
}
public class Anteater extends LongTailAnimal {
    protected void chew(ArrayList<Double> input) {} //OVERLOAD
}

Yes, these classes do compile. However, they are considered overloaded methods, not overridden methods, because the signature is not the same. Type erasure does not change the fact that one of the method arguments is a List and the other is an ArrayList.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

GENERICS AND WILDCARDS

A

Java includes support for generic wildcards using the question mark (?) character. It even supports bounded wildcards.

void sing1(List<?> v) {} // unbounded wildcard
void sing2(List<? super String> v) {} // lower bounded wildcard
void sing3(List<? extends String> v) {} // upper bounded wildcard
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Generic Return Types

A
  • When you’re working with overridden methods that return generics, the return values must be covariant.
  • In terms of generics, this means that the return type of the class or interface declared in the overriding method must be a subtype of the class defined in the parent class.
  • The generic parameter type must match its parent’s type exactly.
public class Mammal {
    public List<CharSequence> play() { ... }
    public CharSequence sleep() { ... }
}
public class Monkey extends Mammal {
    public ArrayList<CharSequence> play() { ... }
}
public class Goat extends Mammal {
    public List<String> play() { ... } // DOES NOT COMPILE
    public String sleep() { ... }
}
  • The play() method in the Goat class does not compile, though.
  • For the return types to be covariant, the generic type parameter must match.
  • Even though String is a subtype of CharSequence, it does not exactly match the generic type defined in the Mammal class.
  • Therefore, this is considered an invalid override.
  • Notice that the sleep() method in the Goat class does compile since String is a subtype of CharSequence.
  • This example shows that covariance applies to the return type, just not the generic parameter type.

For the exam, it might be helpful for you to apply type erasure to questions involving generics to ensure that they compile properly. Once you’ve determined which methods are overridden and which are being overloaded, work backward, making sure the generic types match for overridden methods. And remember, generic methods cannot be overloaded by changing the generic parameter type only.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Redeclaring private Methods

A
  • In Java, you can’t override private methods since they are not inherited.
  • 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 modified 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 is invoked.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Hiding Static Methods

A
  • A hidden method occurs when a child class defines a static method with the same name and signature as an inherited static method defined in a parent class.
  • Method hiding is similar but not exactly the same as method overriding.
  • The previous four rules for overriding a method must be followed when a method is hidden. In addition, a new rule is added for hiding a method:5. The method defined in the child class must be marked as static if it is marked as static in a parent class.
  • Put simply, it is method hiding if the two methods are marked static,
  • and method overriding if they are not marked static.
  • If one is marked static and the other is not, the class will not compile.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Creating final Methods

A
  • final methods cannot be replaced.
  • By marking a method final, you forbid a child class from replacing 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 child class if it is marked final in the parent class.
public class Bird {
    public final boolean hasFeathers() {
        return true;
    }
    public final static void flyAway() {}
}
public class Penguin extends Bird {
    public final boolean hasFeathers() { // DOES NOT COMPILE
        return false;
    }
    public final static void flyAway() {} // DOES NOT COMPILE
}

The static method flyAway() is also marked final, so it cannot be hidden in the subclass. In this example, whether or not the child method used the final keyword is irrelevant—the code will not compile either way.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

HIDING VARIABLES

A
  • Java doesn’t allow variables to be overridden.
  • Variables can be hidden, though.
  • A hidden variable occurs when a child class defines a variable with the same name as an inherited variable defined in the parent class.
  • This creates two distinct copies of the variable within an instance of the child class:
    • one instance defined in the parent class
    • and one defined in the child class.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

OBJECT VS. REFERENCE

A
  • In Java, all objects are accessed by reference, so as a developer you never have direct access to the object itself.
  • Conceptually, though, you should consider the object as the entity that exists in memory, allocated by the Java runtime environment.
  • Regardless of the type of the reference you have for the object in memory, the object itself doesn’t change.
  • For example, since all objects inherit java.lang.Object, they can all be reassigned to java.lang.Object, as shown in the following example:
Lemur lemur = new Lemur();
Object lemurAsObject = lemur;

We can summarize this principle with the following two rules:
1. The type of the object determines which properties exist within the object in memory.
2. The type of the reference to the object determines which methods and variables are accessible to the Java program.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

CASTING OBJECTS

A

We summarize these concepts into a set of rules for you to memorize for the exam:
1. Casting a reference from a subtype to a supertype doesn’t require an explicit cast.
2. Casting a reference from a supertype to a subtype requires an explicit cast.
3. The compiler disallows casts to an unrelated class.
4. At runtime, an invalid cast of a reference to an unrelated type results in a ClassCastException being thrown.

public class Rodent {}
public class Capybara extends Rodent {
    public static void main(String[] args) {
        Rodent rodent = new Rodent();
        Capybara capybara = (Capybara)rodent; // ClassCastException
    }
}
17
Q

THE INSTANCEOF OPERATOR

A

instanceof operator, which can be used to check whether an object belongs to a particular class or interface and to prevent ClassCastExceptions at runtime.

the following code snippet doesn’t throw an exception at runtime and performs the cast only if the instanceof operator returns true:

if(rodent instanceof Capybara) {
    Capybara capybara = (Capybara)rodent;
}

Just as the compiler does not allow casting an object to unrelated types, it also does not allow instanceof to be used with unrelated types. We can demonstrate this with our unrelated Bird and Fish classes:

public static void main(String[] args) {
    Fish fish = new Fish();
    if (fish instanceof Bird) { // DOES NOT COMPILE
        Bird bird = (Bird) fish; // DOES NOT COMPILE
    }
}

In this snippet, neither the instanceof operator nor the explicit cast operation compile.

18
Q

POLYMORPHISM AND METHOD OVERRIDING

A

In Java, polymorphism states that when you override a method, you replace all calls to it, even those defined in the parent class.

Output : 8

class Penguin {
    public int getHeight() { return 3; }
    public void printInfo() {
        System.out.print(this.getHeight());
    }
}
public class EmperorPenguin extends Penguin {
    public int getHeight() { return 8; }
    public static void main(String []fish) {
        new EmperorPenguin().printInfo();
    }
}
  • The facet of polymorphism that replaces methods via overriding is one of the most important properties in all of Java.
  • It allows you to create complex inheritance models, with subclasses that have their own custom implementation of overridden methods.
  • It also means the parent class does not need to be updated to use the custom or overridden method.
  • If the method is properly overridden, then the overridden version will be used in all places that it is called.
  • Remember, you can choose to limit polymorphic behavior by marking methods final, which prevents them from being overridden by a subclass.
19
Q

CALLING THE PARENT VERSION OF AN OVERRIDDEN METHOD

A

there is one exception to overriding a method where the parent method can still be called, and that is when the super reference is used.

class Penguin {
...
    public void printInfo() {
        System.out.print(super.getHeight()); // DOES NOT COMPILE
    }
}

this does not compile, as super refers to the superclass of Penguin, in this case Object. The solution is to override printInfo() in the EmperorPenguin class and use super there.

public class EmperorPenguin extends Penguin {
...
    public void printInfo() {
        System.out.print(super.getHeight());
    }
...
}

This new version of EmperorPenguin uses the getHeight() method declared in the parent class and prints 3.

20
Q

OVERRIDING VS. HIDING MEMBERS

A
  • While method overriding replaces the method everywhere it is called, static method and variable hiding does not.
  • Strictly speaking, hiding members is not a form of polymorphism since the methods and variables maintain their individual properties.
  • Unlike method overriding, hiding members is very sensitive to the reference type and location where the member is being used.
class Penguin {
    public static int getHeight() { return 3; }
    public void printInfo() {
        System.out.println(this.getHeight());
    }
}
public class CrestedPenguin extends Penguin {
    public static int getHeight() { return 8; }
    public static void main(String... fish) {
        new CrestedPenguin().printInfo();
    }
}
21
Q
class Marsupial {
    protected int age = 2;
    public static boolean isBiped() {
        return false;
    }
}
public class Kangaroo extends Marsupial {
    protected int age = 6;
    public static boolean isBiped() {
        return true;
    }
    public static void main(String[] args) {
        Kangaroo joey = new Kangaroo();
        Marsupial moey = joey;
        System.out.println(joey.isBiped());
        System.out.println(moey.isBiped());
        System.out.println(joey.age);
        System.out.println(moey.age);
    }
}
A

The program prints the following:

true
false
6
2
  • in this example, only one object, of type Kangaroo, is created and stored in memory.
  • Since static methods can only be hidden, not overridden,
  • Java uses the reference type to determine which version of isBiped() should be called,
  • resulting in
    • joey.isBiped() printing true
    • and moey.isBiped() printing false.
  • Likewise, the age variable is hidden, not overridden,
  • so the reference type is used to determine which value to output.
    • This results in joey.age returning 6
    • and moey.age returning 2.