Class and instance #
A class can be viewed as a blueprint for a set of similar objects.
For instance, consider the two objects:
{
name: "Florence",
zipCode: 50100,
region: "Tuscany"
}
{
name: "Rome",
zipCode: 00100,
region: "Lazio"
}
Each of these objects describes a city, and they share the same keys (name
, zipCode
and region
).
A possible class for these two objects may enforce this structure, and it could be named City
.
An object that follows this blueprint is called an instance of this class.
Declaration #
In a typed language (like Java), a class must specify not only the “keys” of its instances, but also their types.
For instance, the class City
could be declared as follows in Java:
public class City {
String name;
int zipCode;
String region;
...
}
In Java, a class is often declared in a dedicated file. This file must have the same name as the class (e.g.
City.java
in this example).
The three variables (name
, zipCode
and region
) are called attributes (or sometimes member variables).
Constructor #
A class also needs a special method called a constructor.
The constructor is in charge of creating a (fresh) instance of the class.
Note. A class may have several constructors (with different signatures).
Writing a constructor in Java #
The constructor of a Java class must have the same name as the class.
For instance:
public class City {
String name;
int zipCode;
String region;
public City(String n, int z, String r){
name = n;
zipCode = z;
region = r;
}
...
}
Note. In this example, the variable names
n
,z
andr
are not very explicit. However, usingname
,zipCode
andregion
would be ambiguous (because these names are already used for the attributes of the class). In Java, we can use the prefixthis.
to refer to attribute names, thus eliminating the ambiguity.For instance:
public class City { String name; int zipCode; String region; public City(String name, int zipCode, String region){ this.name = name; this.zipCode = zipCode; this.region = region; } ... }
Calling a constructor in Java #
A Java constructor is called with the keyword new
.
For instance:
City myCity = new City("Florence", 50100, "Tuscany");
City yourCity = new City("Rome", 00100, "Lazio");
Warning. In Java (as in Python, C#, etc.), the constructor does not return the instance itself, but a reference (sometimes called “pointer”) to this instance.
Note. The object that is created in memory contains extra information, in particular a reference to its class. This allows type checking, casts, etc. (more on this later).
Default constructor #
If a class has no explicit constructor, then a default constructor is generated by the compiler. This constructor has no argument.
Example. The following class has no constructor:
public class GhostTown { String name; }
But an instance can nonetheless be created with the default constructor:
GhostTown anonymousCity = new GhostTown();
Accessing an object in Java #
The attributes of an object can be accessed like regular variables, using .
, followed by the name of the attribute.
For instance,
City thatCity = new City("Siena", 53100, "Lazio");
System.out.println("Wrong region: " + thatCity.region);
thatCity.region = "Tuscany";
System.out.println("Better now: " + thatCity.region);
will output
Wrong region: Lazio
Better now: Tuscany
Reference type vs primitive type #
Recall that a Java constructor returns a reference to the object that it creates.
So in the examples above, the value of each variable (myCity
, yourCity
and thatCity
) is a reference, not the object itself.
This also holds for variable with an array type (like int[] myArray
).
The types of these variables (e.g. City
or int[]
) are called reference types.
Syntax. In Java, types that start with a capital letter (like
City
orSet<Integer>
) are usually reference types.
Types that are not references types (like int
or char
) are called primitive types.
In Java, the value of a reference cannot be output (printed, displayed, etc.) by a program (as opposed to C/C++ for instance). But this value can be overwritten or compared to another.
What is the output of the following program?
City aCity = new City("Matera", 75100, "Basilicata");
City theSameCity = new City("Matera", 75100, "Basilicata");
System.out.println(aCity == theSameCity);
System.out.println(aCity.zipCode == theSameCity.zipCode);
false
true
What is the output of the following program?
City anotherCity = new City("Bologna", 40100, "Emilia-Romagna");
City yetAnotherCity = new City("Mantua", 46100, "Emilia-Romagna");
yetAnotherCity.name = anotherCity.name;
System.out.println(yetAnotherCity.name);
anotherCity = yetAnotherCity;
System.out.println(anotherCity.zipCode);
System.out.println(anotherCity == yetAnotherCity);
"Bologna"
46100
true
Passing by value or by reference #
Programming languages differ in the way arguments are passed to methods. Two common strategies are:
- passing by value: the method receives as input a copy of each argument,
- passing by reference: the method receives as input a reference to each argument (which allows the method to modify the initial argument).
Consider for instance the following program (in pseudocode):
int myInteger = 0
myMethod(myInteger)
print(myInteger)
void myMethod(int argument){
argument += 1
}
- If the argument is passed by value, then the program will print
0
. - If the argument is passed by reference, then the program will print
1
.
Java passes by value #
In Java (and many other programming languages, like C, Python, Javascript, etc.), arguments are passed by value.
So the above program translated in Java will print 0
.
Warning. Consider a method with a reference type argument. Because Java passes by value, this method will receive a copy of this argument. But this is a copy of the reference, not a copy of the object itself.
What does the following Java program print?
int myInteger = 0;
City myFirstCity = new City("Florence", 50100, "Tuscany");
City mySecondCity = new City("Mantua", 46100, "Emilia-Romagna");
myMethod(myInteger, myFirstCity, mySecondCity);
System.out.println(myInteger);
System.out.println(myFirstCity.zipCode);
System.out.println(mySecondCity.zipCode);
public void myMethod(int integer, City firstCity, City secondCity){
integer += 1;
System.out.println(integer);
firstCity.zipCode = 20590;
System.out.println(firstCity.zipCode);
secondCity = new City("Rome", 00100, "Lazio");
System.out.println(secondCity.zipCode);
}
1
20590
00100
0
20590
46100