Visibility and static-ness

Download Report

Transcript Visibility and static-ness

Visibilities and Static-ness
Aaron Bloomfield
CS 101-E
Our Circle class
We are going to write a Circle class
Somebody else is going to use it
public class Circle {
double radius;
double Pi = 3.1415926536;
}
We’re ignoring the
public for now
Note the fields
are not static
Note the radius
field is not initialized
Remember that a
variable of a class
is called a field
Using our Circle class
Note it’s a different class
public class CircleTest {
public static void main (String[] args) {
int x = 5;
Circle c = new Circle();
}
Remember that a
}
variable of a method is
just called a variable
c is the object
Note the new
Circle is the class
Accessing our Circle object
Any field or method in an object can be
accessed by using a period
– Example: System.in
– Example: c.radius = 10;
– Example: c.Pi = 4;
This is bad – Pi should
have been declared final
(this will be done later)
What’s the output?
public class Circle {
double radius;
double Pi = 3.1415926536;
}
public class CircleTest {
public static void main (String[] args) {
int x;
Circle c = new Circle();
Java will give a
System.out.println (x);
“variable not
}
initialized” error
}
What’s the output now?
public class Circle {
double radius;
double Pi = 3.1415926536;
}
public class CircleTest {
public static void main (String[] args) {
int x;
Circle c = new Circle();
System.out.println (c.radius);
}
}
Java outputs 0.0!
What’s going on?
A (method) variable needs to be initialized
before it is used
A field (class variable) is automatically
initialized by Java
– All doubles are initialized to 0.0, ints to 0, etc.
This is a bit counter-intuitive…
What happens in memory
Consider: Circle c = new Circle()
A double takes up 8 bytes in memory
Thus, a Circle object takes up 16 bytes of
memory
– As it contains two doubles
Circle c
radius = 0.0
Pi = 3.1415926536
Consider the following code
public class CircleTest {
public static void main (String[] args) {
Circle c1 = new Circle();
Circle c2 = new Circle();
Circle c3 = new Circle();
Circle c4 = new Circle();
}
}
What happens in memory
There are 4 Circle objects in memory
– Taking up a total of 4*16 = 64 bytes of
memory
Circle c1
Circle c2
Circle c3
Circle c4
radius = 0.0
radius = 0.0
radius = 0.0
radius = 0.0
Pi = 3.1415926536
Pi = 3.1415926536
Pi = 3.1415926536
Pi = 3.1415926536
Consider the following code
public class CircleTest {
public static void main (String[] args) {
Circle c1 = new Circle();
//...
Circle c1000000 = new Circle();
}
}
This program creates 1 million Circle objects!
What happens in memory
There are 1 million Circle objects in
memory
– Taking up a total of 1,000,000*16 = 16 Mb of
memory
Circle c1
Circle c2
radius = 0.0
radius = 0.0
Pi = 3.1415926536
Pi = 3.1415926536
…
Circle c1000000
radius = 0.0
Pi = 3.1415926536
Note that the final Pi field is repeated 1 million times
The use of static for fields
If a field is static, then there is only
ONE of that field for ALL the objects
16
(1+1=2 doubles)
Total memory
Totalusage:
memory
8 Mb
usage:
+ 8 40
bytes
bytes
(1,000,000+1=1,000,001
(4+1=5
doubles)
…
Circle c1
Circle c2
Circle c Circle c3
radius = 0.0
radius = 0.0
radius = 0.0
radius = 0.0
Pi Pi
= 3.1415926536
= 3.1415926536
Circle
c1000000
Circle
c4
radius = 0.0
More on static fields
What does the following print
– Note that Pi is not final
Circle c1 = new Circle();
Circle c2 = new Circle();
Circle c3 = new Circle();
Circle c4 = new Circle();
c1.Pi = 4.3;
System.out.println (c2.Pi);
Note you can refer
to static fields by
object.field
Even more on static fields
There is only one copy of a static field
no matter how many objects are declared
in memory
– Even if there are zero objects declared!
– The one field is “common” to all the objects
Thus, you can refer to a static field by
using the class name:
– Circle.Pi
Even even more on static fields
This program also prints 4.3:
Circle c1 = new Circle();
Circle c2 = new Circle();
Circle c3 = new Circle();
Circle c4 = new Circle();
Circle.Pi = 4.3;
System.out.println (c2.Pi);
Even even even more on static
fields
We’ve seen static fields used with their
class names:
– System.in
– System.out
– Math.PI
– Integer.MAX_VALUE
(type: InputStream)
(type: OutputStream)
(type: double)
(type: int)
Non-static fields are generally not called
dynamic fields
– Just “non-static”, or no qualifier at all
A bit of humor…
Back to our Circle class
public class Circle {
double radius;
final static double Pi = 3.1415926536;
}
Note that Pi is now final and static
But it doesn’t do much!
Adding a method
public class Circle {
double radius;
final static double Pi = 3.1415926536;
double computeArea () {
return Pi*radius*radius;
}
}
Note that a (non-static) method can use all the fields
Using that method
public class CircleTest {
public static void main (String[] args) {
Circle c = new Circle();
c.radius = 2.0;
System.out.println (c.computeArea());
}
}
Prints 12.566370614356
Adding another method
double oneOverRadius() {
return 1.0/radius;
}
I couldn’t think of a good reason to divide something
by the radius…
What happens now?
Code in class CircleTest’s main() method
Circle c = new Circle(); // c.radius = 0.0
System.out.println (c.oneOverRadius());
Java won’t crash, but many other programming
languages (C and C++, especially) will
Java prints “Infinity”
– Not what we wanted, though!
One way to fix this…
Note that the radius field
is now initialized to 1.0
public class Circle {
double radius = 1.0;
final static double Pi = 3.1415926536;
double computeArea () {
return Pi*radius*radius;
}
double oneOverRadius() {
return 1.0/radius;
}
}
Back to our program…
This code will now run properly:
Circle c = new Circle(); // c.radius = 1.0
System.out.println (c.oneOverRadius());
But this code will “crash”:
Circle c = new Circle(); // c.radius = 1.0
c.radius = 0.0;
System.out.println (c.oneOverRadius());
Where the “crash” occurs
public class CircleTest {
public static void main
(String[] args) {
Circle c = new Circle();
// c.radius = 1.0
c.radius = 0.0;
System.out.println
(c.oneOverRadius());
}
}
Here is the badly written code
public class Circle {
double radius = 1.0;
final static double Pi =
3.1415926536;
double computeArea () {
return Pi*radius*radius;
}
double oneOverRadius() {
return 1.0/radius;
}
Here is where the “crash” occurs
Motivation for private fields
Problem: We do not want people using our
Circle class to be able to modify the fields on
their own
Solution: Don’t allow other code to modify the
radius field
– Give it private visibility
private means that only code within the class can
modify the field
One way to fix this…
Note that the radius field
is now private
public class Circle {
private double radius = 1.0;
final static double Pi = 3.1415926536;
double computeArea () {
return Pi*radius*radius;
}
double oneOverRadius() {
return 1.0/radius;
}
}
Back to our program…
This code will now not compile:
Circle c = new Circle(); // c.radius = 1.0
c.radius = 0.0;
System.out.println (c.oneOverRadius());
Java will give a compile-time error:
– radius has private access in Circle
Back to our program…
This code will also not compile:
Circle c = new Circle(); // c.radius = 1.0
System.out.println (c.radius);
Java will give the same compile-time error:
– radius has private access in Circle
The problem now…
But now you can’t have a Circle with a radius
other than 1.0!
Solution: Use a get/set methods in Circle:
void setRadius (double r) {
radius = r;
}
double getRadius () {
return radius;
}
Our Circle class so far
public class Circle {
double radius = 1.0;
final static double Pi = 3.1415926536;
double computeArea () {
return Pi*radius*radius;
}
double oneOverRadius() {
return 1.0/radius;
}
void setRadius (double r) {
radius = r;
}
double getRadius () {
return radius;
}
}
Using the get/set methods
public class CircleTest {
public static void main
(String[] args) {
public class Circle {
private double radius = 1.0;
final static double Pi = 3.14159
double computeArea () {
return Pi*radius*radius;
}
Circle c = new Circle();
c.setRadius (1.0);
double oneOverRadius() {
return 1.0/radius;
}
System.out.println
(c.computeArea());
void setRadius (double r) {
radius = r;
}
System.out.println
(c.getRadius());
double getRadius () {
return radius;
}
}
}
Here a method is invoked
}
Here the change to radius occurs
Wait! Another problem!
public class CircleTest {
public static void main (String[] args) {
Circle c = new Circle();
c.setRadius (0.0);
Here is the problem now…
System.out.println (c.oneOverRadius());
}
}
This problem is easily fixed
Change the setRadius method to the
following
void setRadius (double r) {
if ( r > 0.0 )
radius = r;
}
Now there is no way for code outside the
Circle class to change the radius to zero
Visibilities in Java
There are four visibilities:
– private: Only code within the same class can
access the field or method
Note: “access” means reading or writing the field, or invoking
the method
– public: Any code, anywhere, can access the field or
method
– protected: Used with inheritance
We won’t get to that this semester
– package: Almost the same as public
This is the default
Note that it can’t be specified like the others
A few notes on visibilities
You can NOT specify visibilities for method
variables
– Any method variable can only be accessed
within that method
Think of it as public within the method (after it’s
defined) and private outside the method
You can also specify
methods and classes
visibilities
for
– More on that later in the course (or next
course)
Constructors
When you create a object, you often have
to do some initialization
– You have to “construct” the object
public class Circle {
Note the different method declaration
String name;
public Circle() {
Scanner scanner = new Scanner(System.in);
System.out.println (“Enter the Circle’s name:”);
name = scanner.next();
}
//...
}
Constructors, take 2
Now when a Circle is created:
Circle c = new Circle();
Java will ask for the Circle’s name, and put
it in the name field
Okay, so this isn’t the greatest example…
Constructors, take 3
More useful constructors for our Circle
class:
Note there is no return
type for constructors
public Circle() {
radius = 1.0;
}
public Circle (double r) {
radius = r;
}
Note that the constructor
name is the EXACT same
as the class name
Note that there are two “methods” with the same name!
Overriding methods (and
constructors)
Consider the following code:
Circle c1 = new Circle ();
Circle c2 = new Circle (2.0);
Creates a Circle
of radius 1.0
Creates a Circle
of radius 2.0
Java knows which constructor to call by
the list of parameters
– This is called “overloading”
Overriding methods (and
constructors), take 2
The following Circle constructors would
not be allowed:
– We are assuming Pi is not final for this
example
public Circle() {
radius = 1.0;
}
public Circle (double r) {
radius = r;
}
public Circle (double p) {
Pi = p;
}
When Circle(1.0)
is called, which
one is meant?
Constructors, take 4
Our second constructor has a problem:
public Circle (double r) {
radius = r;
}
Consider the following code:
Circle c = new Circle (0.0);
System.out.println (c.oneOverRadius());
The method is dividing 1 by zero (again)
Constructors, take 5
Our revised constructors:
public Circle() {
radius = 1.0;
}
public Circle (double r) {
if ( r <= 0.0 )
radius = 1.0;
else
radius = r;
}
A bit of humor…
Back to the static discussion
Remember that there is one (and only
one) static Pi field, regardless of how
many objects are declared
Consider the following method:
double getPi() {
return Pi;
}
The getPi() method
It doesn’t read or modify the “state” of any
object
– In this example, it doesn’t read/write the
radius
In fact, that particular method doesn’t care
anything about the objects declared
– It’s only accessing a static field
Make getPi() static
Consider the following:
static double getPi() {
return Pi;
}
As the method is static, it can ONLY
access static fields
A static method does not care about the
“state” of an object
– Examples: Math.sin(), Math.tan(), Math.cos()
They don’t care about the state of the Math class
They only perform the computation
Invoking static methods
As with static fields, they can be called
using either an object or the class name:
Circle c = new Circle();
System.out.println (c.getPi());
System.out.println (Circle.getPi());
static methods and nonstatic fields
Consider the following (illegal) Circle
method:
static double getRadius() {
return radius;
}
And the code to invoke it:
public static void main (String[] args) {
Circle c1 = new Circle();
Circle c2 = new Circle();
Circle c3 = new Circle();
Circle c4 = new Circle();
System.out.println (Circle.getRadius());
}
What happening in memory
There are no
1
Circleobjects
Circle
objects
objects
memory
in memory
4 million
Circle
ininmemory
Which radius field does Circle.getRadius()
want?
Circle c1
Circle c2
radius = 0.0
radius = 0.0
…
Circle c3
radius = 0.0
Pi = 3.1415926536
Circle
c1000000
Circle
c4
radius = 0.0
The main static lesson
A static method cannot access or
modify the state of the object
static and non-static rules
Non-static fields and methods can ONLY
be accessed by the object name
Static fields and methods can be accessed
by Either the class name or the object
name
Non-static methods can refer to BOTH
static and non-static fields
Static methods can ONLY access static
fields
Back to our main() method
public static void main (String[] args)
The method does not return a value
Any code anywhere
can call this method
It’s a static method:
•Can’t access non-static fields
•Can be called only by the class name
A bit of humor…