Object-Oriented Programming II
Table of Contents
1 Reading
For a good overview of the OOP concepts we've covered as well as the Java syntax and terminology, read Algorithms 1.2.
2 Video
Here is a video lecture for the material outlined below. If you prefer (or want supplemental) textbook readings, I would recommend Defining Classes in Java from the Java for Python Programmers book (this covers material from Wednesday's topic as well).
The video contains sections on
- Java Packages (0:44)
- Access level (3:27)
public
(4:49)private
(6:48)protected
(8:08)- default access level (9:14)
Circle
example v1 (9:58)static
- Making a field immutable via
final
(17:21) - What is an interface? (19:22)
Shape
interface (19:58)- Class hierarchy (21:33)
extends
(22:04)implements
(25:57)- Class hierarchy diagram (31:58)
Circle
example v2 (32:40)
The Panopto viewer has table of contents entries for these sections: https://carleton.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=6cbfc35d-1fe2-403f-8454-aca5017ed035
3 Access Modifiers
- Background: Java packages
- A package is how Java groups together related classes
- For example, the Java package
java.lang
includes various built-in classes such asString
andMath
- Classes from
java.lang
are always available (don't need to be imported), but classes from other packages likeScanner
need to be imported in order to be used (import java.util.Scanner;
)- Alternatively, you can write
java.util.Scanner
everywhere and forego the import statement (not recommended)
- Alternatively, you can write
- For example, the Java package
- Packages, like classes, are also a layer of encapsulation, meaning they have the ability to hide implementation details
- A package is how Java groups together related classes
- To support abstraction, Java provides a way to specify the access level of classes, methods, and fields
- The access level determines who, if anyone, can access a particular method or field outside of the class that it's in
- Similarly with who can access a class outside of its package
- Access level is also sometimes referred to as visibility
- These access modifiers are keywords that are used
- For methods and fields:
public
- Accessible to everyone with no restrictions
- The author of a class controls how users of that class will interact with it by deciding what methods will be
public
- Fields should (almost never) be
public
, as this exposes the class' underlying implementation (thus breaking abstraction) - Since a class'
main
method is how outside users run the program associated with that class, it must always bepublic
private
- Only accessible in the class where they are declared
- Appropriate for fields and "helper" methods that support the functionality of
public
methods (but don't make sense to be called directly by code using the class)
- We will likely only ever use
public
andprivate
in this course, but there are two other access levels in between these two which I will include here for completeness protected
- Accessible to all classes declared in the same package and any extension to the class whether in the same package or not
- default (i.e., what you get when no access modifier is given)
- Accessible to all classes declared in the same package
- Also called package-private
- To control visibility of classes within a package:
public
- A class declared as
public
is visible to everyone
- A class declared as
- default (i.e., what you get when no access modifier is given)
- A class that isn't declared to be
public
is package-private, only accessible to classes declared in the same package
- A class that isn't declared to be
4 static
- A field or method can be associated with a class or with an object
- That is, it might depend on the state of a particular instance (associated with an object) or be independent of any particular instance (associated with a class)
- Let's make this concrete with an example class representing a circle
public class Circle { private double radius; public Circle(double r) { radius = r; } public double getRadius() { return radius; } public double getArea() { return radius * 3.14159265; } }
- So far this is nothing new, the field
radius
and the two accessor methods all depend on a specific instance ofCircle
- These are called instance variables or instance methods
- If we want the area of a circle a radius 10, we have to write
Circle temp = new Circle(10); double area = temp.getArea();
- Now let's expand
Circle
in two ways: make π a named variable we can reuse and create a method to compute the area of an arbitrary circle
public class Circle { private static double pi = 3.14159265; private double radius; public Circle(double r) { radius = r; } public double getRadius() { return radius; } public double getArea() { return radius * radius * pi; } public static double computeArea(double r) { return r * r * pi; } }
- The
static
keyword makes a field or method part of the class itself rather than a property of each class instance - This means we can invoke
Circle.computeArea
to get the area of a circle with a given radius without needing to create aCircle
object:
double area = Circle.computeArea(10);
- Our field
pi
must bestatic
in order to be available tocomputeArea
—otherwisecomputeArea
would need to create aCircle
object to access it! - One improvement we can make is to cause
pi
to be immutable (meaning its value can never change)- If our code is assuming
pi
will always have the correct value, we should construct our code in such a way to guarantee this assumption - We can declare a variable
final
to give it this immutable property—it is not possible to modify afinal
variable after it's initializedpublic static final double PI = 3.14159265
- It's conventional to make the names of static immutable variables all caps (to set them apart as constants)
- If our code is assuming
- And now that a user of the
Circle
class can't modifyPI
, we can safely make itpublic
5 Interfaces
- Interface
- A contract or template for methods a class must provide
- Intefaces don't provide any implementation themselves
- Note how in the
Shape
interface below we useinterface
instead ofclass
, and the method bodies are omitted
import edu.princeton.cs.algs4.Point2D; public interface Shape { public Point2D getPosition(); public void setPosition(Point2D pos); public double getArea(); }
- Class hierarchy
- A set of relationships between classes and/or interfaces
extends
relationship- When one definition
extends
another it inherits allpublic
methods and data - The original is said to be the supertype and the extension the subtype
- So in the example below,
Polygon
would be a subtype ofShape
(andShape
would be a supertype ofPolygon
) - Every
Polygon
is aShape
, but not everyShape
is aPolygon
- The
Polygon
interface inherits all the methods fromShape
, so we don't have to specify themimport edu.princeton.cs.algs4.Point2D; public interface Polygon extends Shape { public Point2D[] getVertexes(); }
- So in the example below,
- When one definition
implements
relationship- We can make use of an interface by defining a class that
implements
it - This means the class must provide an implementation for every method specified in the interface (it won't compile otherwise)
- This means, for example, that when a class
implements Polygon
, we know it has all the methods specified inShape
andPolygon
import edu.princeton.cs.algs4.Point2D; import edu.princeton.cs.algs4.StdRandom; class Rectangle implements Polygon { // instance variables private double width; private double height; private Point2D position; // constructor Rectangle(double w, double h) { width = w; height = h; position = new Point2D(StdRandom.uniform(), StdRandom.uniform()); } // accessor methods public double getWidth() { return width; } public double getHeight() { return height; } @Override public Point2D getPosition() { return position; } @Override public void setPosition(Point2D pos) { position = pos; } @Override public double getArea() { // required by Shape interface return width * height; } @Override public Point2D[] getVertexes() { // required by Polygon interface Point2D[] verts = new Point2D[4]; // clockwise starting with upper left verts[0] = new Point2D(position.x() - width / 2, position.y() - height / 2); verts[1] = new Point2D(position.x() + width / 2, position.y() - height / 2); verts[2] = new Point2D(position.x() + width / 2, position.y() + height / 2); verts[3] = new Point2D(position.x() - width / 2, position.y() + height / 2); return verts; } }
- We can make use of an interface by defining a class that
- A circle is a shape, but not a polygon, so adapting our
Circle
class from before to use an interface would meaning implementingShape
:public class Circle implements Shape { private static final double PI = 3.14159265; private double radius; private Point2D position; public Circle(double r) { radius = r; position = new Point2D(StdRandom.uniform(), StdRandom.uniform()); } public double getRadius() { return radius; } @Override public Point2D getPosition() { return position; } @Override public void setPosition(Point2D pos) { position = pos; } @Override public double getArea() { return radius * radius * PI; } static double computeArea(double r) { return r * r * PI; } }
6 Practice Problems1
- Which of the following is the correct syntax to indicate that class A is a subclass of B?
public class B extends A {
public class A : super B {
public A(super B) {
public class A extends B {
public A implements B {
- Consider the following class:
// Represents a university student. public class Student { private String name; private int age; public Student(String name, int age) { this.name = name; this.age = age; } public void setAge(int age) { this.age = age; } }
Also consider the following partial implementation of a subclass of
Student
to represent undergraduate students at a university:public class UndergraduateStudent extends Student { private int year; ... }
Can the code in the
UndergraduateStudent
class access thename
andage
fields it inherits fromStudent
? Can it call thesetAge
method? - Consider these two classes:
public class Car { public void m1() { System.out.println("car 1"); } public void m2() { System.out.println("car 2"); } public String toString() { return "vroom"; } } public class Truck extends Car { public void m1() { System.out.println("truck 1"); } }
What is printed as a result of this code?
Car mycar = new Car(); Truck mytruck = new Truck(); System.out.println(mycar); mycar.m1(); mycar.m2(); System.out.println(mytruck); mytruck.m1(); mytruck.m2();
- Imagine that you are going to write a program to play card games. Consider a design with a
Card
class and 52 subclasses, one for each of the unique playing cards (for example,NineOfSpades
andJackOfClubs
). Is this a good design? If so, why? If not, why not, and what might be a better design? - What is the difference between implementing an interface and extending a class?
- What’s wrong with the code for the following interface? What should be changed to make a valid interface for objects that have a border color?
public interface BorderColor { private Color borderColor; public Color getBorderColor() { return borderColor; } }
7 Learning Block
- Questions?
- Get to know you, what's a place or a person from the past you'd like to visit or meet
- Form question
- Demo compiler/runtime errors
- code outside a class
- wrong main signature
- array index exception
- syntax error
- missing ;
- missing "
- missing )
- missing operator
- wrong variable name
- forgot type on declaration
- file name doesn't match class name
- wrong parameters
- forgot () on a method call
- put () on a field access
- divide by zero
- null pointer exception
- type mismatch
- Flying shapes demo
- Note that we can have an array of type
Shape[]
that stores bothCircle
objects andRectangle
objects. This is called polymorphism.Shape
is a supertype of bothCircle
andRectangle
, and an object can always be treated as if they were an instance of their supertype. Since theShape
interface in the flying-shapes example defines amove
method, we can call it on objects of typeShape
. - Also note on line 58 of
ShapeFuntimes.java
how we useinstanceof
to check if a particular object is an instance ofPolygon
(or one of its subtypes, likeRectangle
), and then cast the object to aPolygon
when passing it todrawStreamers
. ShapeFuntimes.java
also demonstrates the implementation of severalstatic
helper methods that are used in bothCircle
andRectangle
, as well as in themain
method.
- Note that we can have an array of type
Footnotes:
Solutions:
- (4)
public class A extends B {
- The
name
andage
fields are decalred to beprivate
, so theUndergraduateStudent
class cannot access them. It can access thepublic
setAge
method. - When an object is printed, it's
toString
method is automatically called to get the string to be printed.Truck
inheritstoString
andm2
fromCar
and does not override either like it doesm1
. Thus, it simply uses the versions oftoString
andm2
defined inCar
.vroom car 1 car 2 vroom truck 1 car 2
- This is not a good design because it uses separate classes to represent something that is more appropriately data within the
Card
class (i.e., the suit and value of the card). See Bailey 7.3 (p. 155–160) for a better design. - Extending a class causes your class to inherit all methods and data from that class. Implementing an interface forces you to write your own code to implement all the methods in that interface.
- What's wrong is that interfaces can't declare fields or write bodies for methods. The following is a correct
BorderColor
interface:public interface BorderColor { public Color getBorderColor(); }