Introduction to Software Development
GWU Computer Science
By the end of this module, you will be able to:
In the last lecture, we discussed how Java handles memory and scope between variables, methods, and fields (variables declared in a class outside of a method). In this lecture, we'll (finally!) go over classes and show how fields are used to represent object state.
We have been defining lots of classes all semester -- in fact, to be able to run
any code in Java, we need a main
method inside of some arbitrary
class! However, we were never really using classes so far for their intended purpose:
to group related information about some user-defined type (the class) in one place,
so that we can operate on that data.
So what is a class? What is an object? You can think of a class as the instructions or blueprint for what we want to store:
What are classes?
String
. Someone has written and defined the String
class, so we now know that each String
stores a list of characters, and
we can call various methods of the String
class on this list of characters,
as we've seen in our exercises so far.So, what are objects?
String lastName = "Mukherjee";
creates the object called
lastName
, which lives somewhere in memory, to be of type String
.
The lastName
object stores the value "Mukherjee" at runtime.Classes are frequently used to collect and store data of real-world concepts, entities, and objects. For example, take the example of the Facebook user class:
public class FacebookUser {
public long userId = 1;
public String firstName,
public String lastName;
public FacebookUser[] friends;
public boolean checkIsFriend(FacebookUser person){
for(int i = 0; i < friends.length; i++)
if(friends[i].equals(person))
return true;
return false;
}
public long getId(){
return userId;
}
public void setId(long idIn){
userId = idIn;
}
//more methods would go below
}
The class gives the blueprint for each object:
What function do objects provide compared to variables, arrays, etc? How do they relate to static variables stored in classes?
Multiple objects exist, each with possibly different sets of data. Objects are allocated with new .
public static void main(String[] args) {
FacebookUser user1 = new FacebookUser();
FacebookUser user2 = new FacebookUser();
user1.setId(5);
System.out.println(user1.userId + " " + user2.getId());
}
If a class gives the blueprint to create objects, constructors lay the initial foundation for each object.
Constructors are methods that are invoked when a new object is created that are used to initialize the data of the new object.
FacebookUser u = new FacebookUser();
new FacebookUser();
invokes the constructor
on the newly created object.
The constructor can be overloaded just like any other method:
FacebookUser u = new FacebookUser("chester", "thecat");
What does a constructor look like? An example:
public class FacebookUser {
private long userId;
private String firstName, lastName;
private FBUser[] friends;
public FacebookUser() {
// initialize object's data here
}
public FacebookUser(String first, String last) {
firstName = first;
lastName = last;
}
public void setId(long id) {
userId = id;
}
public long getId() {
return userId;
}
}
Earlier we saw that we don't have to write a constructor to use one that has no arguments; Java gives you this "for free." Such a constructor will assign all fields their default values (or use how these attributes were initialized). If you start to write your own constructor(s) as above, you will lose the default constructor -- Java's expectation is you know what you're doing and need something more specific than the default behavior.
As we saw above (and earlier with Strings
), methods in a class can operate on an object using the dot
notation. If var is a variable
referring to an object,
var.methodName();
invokes the methodName method on var's object.
Read this as "we're invoking the methodName method of the var object"
When an object is allocated with new, e.g.:
A var = new A();
A reference to the new object's memory is returned.
The variable (var here) is set to this reference.
This should feel familiar -- its the same as with arrays.
The type of the variable is the name of the class:
A var = new A();
The variable itself:
A var = new A();
A slightly more complicated example:
FacebookUser var1 = new FacebookUser();
FacebookUser var2 = var1;
var2.setId(10);
System.out.println(var1.getId());
Finally, create four FacebookUser objects in FBUserTest, initiallize them all, and populate their friend lists.
public
versus private
visibilityYou might be wondering why bother having getters and setters, when we can access the field directly,
as we did above with user1.userId
? It turns out that, as good software engineers, we
actually want to avoid having people write code like this that allows field access directly, for
reasons we will see later this semester.
In Java, we can control what code that is outside of a class is able to see/use. For example,
because we defined userId
to be public
, this meant that anyone can access
the field from the object directly with user1.userId
. However, we're going to stop this for
now, and you'll see almost all examples set fields to private
visibility, which doesn't
allow this type of access; this is why we're writing getters and setters. Later, we'll see examples of
where it makes sense (and good software engineering sense) to use the public
visibility.
Note that, so far, all of our methods have public
visibility; this will often be the case.
You can also specify private
methods, which means only other methods in the same class
can call them.
We'll run though some examples in a bit. For now, let's get used to the proper idioim of keeping our
fields private
, writing getters and setters, and having methods be public
.
Another example:
public class ObjExample {
private int data;
public void modify(int v) {
data = v;
}
public int access() {
return data;
}
public void addData(ObjExample o) {
data += o.access();
}
public static void main(String[] args) {
ObjExample v1 = new ObjExample();
ObjExample v2 = v1;
v2.modify(10);
System.out.println(v1.access());
ObjExample v3 = new ObjExample();
v3.modify(3);
v3.addData(v2);
System.out.println(v3.access());
v3.addData(v3); // what's happening here?
v1.addData(v2); // ...and here?
}
}
What are the last two lines doing? Describe them
static
?We can now better understand the static keyword, given that we know what a class and objects are now.
The static
keyword is used to indicate when a field is meant to be
shared amongst all objects of a class, as opposed to each objects having its own
values for that field:
static
data is
shared between all objects of a class. It's like a team name, shared by all players.
static
methods are not associated
with any specific object, thus none of the non-static (object) data can
be directly accessed within one. These methods can access and
modify comparably static
data in the
class.
Non-static
(object) data has a separate
copy for each object.
Non-static
(class) methods can access the
non-static
(object) data in the
class. They access and modify versions of that data specific
to the current object.
A static
method can only access the
static
fields in the
class. This is why you have seen mostly static
fields defined this semester,
as they were being passed to main
, which is also a static
method.
public class StaticExample {
private static int staticVar;
private int objectVar;
public static void staticSetVar(int val) {
staticVar = val;
}
public static int staticGetVar() {
return staticVar;
}
public void objSetVar(int val) {
objectVar = val;
}
public int objGetVar() {
return objectVar;
}
}
public class TestStaticExample {
public static void main(String[] args) {
StaticExample.staticSetVar();
System.out.println ( StaticExample.staticGetVar() );
StaticExample ob1 = new StaticExample();
ob1.objSetVar();
System.out.println ( ob1.objGetVar() );
}
}
public class StaticExample2 {
private static int staticVar;
private int objectVar;
public void objSetVars() {
objectVar = 10;
staticSetVars();
}
public int[] objGetVars() {
return new int[]{staticvar, objectVar};
}
public static void staticSetVars() {
staticVar = 10;
objSetVars();
}
public static int[] staticGetVars() {
return new int[]{staticvar, objectVar};
}
public static void main(String[] args) {
staticSetVars();
objSetVars();
StaticExample v = new StaticExample();
v.staticSetVars();
v.objSetVars();
}
}
null
is a valid value for a variable of
any non-primitive type. This includes:
objects
arrays
Strings
null
is simply a reference to nothing; you can think of it
as a reference to a "nothing memory address".
null
is often used to denote "there is
no valid object".
It is sometimes returned when an object is expected to denote an error.
Example: What if you try and lookup a facebook user that
doesn't exist -- FacebookUser findUser(String first, String
last)
?
public class NullTest {
private int n;
public int getN() {
return n;
}
public static void main(String[] args) {
NullTest nt = null;
System.out.println(nt.getN());
}
}
FBUser u;
Where is the problem in the following code?
public class FacebookUser {
private long userId;
private String firstName, lastName;
private FacebookUser[] friends;
public FacebookUser(String firstName, String lastName) {
// uh oh...
}
public void setId(long id) {
userId = id;
}
public long getId() {
return userId;
}
}
public class FacebookUser {
private long userId;
private String firstName, lastName;
private FacebookUser[] friends;
public FacebookUser(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public void setId(long id) {
userId = id;
}
public long getId() {
return userId;
}
}
this
is a new keyword that denotes
"the current object".this
.firstName references the
object's firstName
variable, not the
method argument, or a local variable.this
is the type
of the object: FacebookUser
, in this case.
this
is, generically, a variable that
references the "current" object.
Why does Object-Oriented Programming (OOP) exist?
Why is it useful? Why use OOP instead of making all code and data static?
Come up with two examples where it has utility.
Code written for one situation should be, within reason, reusable in other situations
Writing fairly generic classes enables this.
It is important to design your classes before writing your code. I've been doing this for you in homeworks.