1/115
Looks like no tags are added yet.
Name | Mastery | Learn | Test | Matching | Spaced | Call with Kai | Chat |
|---|
No analytics yet
Send a link to your students to track their progress
What is method overloading?
Method overloading is when you have multiple methods with the same name but different method signatures.
What does a method signature include?
A method signature includes:
the number of parameters
the types of parameters
and the order of parameters
Why would we ever use method overloading? Give a simple example of why it may be useful.
We use method overloading when we want the same conceptual action to work on different inputs.
Example:
public class MathUtils {
public int add(int a, int b) {
return a+b;
}
public int add(int a, int b, int c) {
return a+b+c;
}
}
public int add(double a, double b) {
return a+b;
}
}Write two versions of a method called printInfo. One method should take a String, and the other should take an int.
class Printer {
private static void printInfo(String message) {
return message;
}
private static void printInfo(int number) {
return number;
}
}If you change the return type, are you still overloading a method?
public int compute() {
return 1;
}
public double compute() {
return 1.0;
}No, because changing the return type doesn’t help java distinguish between the two methods.
You would still call the methods in the same way, so java doesn’t know which one you’re referring to.
public int compute() {
return 1;
}
public double compute() {
return 1.0;
}
// both methods are called in the same way: compute()
// since their parameter lists are the same, java cannot tell which one you want to use in your programDescribe what each line of code is doing:
public class Rectangle {
private int height;
private int width;
public Rectangle() {
this.width = 1;
this.height = 1;
}
public Rectangle(int size) {
this.width = size;
this.height = size;
}
public Rectangle(int width, int height) {
this.width = width;
this.height = height;
}
}Describe what each line of code is doing:
public class Rectangle {
private int height;
private int width;
public Rectangle() {
this.width = 1;
this.height = 1;
}
public Rectangle(int size) {
this.width = size;
this.height = size;
}
public Rectangle(int width, int height) {
this.width = width;
this.height = height;
}
}Each constructor is assigning the instance variables to either the values in the parameters, or to a specific value (like 1).
What is constructor chaining?
Constructor chaining is when one constructor calls another constructor, either in the same class or a different class.
We use the super() keyword (to call a constructor of the parent class) or the this keyword (to call a constructor within the same class).
Describe what each line of code is doing here:
public class Box {
private int width;
private int height;
public Box() {
this(1,1);
}
public Box(int size) {
this(size, size);
}
public Box(int width, int height){
this.width = width;
this.height = height;
}
}public class Box {
private int width;
private int height;
public Box() {
this(1,1);
}
public Box(int size) {
this(size, size);
}
public Box(int width, int height){
this.width = width;
this.height = height;
}
}Box():
this(1,1) calls the last constructor in the same class with two parameters (Box(int width, int height)).
Box(int size):
this(size, size) calls the last constructor in the same class with two parameters (Box(int width, int height))
Box(int width, int height):
this is the two-parameter constructor that the other two constructors keep referring back to.
Write a class called Point with two instance variables: x and y. It should have a constructor with no parameters that sets the two instance variables to 0, and another constructor that takes two int values and sets them to x and y using the this keyword.
Use constructor chaining.
class Point {
// these should not be final because then the same value of x and y would be shared across all objects
private final int x;
private final int y;
public Point() {
this(0, 0);
}
public Point(final int x, final int y) {
this.x = x;
this.y = y;
}
}Taking your code from the previous question:
Write another constructor with a single formal parameter: int x. This constructor should use constructor chaining to set the instance variables to whatever value is entered in by the user for x.
class Point {
int x;
int y;
public Point() {
this(0);
}
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public Point(int x) {
this(x,x);
}
}Use constructor chaining so that the output is:
Animal
Dog
class Animal {
Animal() { System.out.println("Animal"); }
}
class Dog extends Animal {
Dog() {
// what goes here?
System.out.println("Dog");
}
}class Animal {
Animal() { System.out.println("Animal"); }
}
class Dog extends Animal {
Dog() {
super();
System.out.println("Dog");
}
}Note: Whenever one class extends another, its constructor will always call super() implicitly; Regardless of whether you write it out or not.
In this case, since the constructor of the parent class, Animal(), contains a print statement, the Dog constructor always ends up printing “Animal” regardless of whether or not you included super(). This is because super() is being called implicitly.
Dog() {
super(); // explicit
System.out.println("Dog");
}
Dog() {
System.out.println("Dog"); // implicit super() happens here anyways
}
Will this compile? Explain why or why not?
class A {
MyConstructor() {
this(5);
}
MyConstructor(int x) {
this();
}
}It will not compile.
This is because the first constructor is using the this keyword to refer to the second constructor,
but then the second constructor is using the this keyword to refer BACK to the first constructor.
This just creates an infinite loop where they keep referring back to each other without ever doing anything with the value of x.
What always happens in this code?
class Animal {
Animal() { System.out.println("Animal"); }
}
class Dog extends Animal {
Dog() {
System.out.println("Dog");
}
}super() is actually always called in the Dog class. Even if we don’t explicitly write it, it is still implicitly getting called behind the scenes.
Therefore this code (with no super()):
class Animal {
Animal() { System.out.println("Animal"); }
}
class Dog extends Animal {
// super() is being called here
Dog() {
System.out.println("Dog");
}
}Will produce the same result as this code (with super() explicitly stated):
class Animal {
Animal() { System.out.println("Animal"); }
}
class Dog extends Animal {
super();
Dog() {
System.out.println("Dog");
}
}Both will print out:
“Animal”
“Dog”
What is a rule to remember about constructor chaining?
Whenever you use constructor chaining, this() or super() must ALWAYS be the FIRST statement in the constructor.
What does the this keyword actually mean?
A reference to the current object.
Typically we use this to refer to the fields of a current object:
public class Person {
private String name;
public Person(String name) {
this.name = name;
// this.name refers to the instance variable name
}
}What do we use to call an instance method (a non-static method)?
this.printDetails()
What do we use if we wanted to pass in the current object into the following method:
listener.register(…)
listener.register(this)
What does this(…) as a constructor call mean?
It means one constructor is trying to run another constructor located within the same class.
What do we mean by “Strings are immutable”?
It means that the characters of a string cannot actually be changed after it’s been created. Even if you “modify” a string, java just creates a new string object that it operates on, and the original stays the same.
In the following code, what happens to s when we reassign it?
String s = "hello";
s = s + "world";String s = "hello";
s = s + "world";(no object pointing to) “hello”
s now points to “hello world”
String s was created, and it initially held “hello”.
But then we reassigned s to “hello world”, which means that a new string “hello world” was created, and now s points to the new string.
The old “hello” string still exists in memory, but is now considered garbage (because it no longer has an object pointing to it, so it is inaccessible).
What happens in the following code:
String s = "abc";
String t = s.toUpperCase();s → “abc”
t → “ABC”
First, string s is created, and it holds: “abc”.
Then, we create a new string called t, which points to the value in memory: “ABC”.
We still end up with two different objects pointing to two different memory locations:
What would be the output of the following code? How would you need to change it in order to do what it is intended to do?
public static void change(String x) {
x = x + "!";
}
String s = "hi";
change(s);
System.out.println(s);“hi”
This is because s remains unchanged. In the method, we only changed the value of the local variable x, which is separate from s.
If you actually wanted to make this code modify the value of the variable s, you would need to avoid reassignment altogether, and instead, set the variable s to the function call:
public static void change(String x) {
return x + "!";
}
String s = "hi";
s = change(s);
System.out.println(s);Or you would need to use a mutable wrapper like StringBuilder, which actually allows you to mutate the value of s itself:
public static void change(StringBuilder x) {
x.append("!");
}
String builder s = new StringBuilder("hi");
change("hi");
System.out.println(s);What is the string pool?
The string pool is a special memory area where string literals are all stored.
What happens after the following code runs:
String a = "cat";
String b = "cat";Both a and b point to the same location in memory.
a → “cat”
b → “cat”
What happens when the following code runs:
String a = "cats";
String b = "cat";a and b point to two different locations in memory.
a → “cats”
b → “cat”
Why do we have String Builder?
Because it’s a more efficient way of doing repeated string concatenation. Normally, when you concatenate strings, it is very expensive in terms of memory allocation. For example, in an example like this:
String s = "";
for(int i=0; i<5; i++) {
s = s + i;
}This creates like 5 different strings, resulting in a lot of garbage (that is no longer being pointed to by any object):
“0”
“01”
“012”
“0123”
“01234”
How is StringBuilder different from regular concatenation?
StringBuilder is different because it is mutable; So it allows you to change variables of type “StringBuilder” after they’ve been created, effectively letting you modify strings (except they’re not actually strings, they’re of type StringBuilder).
How would you rewrite the following code so that it uses StringBuilder instead?
String s = "";
for(int i=0; i<5; i++) {
s = s + i;
}StringBuilder SofiasBuilder;
SofiasBuilder = new StringBuilder();
for(int i = 0; i < 5; i++) {
SofiasBuilder.append(i);
}
String s = SofiasBuilder.toString();What package is StringBuilder in?
StringBuilder is in the java.lang package, which means it is automatically imported into java (no import statements required).
What are the two different methods for extracting the numeric value out of the following string: “123”
int a;
int b;
a = Integer.parseInt("123");
b = Integer.valueOf("123");What are the two different methods for extracting the numeric value out of the following string: “6.5”
double a;
double b;
a = Double.parseDouble("6.5");
b = Double.valueOf("6.5");What would be the output of the following code:
int c = Integer.valueOf("hello");NumberFormatException
This is because valueOf is for extracting numeric values out of a string, and if there is no numeric value present, it is not possible to do so.
For the following String, use methods to:
Determine whether or not the string has the word “program” in it
Determine whether or not the string finishes with “mming”
Determine whether or not the string begins with “Java”
Determine the index value of the letters “na”
String s;
s = "Java Programming";For this next string, use methods to:
Change all values of cat to dog
Remove all the whitespace in the string, storing the value in a new variable
String c;
c = "cat cat cat";String s;
s = "Java Programming";
s.charAt(0); // J
boolean b = s.contains("program"); //true
boolean c = s.endsWith("mming"); //true
boolean d = s.startsWith("Java"); //true
int index = s.indexOf("na");
String c;
c = "cat cat cat";
c.replace("cat", "dog"); // replaces all instances of cat with dog: dog dog dog
String stripped;
stripped = c.strip(); // removes all trailing whitespace, including tabs, newlines, and unicode characters representing whitespace.Most instance variables ….
should be private and final.
Include javadoc comments for…
the class
non-private constants
non-private constructors
non-private methods
Why do we use constructor chaining with either the this() keyword or with super()?
Because it helps us avoid code duplication when initializing variables in constructors.
To validate the data in a constructor ….
use private static validation methods.
Why do validation methods need to be private static?
Because private static methods cannot be overridden.
In the following example, how would you use validation methods to validate the name and age?
The name must not be null or blank, and the age must be greater than 0 but less than 150.
public class Person {
public Person(final String name, final int age) {
this.name = name;
this.age = age;
}
}public class Person {
// pretend the instance variables are up here
public Person(final String name, final int age) {
this.name = name;
this.age = age;
validateName(name);
validateAge(age);
}
private static void validateName(final String name) {
if(name == null || name.isBlank()) {
throw new IllegalArgumentException("name cannot be empty");
}
private static void validateAge(int age) {
if(0 > age || age > 150) {
throw new IllegalArgumentException("Age must be between 0 and 150");
}
}What is the String.format() method used for? What about the System.out.printf() method?
It is used for formatting strings using format specifiers like %s %d
What is the format specifier for whole number values?
%d
(works with short, int, byte,and long)
What is the format specifier for floating point numbers?
%f
(can hold up to 6 decimal places)
What is the format specifier for a float with 2 decimal places?
%.2f
What is the format specifier for a string? What about for a character? A boolean?
%s
%c
%b
What is the format specifier for the newline character?
%n
What is the format specifier for a literal percent sign?
%%
How do you specify a whole number value with a width of 5? What does this even mean?
%5d
This specifies that the number should have a “width” of 5, aligned to the right.
// BEFORE: "42"
// AFTER: " 42" // 42 gains an additional 3 whitespace characters to the left in order to meet the "width of 5"How do you specify a whole number value with a width of 5, but this time, trailing to the left?
%-5d
// BEFORE: "42"
// AFTER: "42 "...there are 3 spaces of trailing whitespace here, but now the number is trailing to the left.What if you wanted to pad a whole number with zeroes (in the front), and make it have a width of 5?
%05d
// BEFORE: "5"
// AFTER: "00005"What if you wanted a larger whole number to have groupings?
%,d
// BEFORE: 123456789
// AFTER: 123,456,789In the following examples below, format them using format specifiers, making sure that each starts on a different line:
// format as a string
System.out.printf("Name:", "Sofia");
// format as a decimal (whole number value)
System.out.printf("Score:", 95);
// format as a floating point value with only 3 places after the decimal point
System.out.printf("Pi approx:", 3.14159);
// format as a decimal value with a width of 5, padded with 0s in front
System.out.printf("Padded:", 42);
// format as a decimal value grouped by commas
System.out.printf("Money:", 1000000);System.out.printf("Name: %s%n", "Sofia");
System.out.printf("Score: %d%n", 95);
System.out.printf("Pi approx: %.3f%n", 3.14159);
System.out.printf("Padded: %05d%n", 42);
System.out.printf("Money: %,d%n", 1000000);
// note: the %n operator is used to create a newline for each// OUTPUT:
Sofia
95
3.141
00042
1,000,000Note: It is necessary to include %n at the end of every line because unlike println, printf does not move onto the next line when it has finished printing a statement.
What is .compareTo() used for?
.compareTo() is a String method used for comparing strings based on alphabetical order (lexicographically).
It returns 0 if the strings are equal
negative if the caller comes before the argument
or positive if the caller comes after the argument (or is greater than)
What would be the result of the following code:
"apple".compareTo("banana");Apple comes before banana, therefore, the caller comes before the argument, and the result is:
NEGATIVE
What would be the result of the following code:
"dog".compareTo("cat");Dog comes after cat, so the caller comes after the argument, therefore the result is POSITIVE.
What would be the result of the following code:
"apple".compareTo("apricot");The third p in apple comes before the r in apricot, therefore the caller comes before the argument, so the result is NEGATIVE.
What would be the result of the following code?
"apple".compareTo("Apple");In unicode, uppercase letters come before lowercase letters. So in this case, the caller comes after the argument, and therefore the result is POSITIVE.
How can we get around this weird quirk of uppercase letters coming before lowercase letters in unicode?
"apple".compareTo("Apple");We can use .compareToIgnoreCase()
"apple".compareToIgnoreCase("Apple"); // this will give you a result of 0What does == compare when used on strings?
== compares the memory locations of two strings.
What does .equals() and .equalsIgnoreCase() compare when used on strings?
.equals() and .equalsIgnoreCase() both compare the content of strings, with one being case-insensitive.
Given that h has a unicode value of 104, and b has a unicode value of 98, what would be the output of the following code:
System.out.println(“hi”.compareTo(“bye”));
Well since h comes after b, we can say that the caller comes after the argument. Therefore the result will be POSITIVE.
so 104-98 = 6
Answer: 6
If we had done:
System.out.println(“bye”.compareTo(“hi”));
The result would’ve been -6.
What are the characteristics of object oriented programming langauges?
Classes and objects, encapsulation, inheritance, polymorphism, abstraction, and composition.
When would be a good time to use inheritance?
Whenever you have one class that is a more specialized version of another.
Examples:
Dog is a more specialized version of Animal
SavingsAccount is a specialized version of BankAccount
What does a child actually inherit from a parent (through inheritance)?
A child automatically inherits the instance variables and public methods of a parent class. It does not inherit private methods.
In the following code, what would we need to write in order to make child inherit from parent?
class Parent {
}
class Child {
}class Parent {
}
class Child extends Parent {
}Write a class called Animal with a method called eat.
Then write another class called Dog that inherits from Animal, creating its own method called bark().
public class Animal {
public void eat() {
System.out.println("munch");
}
}
public class Dog extends Animal {
public void bark() {
System.out.println("bark");
}
}In main, define a new Dog object.
Use the methods in Animal and Dog on the Dog object. What output would it produce?
public class Animal {
public void eat() {
System.out.println("munch");
}
}
public class Dog extends Animal {
public void bark() {
System.out.println("bark");
}
}public class Main {
public static void main(final String[] args) {
Dog sofiasdog;
sofiasdog = new Dog();
sofiasdog.eat();
sofiasdog.bark();
}
}// OUTPUT:
"munch"
"bark"In Dog, override the speak() and move() method inherited from Animal so that it is more appropriate for a dog.
public class Animal {
public void speak() {
System.out.println("speaking");
}
public void move() {
System.out.println("moving");
}
}
public class Dog extends Animal {
public void eat() {
System.out.println("munch");
}
}public class Animal {
// pretend all of the methods in Animal are still here
}
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("munch");
}
@Override
public void speak() {
System.out.println("bark");
}
@Override
public void move() {
System.out.println("running");
}
}Why will this produce a compiler error?
class Animal {
private double weightKg;
Animal(final double weightKg) {
this.weightKg = weightKg;
}
}
// in a separate class:
class Dog extends Animal {
}Because we didn’t explicitly define a constructor for the child class Dog, Java automatically creates a constructor for us.
But when it does this, it automatically calls super() inside of our default constructor.
So in our example code:
class Animal {
private double weightKg;
Animal(final double weightKg) {
this.weightKg = weightKg;
}
}
// this code is being run
class Dog extends Animal {
// Dog() {
// super();
// }
}
// All of this code is implicitly being run, even though we didn't write it ourselves. Java automatically made us a constructor and called super() in it.The problem is that when super() calls the constructor of the parent class, it is assuming that the parent class has a constructor with no parameters/arguments in it, but this is not the case.
Our Animal constructor actually takes in a parameter of double weightKg. So when java inserts super() into Dog(), it tries to call a constructor that doesn’t exist, giving us a compiler error.
How can we fix this compiler error?
class Animal {
private double weightKg;
Animal(final double weightKg) {
this.weightKg = weightKg;
}
}
// in a separate class:
class Dog extends Animal {
}Option one: You can create your own constructor for Dog and explicitly call super() yourself, passing in a value for weightKg
// OPTION ONE
class Dog extends Animal {
Dog() {
super(43.5);
}
}OR, Option two: You can create your own constructor for Dog that takes in a parameter, and explicitly call super() yourself, passing in the parameter as the value for weightKg
// OPTION TWO
class Dog extends Animal {
Dog(final double weightKg) {
super(weightKg);
}
}What happens if you do define your own constructor for a child class, but you don’t call super(..) in it?
If you define your own constructor and don’t call super(..) explicitly, Java still tries to insert super().
But this only works properly if the superclass/parent class has a no-argument constructor.
What does overriding actually mean in Java?
Overriding is when a child class provides a more specific implementation for a method that is already provided in the parent class.
The overridden method must always have the same name and parameter list, but its visibility can only be the same or greater than the one of the parent.
What are the visibility rules for overriding in java?
When you override a method, your new method in the child class must either have the same or greater visibility than the parent’s original method.
public → public
protected → protected or public
default → default, protected, or public
BUT THIS IS NOT ALLOWED:
public → protected
protected → default or private
default → private
For example:
class Animal {
public void speak() {
System.out.println("speaking");
}
protected void move() {
System.out.println("moving");
}
}
// THIS IS ALLOWED
class Dog extends Animal {
public void move() {
System.out.println("running");
}
}
// THIS IS NOT ALLOWED, BECAUSE WE REDUCED THE VISIBILITY OF THE ORIGINAL METHOD WHICH WAS protected
class Dog extends Animal {
private void move() {
System.out.println("running");
}
}Can you override all methods?
No, you cannot override methods that are private, or methods that are private static.
This is because methods that are private or private/static cannot even be inherited because they are not visible to subclasses.
Remember: the private visibility modifier makes it so that a method is not visible to any other classes outside of the current class.
What does the @Override annotation actually do?
The @Override annotation actually does nothing besides check to see if you’ve overridden a method correctly. So it is only used to catch mistakes like typos when overriding methods.
If you’ve overridden a method correctly, it won’t actually do anything (it will only warn you if you’ve made a mistake).
But it is good practice to include the @Override annotation just before you override any method:
@Override
public void speak() {
System.out.println("woof");
}Can static methods be inherited? Can static methods be overridden?
Static methods can be inherited, but they cannot be overridden by a child class.
For example, this will work just fine:
class A {
static void greet() {
System.out.println("hello from A");
}
}
class B extends A {
}
// then somewhere in the main method, if you do this: B.greet(), it will run just fine, printing: Hello from AWhat will be the output of the following code?
class A {
static void greet() {
System.out.println("hello from A");
}
}
class B extends A {
@Override
static void greet() {
System.out.println("hello from B");
}
}
// then somewhere in the main method you run:
A.greet();
B.greet();It will run exactly as you would expect it to run, printing out:
“hello from A”
“hello from B”
What’s actually happening is that the static method greet is being hidden, not overridden.
Static methods belong to the class, not the object.
So the method that runs is chosen at compile time, based on the class name you write, not on inheritance or polymorphism.
In the code, B.greet() does not override A.greet().
It simply defines a new static method with the same name, which hides the one in A.
The @Override annotation is actually illegal here — the compiler would complain, because static methods cannot be overridden.
What happens when you do this:
class A {
static void greet() {
System.out.println("hello from A");
}
}
class B extends A {
static void greet() {
System.out.println("hello from B");
}
}
A sofiasb = new B();
sofiasb.greet();Static methods belong to the class, not the instance.
When you write sofiasb.greet(), Java does not look at the actual object (new B()). Instead, it looks only at the static type, which is A. Because static methods do not participate in polymorphism, the method in A is chosen at compile time.
The version in B does not override the one in A; it merely hides it. Hidden static methods are selected based on the static type, not the dynamic type.
Define polymorphism:
Polymorphism is the ability of a single method call to execute different method implementations depending on the runtime type of the object (otherwise known as the static type).
AKA:
Polymorphism is the ability for a single method to behave differently depending on the dynamic type of an object, which is determined at runtime.
Define Substitution:
Substitution, otherwise known as the Liskov Substitution Principle, means that an object of a subclass can be used anywhere a variable, parameter, or return type expects an object of the superclass, without breaking the program’s correctness.
Substitution means that anywhere a variable, parameter, or return type expects a parent class, you can provide an instance of a child class, and the code will still compile and behave correctly according to the parent’s contract.
Dog is a type of Animal, use this info to give an example of substitution. Use the method speak() on this new object.
Animal a = new Dog();
a.speak();What is Static Type? What is it used for?
Static type is the type of the reference variable (typically the type of the parent class). The static type is the type the compiler uses to check method calls, access fields, and assign values. It never changes during execution, and is determined at compile-time.
What is Dynamic Type?
The dynamic type of a variable is the actual class/type of the object created with new, not the type of the reference variable. Dynamic type is determined at runtime, and it can change throughout program execution.
What is the static type in the following example:
Animal a = new Dog();Animal is the static type. We know this because static type always refers to the type of the reference variable, or in other words, the type of the parent variable.
What is the dynamic type in the following example:
Animal a = new Dog();The dynamic type is Dog, because it represents the type of the actual object created with new.
What does static type determine?
Static type determines what methods the compiler allows you to call, and it also determines what the compiler thinks the variable is.
For each of the variables below, state which is its dynamic type and static type:
class Zoo {
public static void main(final String[] args) {
final Animal a1;
final Animal a2;
final Animal a3;
final Animal a4;
a1 = new Animal(200.0);
a2 = new Dog(30.0, "Rex");
a3 = new Pitbull(50.0, "Rocky", true);
a4 = new Dolphin(300.0, false);
}
}a1:
Static type - Animal
Dynamic type - Animal
a2:
Static type - Animal
Dynamic type: Dog
a3:
Static type - Animal
Dynamic type: Pitbull
a4:
Static type - Animal
Dynamic type - Dolphin
What does dynamic type determine?
Dynamic type determines which overridden method actually runs and what the object really is at runtime.
What would be the output of Main?
class Animal {
void speak() {
System.out.println("Animal speaks");
}
}
class Dog extends Animal {
@Override
void speak() {
System.out.println("Dog barks");
}
void fetch() {
System.out.println("Dog fetches");
}
}
// OUTPUT IS...?
public class Main {
public static void main(final String[] args) {
Animal a = new Dog();
a.speak();
}
}
“Dog barks”
because Dog is the dynamic type that was decided at runtime, and we overrode the speak() method that we had in animal, so it prints out “Dog barks”.
What would be the output of the following code:
class Animal {
void speak() {
System.out.println("Animal speaks");
}
}
class Dog extends Animal {
@Override
void speak() {
System.out.println("Dog barks");
}
void fetch() {
System.out.println("Dog fetches");
}
}
// OUTPUT IS...?
public class Main {
public static void main(String[] args) {
Animal a = new Dog();
a.fetch();
}
}A compiler error! This is because fetch is a method that is only specified in Dog.
Remember that the static type (Animal) controls what methods the compiler allows.
While The dynamic type (Dog) controls which overridden method actually runs.
In this case, since fetch does not exist in Animal, and it only exists in Dog, it will throw a compiler error because it can only allow methods that are defined in the static type.
The reason a.speak() worked last time was because it was defined in both in Animal (the static type) and in Dog (the Dynamic type). The overridden method in Dog just let the compiler know which version of the method to run.
What would be the output of the following code?
class Animal { }
class Dog extends Animal { }
public class Main {
public static void main(String[] args) {
Animal a = new Dog();
System.out.println(a.getClass());
System.out.println(a.getClass().getName());
System.out.println(a.getClass().getSimpleName());
}
}
class Animal { }
class Dog extends Animal { }
public class Main {
public static void main(String[] args) {
Animal a = new Dog();
System.out.println(a.getClass()); // class Dog
System.out.println(a.getClass().getName()); // Dog
System.out.println(a.getClass().getSimpleName()); // Dog
}
}
What would be the output of the following code, if it was in a package:
package ca.bcit.comp2522.Animal;
class Animal { }
class Dog extends Animal { }
public class Main {
public static void main(String[] args) {
Animal a = new Dog();
System.out.println(a.getClass());
System.out.println(a.getClass().getName());
System.out.println(a.getClass().getSimpleName());
}
}
package ca.bcit.comp2522.Animal;
class Animal { }
class Dog extends Animal { }
public class Main {
public static void main(String[] args) {
Animal a = new Dog();
System.out.println(a.getClass());
// class bcit.comp2522.Animal.Dog
System.out.println(a.getClass().getName());
// bcit.comp2522.Animal.Dog
System.out.println(a.getClass().getSimpleName()); // Dog
}
}Get the class name using the built in methods in three different ways:
Animal s = new Sofia(); Animal s = new Sofia();
System.out.println(s.getClassName());
// class Sofia
System.out.println(s.getClassName().getName()); // Sofia
System.out.println(s.getClassName().getSimpleName()); // sofiaWhat is instanceof used for?
instanceof is used to verify that the dynamic type of an object belongs to a specific class
Use instanceof to check that the following animal is a dolphin:
final Animal a3;
a3 = new Dolphin(50.0, "Rocky", true);final Animal a3;
a3 = new Dolphin(50.0, "Rocky", true);
if(a3 instanceof Dolphin) {
return true;
}Note: instanceof is always all lowercase
What is object casting? What are the two different types of object casting?
Object casting is a way of changing the static type of an object, not the dynamic type. It tells the compiler to treat the object as a different type.
The two different types of object casting are:
Upcasting: when a subclass (child) object is treated as a superclass type
Downcasting: when a superclass (parent) object is treated as a subclass type
Is this an example of upcasting or downcasting?
Dog d = new Dog();
Animal a = d;This is an example of upcasting. We’re going from the child class Dog, to the super/parent class, Animal.
Since we are upcasting, this process technically happens automatically, without an explicit cast actually required.
Is this an example of upcasting or downcasting?
Animal a = new Dog();
Dog d = (Dog) a;This is an example of downcasting. We know this because we’re going from the superclass (parent) type of Animal to the subclass type, Dog. We also know that it’s downcasting because downcasting is always explicit.
Given that:
Animal has a method called makeSound that prints out “Make sound” and Dog has a method called makeSound that prints out “Woof woof”; What would be the output of the following?
Also, determine the static type of each variable, and whether upcasting or downcasting is happening:
Dog d = new Dog();
Animal a = d;
a.makeSound();
Dog d = new Dog(); // Dynamic and static type are both dog (no upcasting/downcast)
Animal a = d; // Implicit upcasting to the static type Animal
a.makeSound(); // "Woof woof"Answer: “Woof woof”, because at runtime, the dynamic type is determined to be dog
Given that:
Animal does not have a method called fetch, but Dog does have a method called fetch that prints out: “Fetched ball”, what is the output of this code?
Animal a = new Dog();
Dog d = (Dog) a;
d.fetch(); Animal a = new Dog(); // static type: Animal, dynamic type: Dog (upcasting)
Dog d = (Dog) a; // static type: Dog, dynamic type: Dog (downcast from Animal to Dog)
d.fetch(); Output: Fetched Ball
Will this compile? Why or why not?
Animal a = new Cat();
Dog d = (Dog) a; It will compile, but it will not run; Instead, it will give you a ClassCastException.
This is because java only allows downcasting when the dynamic type is an instance of the current/target class. In this case, Dog is not an instance of Cat, so it doesn't work.
Animal a = new Cat(); // Static type: Animal, Dynamic type: Cat (upcasting)
Dog d = (Dog) a;
// The problem is that both Cat and Dog are siblings. They both share the same parent of Animal, but they're not actually related to each other.
// PAY ATTENTION: this ONLY applies to downcasting, not upcasting.