
Advantages of Object-Oriented Programming and Creating Classes in Java
Understand the benefits of Object-Oriented Programming (OOP), learn how to define classes and objects in Java, and explore concepts like inheritance, creating objects, and defining classes with internal values. Discover how classes define the structure and behavior of objects, and how to access and manipulate data within classes.
Download Presentation

Please find below an Image/Link to download the presentation.
The content on the website is provided AS IS for your information and personal use only. It may not be sold, licensed, or shared on other websites without obtaining consent from the author. If you encounter any issues during the download, it is possible that the publisher has removed the file from their server.
You are allowed to download the files provided on this website for personal or commercial use, subject to the condition that they are used lawfully. All files are the property of their respective owners.
The content on the website is provided AS IS for your information and personal use only. It may not be sold, licensed, or shared on other websites without obtaining consent from the author.
E N D
Presentation Transcript
Classes and Objects The main advantage of OOP is that you can grow the language add our own classes and their behavior how they function, what they can do, what they store build on already existing classes by extending them extending a class uses a process called inheritance we discuss this in chapter 11 In chapter 9, we look at defining our own classes but before we do so, let s review some concepts about classes and objects A class is a definition we can define our own classes many classes already exist in Java (we ve seen numerous ones throughout this semester: String, Math, Random, Date, Scanner, etc Once we define a class, we use it by creating objects an object is an instance of a class we assign a variable to refer to an object and create one using the word new
Objects A class is a definition An object is a specific instance of the class the instance is stored in heap memory we access the object through a reference variable the reference variable stores the address in heap memory of the object, in other languages we refer to the reference as a pointer we pass the object messages each message is implemented as a method passing a message to the object invokes the corresponding method in that class if we assign our reference variable to a new object, the old object is no longer being referenced (pointed to) and this causes the Java run-time environment s garbage collector to reclaim it as memory to be allocated later The class defines the internal portions of the object the data and methods Once we have our class, we can create any number of objects each object shares the same structure (the same internal parts) but is stored in its own area of memory so has its own specific values
Defining Our Own Class To define our own class we must name it decide what internal values it will store we refer to these pieces of data as instance data we specify the visibility of these data using visibility modifiers whether they can be directly accessed from outside the class or not, usually we want them hidden (using the word private) write the methods needed to access instance data access can be to retrieve data, change data, store new data, output data the methods give our class its behavior what it can do and how it does it we specify visibility modifiers on our methods We must write and compile our class before we can create objects of it We almost never run a class on its own to run a class, it needs a main method, mostly our classes will not have a main method instead, we write a user program which will create objects of our class and use them through message passing
public class Circle { private double radius; public Circle(double r) { radius = r; } Sample Class: Circle A circle will have a radius A circle will need to compute things like its circumference (perimeter) and area We define our Circle class to have one instance datum, radius (double) two computational methods: getArea, getPerimeter a method to access the value of the radius a method to set the radius to a new value a method (called a constructor) to initialize a Circle object public Circle() { radius = 1.0; } public void setRadius(double r) { if(r>0) radius = r; } public double getRadius() {return radius;} public double getArea() { return Math.PI * radius * raduis; } public double getPerimeter() { return Math.PI * 2 * radius; } }
Comments The words public and private are our visibility modifiers private items cannot be accessed from outside of the class public items can be accessed from anywhere we usually make all instance data private this prevents another object from reaching into this object and changing it we usually make all methods public which define the interface to our object we may have private methods if the methods are intended to only be invoked from inside the class itself Let s look at the Circle class what is the value of making radius private when we can change it using the setRadius method? notice that for the radius to change, it must be > 0 this makes sense from a Circle s point of view, any radius must be a positive number so by restricting access by making radius private an outside source can only change a Circle s radius through setRadius which itself controls the new radius to make sure it is a reasonable value
Class Scope With the class definition, we have a new form of scope the instance datum which is accessible throughout the class if private and anywhere if public notice this leads to a potential interesting conflict if you define a parameter in a method whose name matches an instance datum s name see the code to the right where someMethod and someMethod2 receive a and be respectively for b = a; what is a referring to? for b = b; what is b referring to? public class SomeClass { private int a, int b; public SomeClass() { a = 0; b = 1; } public someMethod(int a) { b = a; } public someMethod2(int b) { b = b; } }
Constructors We ve introduced a new type of method here called a constructor In the Circle example, the first two methods were its constructors multiple constructors because we used method overloading Constructors have the form public ClassName(params) there will never be a return type for the constructor the constructor must always be public and use the name of the class as its name you must always include a no-arg constructor (no parameters) or one will be generated for you automatically by the Java compiler we explore why we need the no-arg constructor in chapter 11 but you can define as many constructors as you like as long as they all have different parameter profiles The constructor is invoked whenever you use new as in Circle c = new Circle( ); The idea behind a constructor is to initialize some or all of the class instance data
Using the Circle Class Circle has no main method therefore, we can not run it directly How then do we use it? compile Circle (and debug any syntax errors that exist) write a separate program, say CircleUser this program will have a main method create one or more variables of type Circle instantiate it(them) pass it(them) messages Notice the methods of Circle are not static we usually use static methods when a class has a main method we will consider what static means later in these notes public class CircleUser { public static void main(String[] args) { Circle c1, c2; c1 = new Circle(10.5); c2 = new Circle(); System.out.println(c1.getArea()); System.out.println(c2.getPerimeter()); c2.setRadius(6.25); System.out.println(c2.getArea()); c1.setRadius(-1); System.out.println(c1.getRaduis()); } } c1 and c2 are both Circles but they are stored in different areas of heap memory and have different values for radius Notice in the second to last instruction that c1 s radius will not change
Why Classes? Did we really need a class called Circle in CircleUser we could have written methods to compute areas and perimeters given the radius of a circle, so what value is Circle? we can use the Circle class from many other programs If Circle was doing more, then it becomes more useful to have a separate class that can be used by multiple User classes We could expand Circle to include its central point, its color, etc and then use it in a drawing program which can draw circles in a Graphics region (something you learn about in 360) compute about proximity to other Circles in a geography program Its the reusability that makes classes valuable we can make a class even more reusable by extending it through inheritance an extended version of Circle (say DrawingCircle) could then be given more instance data and methods to add to the functionality of Circle
UML Notation The Unified Modeling Notation used to describe objects Generally divided into two areas: instance data, methods instance data are listed using the notation name: type methods use + to indicate they are public and include parameters and return type the indicates that the item is private which should generally be the case for all instance data To the right is an example of a TV class can you figure out its instance data and methods? if not, see page 327-328 for its implementation TV -channel: int -volumeLevel: int -on: boolean +TV() +turnOn(): void +turnOff() : void +setChannel(newChannel: int): void +setVolume(newVolumeLevel: int): void +channelUp(): void +channelDown(): void +volumeUp(): void +volumeDown(): void We might want another constructor that provides the TV s max number of channels and value as in +TV(maxChannel: int, maxVolume: int) and add instance data of maxChannel and maxVolume
Accessing an Objects Data and Methods As we have seen we access an object s method via message passing The syntax is object.method(params) for methods We can also access an object s data via object.datum but we can only access those items that are visible meaning that the instance datum being referenced must be public We want to use private for instance data to prevent such access recall our Circle class, if radius was public, then the CircleUser program could do c1.radius = -1; which would violate how we want to treat our Circles However, user programs often have a need to access and change instance data of an object we need some method in the class interface to access every instance datum and possibly a method to change every instance datum we refer to these types of methods as accessors and mutators every mutator should probably test the parameter(s) passed in to make sure the new value for the instance datum makes sense
The Value null and NullPointerExceptions One danger in OOP is passing messages to an object that has not yet been instantiated Recall that all variables that store objects are actually reference variables (the address in the heap memory of where that object is stored) if a variable has not yet been assigned an address it is given the special value null if, when passing a message to an object, that object has the value null, we get a run-time exception called a NullPointerException the reason is that the variable has no object to pass a message too the NullPointerException does not necessarily mean that the program will terminate as we can provide our programs with sets of code called exception handlers (we cover this in 360) for now, we can avoid NullPointerExceptions by testing any reference variable before we pass it a message using code like the following if(variable!=null) variable.method(params); this solution, while useful, can be time and space consuming to use, so we will assume that we won t have NullPointerExceptions for the remainder of our programs
Static Variables, Constants and Methods The word static has a specific meaning in Java an item that is static is shared among all objects of the class consider the Circle class, if radius were static it would mean every Circle object would share the same radius We will usually not have static variables in a class because there is little need here s an example, consider a class called Library used to keep track of all of the library books loaned out by every Library in town we add a variable called totalLoanedBooks which is static every library can increment this shared variable we refer to a static variable as a class variable (or a class-wide variable) a static constant makes more sense, a constant in a class will never change so why not share the same constant among all objects of the same class? A static method is shared among all instances of objects but the interesting aspect of a static method is that you do not have to create an object to use it we see this with the Math class we did not need a Math object, instead we could do Math.abs or Math.sqrt note that a static method cannot access non-static instance data of its class
Static Example Here we see a simple class that has static components We see one static instance datum, d3 it will be shared among all instances all d3 does is count the number of times any object s d1 or d2 is incremented There is one static method, foo, which is not allowed to access d1 or d2 but could access d3 Notice that d3 has no accessor but we could give it one or we could obtain it by call StaticExample.foo(1); note: in UML, a static method is underlined foo(int) : int public class StaticExample { private int d1, d2; private static int d3; public StaticExample(int a, int b) { d1 = a; d2 = b; d3 = 0; } public static int foo(int d) { return d * d3; } public void increment1() { d1++; d3++; } } public void increment2() { d2++; d3++; public int getD1() {return d1;} public int getD2() {return d2;} }
No-arg Constructors, Garbage Collection If you do not write a constructor for your class, the Java compiler automatically generates a no-arg constructor this constructor does not do anything because the compiler has no idea what it should do, so its only use is as a target for the new Class() invocation We will see why we need a no-arg constructor when we look at inheritance in chapter 11 All objects come from the heap the heap provides dynamically allocatable memory (memory that is provided at run-time rather than compile time) When an object is no longer needed, we need to give that memory space back to the heap the Java run-time environment (the JVM) automatically allocates and deallocates objects for us the deallocation occurs when an allocated area of memory is no longer being referenced by a variable (see the next slide) the JVM uses a technique called garbage collection to locate and deallocate no longer used memory not all programming languages use garbage collection for instance C and C++ do not so it is up to the programmer to ensure that once an object is no longer of use, it can be reclaimed by the heap we will explore this in 362
How Garbage Collection Works Object type assignment c1 = c2 There are three ways we can deallocate a chunk of memory Assign the object to null c1 = null; Assign the object to a new piece of memory c1 = new Circle( ); Assign the object to another already existing object c1 = c2; In all 3 cases, the old object in heap memory is garbage collected Before: After: c1 c1 c2 c2 C2: Circle radius = 2 c1: Circle radius = 1 C2: Circle radius = 2 c1: Circle radius = 1 The space reserved for c1 is now garbage collected
The this Reserved Word The word thisrefers to this object There are a few instances where we need to have an object refer to itself we see this for instance when we use Listeners something we cover in 360 The one useful use of this arises out of laziness Consider the partial class code to the right the second constructor has a problem in that we the references to a and b are to the parameters passed to the constructor, not the class instance data (the variables on the right of the assignment are meant to reference the params while on the left the instance data) we resolve this problem by adding the word this to the variable as in this.a = a; public class ThisExample { private int a, b; public ThisExample() { a = b = 0; } public ThisExample(int a, int b) { a = a; b = b; } } public ThisExample(int a, int b) { this.a = a; this.b = b; } We can also use this in a no-arg constructor, for instance by doing public ThisExample() { this(0, 0); }
Some UML Practice Two Java Classes java.util.Date The + sign indicates public modifer +Date() +Date(elapseTime: long) Constructs a Date object for the current time. Constructs a Date object for a given time in milliseconds elapsed since January 1, 1970, GMT. Returns a string representing the date and time. Returns the number of milliseconds since January 1, 1970, GMT. Sets a new elapse time in the object. Notice that this UML notation does not show us the private instance data! +toString(): String +getTime(): long +setTime(elapseTime: long): void java.util.Random +Random() +Random(seed: long) +nextInt(): int +nextInt(n: int): int +nextLong(): long +nextDouble(): double +nextFloat(): float +nextBoolean(): boolean Constructs a Random object with the current time as its seed. Constructs a Random object with a specified seed. Returns a random int value. Returns a random int value between 0 and n (exclusive). Returns a random long value. Returns a random double value between 0.0 and 1.0 (exclusive). Returns a random float value between 0.0F and 1.0F (exclusive). Returns a random boolean value.
Visibility Modifiers There are 4 types of visibility modifiers public any external entity can access the item usually limited to constants and methods, should never be used for instance data private no external entity can access the item usually used for instance data except when you expect the class to be extended protected only external entities that can access the item are subclasses used in place of private for a class that you expect to be extended package item is visible to items in its own class, extended classes and any classes defined in the same package (such as if an instance datum defined in Scanner was given package visibility, then any other class in java.util could access that instance datum of a Scanner) for package visibility, omit the modifier (that is, no visibility modifier means package) int x; // x has package visibility protected int y; // y has protected visibility private int z; // z has private visibility Programmers often omit modifiers out of laziness but this is a bad habit because it gives the item package visibility instead of private or protected
Example package p1; package p2; public class C1 { public int x; int y; private int z; public void m1() { } void m2() { } private void m3() { } } public class C2 { void aMethod() { C1 o = new C1(); can access o.x; can access o.y; cannot access o.z; can invoke o.m1(); can invoke o.m2(); cannot invoke o.m3(); } } public class C3 { void aMethod() { p1.C1 o = new p1.C1(); can access o.x; cannot access o.y; cannot access o.z; can invoke o.m1(); cannot invoke o.m2(); cannot invoke o.m3(); } } package p1; package p2; class C1 { ... } public class C2 { can access C1 } public class C3 { cannot access C1; can access C2; }
Passing Objects Recall that an object is referenced by a reference variable Passing an object means that the parameter being passed is a reference (an address) we refer to passing an address as a parameter as pass by reference instead of pass by value When the parameter is a reference, if we manipulate the internal portion of the referred object it changes the original, not a copy public class CircleUser { public static void main(String[] args) { Circle c1 = new Circle(10.1); c1.setRadius(10.2); System.out.println(c1.getRadius()); change(c1, 5.6); System.out.println(c1.getRadius()); } public static void change(Circle c, double d) { c.setRadius(d)); System.out.println(c.getRadius()); } } Output: 5.6 10.2 5.6
Changing Objects in a Method Let s modify the last example where the reference parameter is changed This is not the same as the last example in the last example, c is pointing to the same memory as c1 and therefore c.setRadius changes c1 s radius here, when we do c = new Circle(2.2); c in change is pointing to a different area of the heap than c1 when change changes c s radius, it is not impacting c1 when we return to main, c1 is still pointing at the Circle whose radius is 10.2 public class CircleUser { public static void main(String[] args) { Circle c1 = new Circle(10.1); c1.setRadius(10.2); System.out.println(c1.getRadius()); change(c1, 5.6); System.out.println(c1.getRadius()); } public static void change(Circle c, double d) { c = new Circle(2.2); c.setRadius(d)); System.out.println(c.getRadius()); } } Output: 10.2 10.2 5.6
The toString Method Consider the following String x = abc ; int y = 5; Circle z = new Circle(5.1); System.out.println(x + + y + + z); As we ve seen, the println statement can output the values of variables the above outputs abc and 5 as we expect but what is output for z? we get something that looks like garbage like Circle@15db9742 the latter part of the output is the address of z represented in hexadecimal notation not a very useful output To output an object s instance data using println, we can provide a toString method this method returns a String of what we want output from the object there are three examples shown below public String toString() { return + radius; } public String toString() { return The radius is + radius; } public String toString() { return radius: + radius + \narea: + getArea() + \nperimeter: + getPerimeter(); }
Immutable Objects Consider the following String x = abc ; x.toUpperCase(); Remember that toUpperCase() returns a new String, it does not change x this is because Strings are immutable once created their contents cannot change Immutable classes are those in which, once the instance data are set, they cannot change we can create an immutable class by not having any mutators methods all methods will either be accessors or will return results but not change instance data values What if we write a method called capitalize and pass it x? See the code below to the left will x change? only x in the method, the original x is still abc We could instead write capitalize2 in which case we can change x by doing x = capitalize2(x); (of course we can also just do x = x.toUpperCase();) public String capitalize2(String x) { return x.toUpperCase(); } public void capitalize(String x) { x = x.toUpperCase(); }
Arrays of Objects Just as we can have arrays of primitive types, we can have arrays of objects Circle[] circleArray = new Circle[100]; Notice that while circleArray is an array of 100 Circles, none of the individual Circle elements have been instantiated for(int i=0;i<100;i++) circleArray[i] = new Circle(); The two instantiations above differ new Circle[100]; - creates the array new Circle(); - creates a single Circle can we combine the two? sort of, if we want to omit new Circle[100]; in place of initializing the array Circle[] circleArray = {new Circle(), new Circle(), new Circle(), , new Circle()}; Remember that circleArray is an array, to access one Circle, index into it circleArray[0] is a Circle to access the Circle, we pass it messages so we might have circleArray[0].getRadius(); or circleArray[1].getArea();
Using the Array of Objects We will use an array of objects often to store a group of individual items and perform mass operations on all items in this way, the collection of objects is somewhat like a database where I could search for all objects that fulfill some criteria For instance, consider a Student class (to store for a Student his/her name, major, GPA, number of hours earned, etc) Now I create an array of Student objects each individual array element is one Student in my class I can search for all Students in my class that are CSC majors or have GPAs > 3 for(int i=0;i<students.length;i++) if(students[i].getMajor.equals( CSC )) System.out.println(students[i].getName()); I can sort the Students by last name or major or GPA or hours earned See the Student and StudentsUser classes on the website
Common Errors and Pitfalls Not defining a constructor although not an error, it is bad programming Placing a return type in the constructor s header (often void) remember constructors do not have return types at all Using the wrong visibility modifier making instance data public, methods private that should be part of the interface, or omitting the visibility modifier and thus giving the item package interface Not providing an adequate interface for your class (for instance, not have accessors or mutators that might be needed) Forgetting to test an object for null and getting NullPointerExceptions Defining your own class whose name is already in use as a built-in or imported Java class (e.g., Date) Adding a main method to a class (generally we only do this for user classes) Declaring an array of objects but either not instantiating the array or instantiating the array but not instantiating the individual objects Although not an error, this is a waste of time: recompiling your user class after you make changes to a class which the user class uses (e.g., after changing Circle and compiling it, you compile CircleUser even though you made no changes to it)