Download presentation
Presentation is loading. Please wait.
1
Chapter 13 - Inheritance and Polymorphism
The Object Class The equals Method The toString Method Polymorphism Dynamic Binding Compilation Details Polymorphism with Arrays Abstract Methods And Classes protected Access Modifier 1. In this chapter I demo these files: Payroll.java Employee.java Salaried.java Hourly.java
2
The Object Class The Object class is a superclass for all other classes. When declaring your own classes, you don't have to specify the Object class as a superclass - it's automatically a superclass. I'm only covering two of Object's methods. The equals and toString methods are the most important Object methods.…
3
The equals Method For classes that don't have their own equals method, if objects from those classes are compared with the equals method, they inherit and use the Object class's equals method. The Object class's equals method returns true if the two reference variables that are being compared point to the same object; i.e., if the two reference variables contain the same address.
4
The equals Method Assuming that the Car class does not have its own equals method, what does this code fragment print? Car car1 = new Car("Honda"); Car car2 = car1; if ((car1.equals(car2) && (car1 == car2)) { System.out.println("cars are equal - first time"); } car2 = new Car("Honda"); if ((car1.equals(car2) || (car1 == car2)) System.out.println("cars are equal - second time"); Aside: the == operator works the same as the Object class's equals method; == returns true if the two reference variables point to the same object. 1 1. As I read the == parenthetical element, I should point out the bottom bullet point. 2. output: cars are equal - first time 2
5
The equals Method Usually, the Object class's equals method is not good enough. You'll usually want to compare the contents of two objects rather than just whether two reference variables point to the same object. To do that, you'll need to have an equals method in the object's class definition that compares the contents of the two objects. 1 1. We'll write an equals method for the Car class on the next slide....
6
Defining Your Own equals Method
1 Write an equals method for a Car class. Use this skeleton: public class Car { private String make; private int year; private String color; <equals method goes here> } // end class Car public class CarDriver public static void main(String[] args) Car car1 = new Car(); Car car2 = new Car(); if (car1.equals(car2)) System.out.println("cars have identical features"); } ... 2 4 1. This might look familiar since we wrote a similar equals method in Chapter 7. But in Chapter 7, we didn't realize that our Car class's equals method needed to avoid using the Object class's equals method. 2. See where the equals method definition should go? 3. See the way that we call the equals method? 4. I write the following on the board with the students’ help. I initially skip the if otherCar == null test (but leave room for it) and come back to it by asking what happens if otherCar is null. public boolean equals(Car otherCar) { if (otherCar == null) return false; } else return make.equals(otherCar.make) && year == otherCar.year && color.equals(otherCar.color); } // end equals 5. You'll probably want to create an equals method for many of your homemade classes. Those equals methods will look pretty similar to this equals method. [6. It might appear that Car's equals method is an overriding method, but strictly speaking it's not since the parameter type is different than the parameter type in the Object class's equals method.] 3 5 6
7
The equals Method Note that equals methods are built into lots of Java's API classes. For example, the String class and the wrapper classes implement equals methods. As you'd expect, those equals methods test whether the contents of the two compared objects are the same (not whether the addresses of the two compared objects are the same). What does this code fragment print? String s1 = "hello", s2 = "he"; s2 += "llo"; if (s1 == s2) { System.out.println("\"==\" works"); } if (s1.equals(s2)) System.out.println("\"equals\" works"); 1 1. If you're curious, look up the equals method at Sun's API site and you'll see equals methods for lots of the classes. 2. Output: "equals" works [3. Note that if s2 was initialized to "hello", then s2 and s1 would contain the same address. That's because String values are pooled.] 4. Remember to use equals instead of == when comparing strings. Using == for string comparison is a very common mistake!! 5. Let's now discuss another important method provided by the Object class … 2 5
8
The toString Method The Object class's toString method returns a string that's a concatenation of the calling object's class name, sign, and a sequence of digits and letters (called a hashcode). Consider this code fragment: Object obj = new Object(); System.out.println(obj.toString()); Car car = new Car(); System.out.println(car.toString()); Here's the output: If a class is stored in a package, toString prefixes the class name with the class's package. 1 2 5 1. I'll explain the hashcode shortly, but first an example…. 2. Note how we instantiate an Object object and then print its toString value. Note the output - a) The class name is Object and the Object class is stored in the java.lang package (read the bottom bullet item). Java organizes its API library into groups of classes and those groups are called packages. b) After the class comes sign. c) After sign comes the obj's hashcode…. 3. You can think of an object's hashcode value as its location in memory, but it's really a bit more complicated than that. The JVM translates an object's hashcode value to one or more other values and the last value in the translation chain specifies the object's actual location in memory. 4. In Java, hashcode values, like 601BB1, are written as hexadecimal numbers. You're not responsible for hexadecimal details, but briefly,… Hexadecimal addresses use digits that can have one of 16 values - 0 through 9 or A through F. See the example: 601bb1 contains six hex digits, the fourth and fifth containing the odd-looking b hex digit. "Hexadecimal" comes from the Greek "hexi" for six and the Latin "decimal" for ten. Six plus ten makes sixteen and the hexadecimal number system uses sixteen unique symbols. 5. Note how we instantiate a Car object and then print its toString value. When car.toString is called, the JVM gets the inherited toString method from the Object class and prints the class name, Car, followed and the Car object's hashcode value. Car is not part of a package, so there's no package prefix in front of Car. The Object class is in the java.lang package. 4 hashcode 3
9
The toString Method Retrieving the class name, sign, and a hashcode is usually worthless, so you'll almost always want to avoid calling the Object class's toString method and instead call an overriding toString method. In general, toString methods should return a string that describes the calling object's contents. You'll find lots of overriding toString methods in the Java API classes. For example, the Date class's toString method returns a Date object's month, day, year, hour, and second values as a single concatenated string. Since retrieving the contents of an object is such a common need, you should get in the habit of providing a toString method for most of your programmer-defined classes. Typically, your toString methods should simply concatenate the calling object's stored data and return the resulting string. Note that toString methods should not print the concatenated string value; they should just return it!!! 1 2 1. The only reason I covered the Object class's toString method is because you might accidentally call it and I don't want you to freak out when you see class hashcode. Later on, I'll explain how you can accidentally call the toString method. 2. The Object class's toString method doesn't do a very good job of that, but you shouldn't blame it too much. After all, an Object object doesn't contain much useful data - it contains the object's class name and its memory location, so that's what it returns. 3. For a diversion, look up the java.util.Date (not java.sql.Date) API documentation online and note the format of the string returned by toString. 4. I'm mentioning this point because many students in the past have put print statements in their toString methods and that's wrong. A method should only do what it's supposed to do and nothing more - toString is supposed to return a string value and that's it! 5. I give an example of a programmer-defined toString method on the next slide … 3 4 5
10
The toString Method Write a toString method for a Car class. Use this skeleton: public class Car { private String make; private int year; private String color; ... <toString method goes here> } // end class Car public class CarDriver public static void main(String[] args) Car car = new Car("Honda", 1998, "silver"); System.out.println(car); 1 4 5 1. See where the toString method definition should go? 2. Where's the statement that calls the toString method? There is no method call! Note: When a reference variable appears inside a System.out.println statement, the reference variable's toString method is automatically called. I go to the next slide, read the whole thing, and then return here. 3. So now where's the statement that calls the toString method? The System.out.println statement generates the call to the toString method! 4. I coax the students to write this: public String toString() { return "make = " + make + ", year = " + year + ", color = " + color; } 5. Note that the toString method returns the Car contents and it does not print the Car contents. 2 3
11
The toString Method The toString method is automatically called when a reference variable is an argument in a System.out.println or System.out.print call. For example: System.out.println(car); The toString method is automatically called when a reference variable is concatenated (+ operator) to a string. For example: String carInfo = "Car data:\n" + car; Note that you can also call an object's toString method using the standard method-call syntax. For example: car.toString(); 1 Notice that there is no explicit call to the toString method! It's automatically generated behind the scenes whenever there's a reference variable inside of a System.out.println statement. Cool! 2. Just like with the System.out.println example, there is no explicit call to the toString method in this example! It's automatically generated behind the scenes whenever there's a reference variable concatenated with a string. 3. I return to the previous slide … 2 3
12
The toString Method Write a toString method for a Counter class. Use this skeleton: public class Counter { private int count; ... <toString method goes here> } // end class Counter public class CounterDriver public static void main(String[] args) Counter counter = new Counter(100); String message = "Current count = " + counter; 3 4 5 6 1. Where's the statement that calls the toString method? When you concatenate a string to a reference variable, the reference variable's toString method is automatically called. 2. Note that you'll often see the toString method explicitly called even when it's not necessary. I write this on the board with an arrow pointing to "counter": optional: counter.toString() 3. Let's write the toString method definition. I write this skeleton on the board: public String toString() { } 4. How can we generate the string version of a number? Use a wrapper class toString method! I go through the entire wrapper class slide and return here. 5. So now how can we implement the Counter class's toString method body? I add this to the Counter class's toString method: return Integer.toString(count); [6. Acceptable alternatives for toString's body: return "" + count return String.valueOf(count);] 2 1
13
Wrapper Classes' toString Methods
1 All the primitive wrapper classes have toString methods that return a string representation of the given primitive value. For example: Integer.toString(22) : evaluates to string "22" Double.toString(123.45) : evaluates to string "123.45" 2 3 4 5 1. This slide's material should sound familiar because I covered wrapper class toString methods in Chapter 5. 2. Review: What are the names of the primitive wrapper classes? Boolean, Character, Integer, Long, Float, etc. 3. Are these toString methods class methods (using the static modifier) or instance methods? We know that they're class methods because they're prefixed with a class name! [4. a) Wrapper classes implement overriding toString instance methods, but it's easier to just use the static toString methods, so I'm not covering the overriding toString instance methods. b) The String class also implements the toString method, but it's worthless because you can just use the string itself without the toString method at all. c) I'm not bothering to show examples with the Byte and Short wrappers because they're not very useful. Short.toString(22) => compile error because the argument needs to be a short] 5. I return to the previous slide …
14
Polymorphism 1 Polymorphism is when different types of objects respond differently to the same method call. To implement polymorphic behavior, declare a general type of reference variable that is able to refer to objects of different types. To declare a "general type of reference variable," use a superclass. Later, we'll use a programmer-defined superclass. For now, we'll keep things simple and use the predefined Object superclass. In the following Pets program, note how obj is declared to be an Object and note how the obj.toString() method call exhibits polymorphic behavior: If obj contains a Dog object, toString returns "Woof! Woof!" If obj contains a Cat object, toString returns "Meow! Meow!" 1. Usually, the three most important characteristics of OOP are considered to be encapsulation, inheritance, and polymorphism. We've already talked about encapsulation and inheritance. Now let's talk about polymorphism. The word polymorphism comes from the Greek for "having many forms." 2. I go to the next slide and point out the obj declaration and the obj.toString method call (marked by green boxes). 2
15
Polymorphism Declare obj as a generic Object. Polymorphic method call.
1 import java.util.Scanner; public class Pets { public static void main(String[] args) Scanner stdIn = new Scanner(System.in); Object obj; System.out.print("Which type of pet do you prefer?\n" + "Enter d for dogs or c for cats: "); if (stdIn.next().equals("d")) obj = new Dog(); } else obj = new Cat(); System.out.println(obj.toString()); System.out.println(obj); } // end main } // end Pets class Declare obj as a generic Object. 1. I walk through this slide and stop at the polymorphic method call. I show the next slide. 2. What happens when the JVM sees the obj.toString method call? If obj holds a Dog object, then the JVM calls the Dog version of toString (see the next slide). If obj holds a Cat object, then the JVM calls the Cat version of toString (see the next slide). 3. What is the output? If the user enters d for dog, the program prints Woof! Woof! If the user enters something other than d, the program prints Meow! Meow! 4. What does println(obj) do? When a reference variable is an argument in a print statement, the reference variable's object calls its toString method. So the last two statements in the Pets class are equivalent. Polymorphic method call. 2 3 4
16
Polymorphism public class Dog { public String toString()
return "Woof! Woof!"; } } // end Dog class public class Cat return "Meow! Meow!"; } // end Cat class
17
Dynamic Binding 1 Polymorphism is a concept. Dynamic binding is a description of how that concept is implemented. More specifically, polymorphism is when different types of objects respond differently to the exact same method call. Dynamic binding is what the JVM does in order to match up a polymorphic method call with a particular method. We'll now describe how that "matching up" process works. Just before the JVM executes a method call, it looks at the method call's calling object. More specifically, it looks at the type of the object that's been assigned into the calling object's reference variable. If the assigned object is from class X, the JVM binds class X's method to the method call. If the assigned object is from class Y, the JVM binds class Y's method to the method call. After the JVM binds the appropriate method to the method call, the JVM executes the bound method. 1. The terms polymorphism and dynamic binding are intimately related, but they're not the same. It's important to know the difference. 2. I present the below comments while referring to the Pets program on the previous slides. Just before executing the obj.toString method call, the JVM looks at the obj calling object. It looks at the type of the object that's been assigned into the obj reference variable. If the user entered d for dog, then obj contains a Dog object. If the user entered something other than d, then obj contains a Cat object. Depending on which type of object is in obj, the JVM binds either Dog's toString method or Cat's toString method to the obj.toString method call. After binding takes place, the JVM executes the bound method and prints either "Woof! Woof!" or "Meow! Meow!" 3. Dynamic binding is referred to as "dynamic" because the JVM performs the binding operation while the program is running. Dynamic binding is also referred to as late binding because the binding takes place at the latest possible moment, right before the method is executed. By the way, some programming languages bind method calls at compile time rather than at run time. That type of binding is called static binding. Java's designers decided to go with dynamic binding rather than static binding because dynamic binding enables polymorphic behavior. 2 3
18
Dynamic Binding Compilation Details
1 If Dog implements a display method that prints "I'm a dog", would the following code work? Object obj = new Dog(); obj.display(); Be aware of these compiler issues when dynamic binding takes place: When the compiler sees a method call, <reference-variable>.<method-name>(), it checks to see if the reference variable's class contains a method definition for the called method. Normally, when you assign an object into a reference variable, the object's class and the reference variable's class are the same. But note in the above example how an object of type Dog is assigned into a reference variable of type Object. Such assignments only work if the right side's class is a subclass of the left side's class. 2 3 1. Note the slide title. 2. Ideally, the JVM would see a Dog object in the obj reference variable and bind the Dog's display method to the obj.display method call. But the code won't compile successfully. I continue reading the slide…. 3. Note the obj.display method call in the example. The compiler checks to see if obj's class, Object, contains a display method. The Object class does not contain a display method, so the code produces a compilation error. 4. Note the obj.toString method call in the Pets program. The compiler checks to see if obj's class, Object, contains a toString method. The Object class does contain a toString method, so the code compiles successfully. 5. I point out the Object obj = new Dog; statement. 6. Dog is certainly a subclass of Object since all classes are subclasses of the Object class. 4 5 6
19
Polymorphism with Arrays
1 The real usefulness of polymorphism comes when you have an array of generic reference variables and assign different types of objects to different elements in the array. That allows you to step through the array and for each array element, you call a polymorphic method. At runtime, the JVM uses dynamic binding to pick out the particular methods that apply to the different types of objects that are in the array. To illustrate polymorphism with arrays, we present a payroll program that stores payroll data in an employees array…. 1. In the previous slides, we introduced polymorphism with the help of a very simple Pets program. The Pets program served its purpose – it illustrated the basics. But it didn't illustrate the real usefulness of polymorphism.
20
Polymorphism with Arrays
UML class diagram for the Payroll program: 1 2 1. The Employee class is a superclass for Salaried and Hourly subclasses. The Payroll class is a container for the Salaried and Hourly employees - see how Payroll contains an array of Employee elements in Payroll's main method? 2. Who can spot the polymorphic method? The getPay method is defined in the superclass, Employee, as well as the subclasses, Salaried and Hourly. When an employees element calls getPay, either the Salaried getPay method or the Hourly getPay method is bound to the method call. The decision of which method is executed is based on the type of object that's been assigned into the employees element.
21
Polymorphism with Arrays
1 public class Payroll { public static void main(String[] args) Employee[] employees = new Employee[100]; int day; // day of week (Sun=0, Mon=1, ..., Sat=6) Hourly hourly; employees[0] = new Hourly("Aza", 25.00); employees[1] = new Salaried("Ben", 48000); employees[2] = new Hourly("Joby", 20.00); 2 3 4 5 1. Let's now walk through the Payroll program's source code…. 2. The employees array keeps track of all the employees that are in the payroll system. 3. We need to keep track of the day of the week because certain types of employees (hourly employees) get paid on Fridays. 4. Note the 2 Hourly objects and the 1 Salaried object assigned into the first 3 employees elements. What do you think the constructor call arguments are for? I go to the Hourly and Salaried slides and walk through the Hourly and Salaried constructors and return here. 5. Let's identify the polymorphism. I go to the 4th Payroll slide and show where main calls printPay. 6. I go to the Employee class slide and show how printPay prints the date and the employee's name and then calls the polymorphic getPay methods. Note the Employee class's getPay method - does it get called? No, it's a dummy method that's needed to satisfy the compiler. Since the employee elements contain Salaried and Hourly objects, the Salaried and Hourly versions of getPay get called. 7. I go to the Salaried and Hourly slides and show how getPay returns data that's specific to the Salaried and Hourly classes and return to the next slide. 6 7
22
Polymorphism with Arrays
1 // This driver arbitrarily assumes that the payroll's month // starts on a Tuesday (day = 2) and contains 30 days. day = 2; for (int date=1; date<=30; date++) { day++; // change to the next day of the week day %= 7; // causes day of week to cycle from 0-6 repeatedly // Loop through all the employees for (int i=0; i<employees.length && employees[i] != null; i++) 2 1. This is a continuation of the main driver. I read the comment and show the associated code. If you want to learn how to get 1) the actual day of the week for a particular month's first day and 2) the number of days in a particular month, go to Sun's Java API Web site and read up on the Calendar class. [int lastDayInCurrentMonth = Calendar.getInstance().getActualMaximum(Calendar.DAY_OF_MONTH);] 2. What's the point of the day++ and day%=7 statements? They cause the day of the week to change to the next day, and they ensure that the day of the week cycles from 0 to 6 repeatedly. I write day = day % 7 on the board and show how 7 % 7 evaluates to 0 and 0..6 % 7 evaluates to the original 0..6. 3. Why is the employees[i] != null necessary? Because only 3 of the 100 elements in the employees array are filled up (see the previous slide); the other elements are null. 3
23
Polymorphism with Arrays
if (day > 0 && day < 6 && employees[i] instanceof Hourly) { hourly = (Hourly) employees[i]; hourly.addHours(8); } The instanceof operator returns true if the object at its left is an instance of the class at its right. 1 4 5 The cast operator is necessary because without it, you'd get a compilation error. Why? Because we're attempting to assign a superclass object into a subclass reference variable (employees is defined with an Employee superclass type and hourly is defined with an Hourly subclass type). If you want to assign a superclass object into a superclass reference variable, you can do it, but only if the "superclass object" really contains a subclass object and you include a cast operator. 2 1. Read the instanceof green box. Note that instanceof is an operator, not a method call, so there are no parentheses and the o in of is not capitalized. 2. Read the cast green box. 3. How do you know that the employees[i] object really does contain an Hourly object? We're inside an if statement that checks to make sure employees[i] is an instanceof Hourly. 4. Note the hourly.addHours(8) call. I go to the Hourly slide and show the addHours method and return to the next slide…. [5. Why do we bother to assign employees[i] into hourly prior to calling addHours? Why not call employees[i].addHours and let polymorphism bind Hourly's addHours method to employees[i]? There would be a compilation error because employees[i] is an Employee, and the Employee class does not have an addHours method.] 3
24
Polymorphism with Arrays
1 // Print hourly employee paychecks on Fridays. // Print salaried employee paychecks on 15th and 30th. if ((day == 5 && employees[i] instanceof Hourly) || (date%15 == 0 && employees[i] instanceof Salaried)) { employees[i].printPay(date); } } // end for i } // end for date } // end main } // end class Payroll 1. We're still inside the nested loops that iterate through the first 30 days of a month and iterate through each employee in the employees array (verify on the previous slides). Now we print a paycheck if it's appropriate. I read the comments and analyze the code. 2. We've already looked at the Employee class's printPay and getPay methods in the next slide, but let's look at it again as a lead in to our next topic (after glancing at the getPay method, I jump to the abstract slide). 2
25
Polymorphism with Arrays
public class Employee { private String name; //***************************************************** public Employee(String name) this.name = name; } public void printPay(int date) System.out.printf("%2d %10s: %8.2f\n", date, name, getPay()); } // end printPay // This dummy method is needed to satisfy the compiler. public double getPay() System.out.println("error! in dummy"); return 0.0; } // end getPay } // end class Employee polymorphic method call This method never executes; it's provided to satisfy the compiler.
26
Polymorphism with Arrays
public class Salaried extends Employee { private double salary; //*********************************************************** public Salaried(String name, double salary) super(name); this.salary = salary; } // end constructor public double getPay() return this.salary / 24; } // end getPay } // end class Salaried
27
Polymorphism with Arrays
public class Hourly extends Employee { private double hourlyRate; private double hours = 0.0; //*********************************************************** public Hourly(String name, double rate) super(name); hourlyRate = rate; } // end constructor public double getPay() double pay = hourlyRate * hours; hours = 0.0; return pay; } // end getPay public void addHours(double hours) this.hours += hours; } // end addHours } // end class Hourly
28
abstract Methods and Classes
1 Declare a method to be abstract if the method's class is a superclass and the method is merely a "dummy" method for an overriding method(s) in a subclass(es). Java requires that when you define a method to be abstract, you must: Use an abstract method heading instead of a method definition. An abstract method heading is the same as a standard method heading except that it includes the abstract modifier and a trailing semicolon. Define an overriding version of that method in each of the superclass's subclasses. Define the superclass to be abstract by using the abstract modifier. In defining a class to be abstract, you're telling the compiler to not allow the class to be instantiated; i.e., if a program attempts to instantiate an abstract class, a compilation error is generated. 2 3 1. The Employee class's getPay method is "kludgy." Kludgy code = ugly/inelegant code whose purpose is to provide a workaround for a problem. Kludgy code is fairly common in industry and it hinders maintainability. Sometimes, there's no better solution than the kludgy workaround code, but in this case, there is a better solution.... 2. The Employee class's getPay method doesn't do anything - it's just a dummy method. The Salaried and Hourly classes contain overriding getPay methods that do all the work. Therefore, it's appropriate to declare the Employee class's getPay method to be an abstract method. I'll show the code for that shortly. 3. I show the getPay method's abstract modifier on the next slide, read through the slide's notes, and return here. 4. This should make sense. The point of an abstract method is to have a placeholder in the superclass and have an actual method in each of the subclasses. Have we followed this rule for our Employee example? i.e., do we have overriding versions of the getPay method? Yes - You've already seen the overriding getPay methods in the Salaried and Hourly classes. 5. I show the Employee class's abstract modifier on the next slide and return here. 6. I write this at the bottom of the Employee class on the next slide: public static void main(String[] args) { Employee emp = new Employee("Jill"); // compilation error } 4 5 6
29
abstract Methods and Classes
public abstract class Employee { private String name; public abstract double getPay(); //***************************************************** public Employee(String name) this.name = name; } public void printPay(int date) System.out.printf("%2d %10s: %8.2f\n", date, name, getPay()); } // end printPay } // end class Employee 1 2 3 1. Note the abstract heading for getPay: abstract modifier trailing semicolon 2. For style reasons, abstract headings should appear above your constructors and method definitions. Why? Because if they were down among the method definitions, they'd be hard to find since they are only one line long. [3. I tested: OK to put abstract before the public/private access modifier. But don't do it because it looks weird.]
30
protected Access Modifier
1 2 The protected access modifier is in between the public and private modifiers in terms of how accessible something is. protected members (instance variables, class variables, and methods) can only be accessed by classes within the subtree associated with the member's class. 3 4 5 [1. The protected access modifier is needed if protected problems are assigned, but otherwise, the protected access modifier can be skipped. I skip the protected slides.] 2. So far, we've discussed only two modes in terms of accessibility for a class's members: public and private. Public members can be accessed from anywhere. Private members can only be accessed from inside the members' class. 3. I point out and circle the Employee class's subtree and the Manager class's subtree. 4. Suppose that there's a protected member in the Employee class. What classes can access it? Employee, Manager, Laborer, Secretary, Executive, Middle Manager 5. Suppose that there's a protected member in the Manager class. Manager, Executive, Middle Manager [6. Actually, protected members can also be accessed by any class that's in the package associated with the member's class. If you want to learn about package details, see Appendix 4.] 6
31
protected Access Modifier
When to use the protected access modifier: When you want a member to be directly accessible from any class within its subtree of classes, but you don't want it to be accessible elsewhere. Example: Suppose that the Employee class contains an employeeId instance variable and all of the descendant classes need to access it. To make access easier for the descendant classes, declare employeeId with the protected access modifier: protected int employeeId; Then, the descendant classes can access employeeId directly rather than having to use a getId() accessor method call.
32
Chapter 13 - Quiz Questions
What is the name of the class that is the superclass of all other classes? Object class Class class Grandfather class Dynamic binding is also called: early evaluation early binding late binding 1. a 2. c
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.