week5 - Andrew.cmu.edu - Carnegie Mellon University
Download
Report
Transcript week5 - Andrew.cmu.edu - Carnegie Mellon University
Initialization and Cloning
Slides adapted from course text
“Thinking in Java” Bruce Eckel
Carnegie Mellon University,
Graduate School of Industrial
1
Guaranteed Initialization with the Constructor
class Rock {
Rock() {
System. out. println(" Creating Rock");
}
}
public class SimpleConstructor {
public static void main( String args[]) {
for( int i = 0; i < 10; i++)
new Rock();
}
Carnegie Mellon University,
Graduate School of Industrial
2
Method Overloading
class Tree {
int height;
Tree() {
prt(" Planting a seedling");
height = 0;
}
Tree( int i) {
prt(" Creating new Tree that is "+ i
+ " feet tall");
height = i;
}
Carnegie Mellon University,
Graduate School of Industrial
3
void info() {
prt(" Tree is " + height
+ " feet tall");
}
void info( String s) {
prt( s + ": Tree is "
+ height + " feet tall");
}
static void prt( String s) {
System. out. println( s);
}
}
Carnegie Mellon University,
Graduate School of Industrial
4
public class Overloading {
static Random rand = new Random();
static int pRand( int mod) {
return Math. abs( rand. nextInt()) % mod;
}
public static void main( String args[]) {
Carnegie Mellon University,
Graduate School of Industrial
5
int i = 0;
while( i != 9) {
Tree t = new Tree( i = pRand( 10));
t. info();
t. info(" overloaded method");
}
// Overloaded constructor:
new Tree();
}
Carnegie Mellon University,
Graduate School of Industrial
6
Default Constructor: Takes no Arguments
• Compiler creates one for you if you write
exactly 0 constructors
class Bird {
int i;
}
public class DefaultConstructor {
public static void main( String args[]) {
Bird nc = new Bird(); // default!
}
}
Carnegie Mellon University,
Graduate School of Industrial
7
this: Handle to Current Object
public class Leaf {
private int i = 0;
Leaf increment() {
i++;
return this;
// return handle to
// current object
}
Carnegie Mellon University,
Graduate School of Industrial
8
void print() {
System. out. println(" i = " + i);
}
public static void main( String args[]) {
Leaf x = new Leaf();
x. increment(). increment(). increment(). print();
}
Carnegie Mellon University,
Graduate School of Industrial
9
this: Calling Constructors from Constructors
this: To clear up ambiguity
class Flower {
String s;
Flower( int i) { /* ... */ }
Flower( String s) { /* ... */ }
Flower( String s, int x) {
this( x);
// if done, must be done first!
//! this( s); // Can't call two!
this. s = s; // Another use of "this"
System. out. println(" String & int args");
}
// ...
Carnegie Mellon University,
Graduate School of Industrial
10
Member Initialization
void f() {
int i; // No initialization
i++;
}
• Produces compile- time error
• Inside class, primitives are given default
values if you don’t specify values
Carnegie Mellon University,
Graduate School of Industrial
11
class Data {
int i = 999;
long l; // defaults to zero
// ...
Carnegie Mellon University,
Graduate School of Industrial
12
Constructor Initialization
• Order of initialization
– Order that variables/ objects are defined
in class
• Static data initialization
class Cupboard {
Bowl b3 = new Bowl( 3);
static Bowl b4 = new Bowl( 4);
Carnegie Mellon University,
Graduate School of Industrial
13
// ...
– b4 only created on first access or when first object of
class Cupboard is created
It’s helpful to summarize the process of creating an object.
Consider a class called Dog:
1. The first time an object of type Dog is created, or the
first time a static method or static field of class Dog is
accessed, the Java interpreter must locate Dog.class, which
it does by searching through the classpath.
Carnegie Mellon University,
Graduate School of Industrial
14
2. As Dog.class is loaded (which creates a Class object,
which
You’ll learn about later), all of its static initializers are
Run. Thus, static initialization takes place only once,
as the Class object is loaded for the first time.
3. When you create new Dog(), the construction process for
a
Dog object first allocates enough storage for a Dog object
on the heap.
4. This storage is wiped to zero, automatically setting all
The primitives in Dog to their default values (zero for
numbers and the equivalent for boolean and char).
Carnegie Mellon University,
Graduate School of Industrial
15
5. Any initializations that occur at the point of
field definition are executed.
6. Constructors are executed.
Assignment and Aliasing
Assignment of primitives is as you would expect.
If c and d are handles then c=d sets c to refer
to the same object as d. This is called aliasing.
Carnegie Mellon University,
Graduate School of Industrial
16
Aliasing will also occur when you pass an object into a
method.
Example:
Sometype p=new Sometype();
Sometype h=p;
System.out.println(h+ ”in”+p);
Carnegie Mellon University,
Graduate School of Industrial
17
Sometype@1653748
Sometype@1653748
The code above invokes object’s toString().
Why?
Carnegie Mellon University,
Graduate School of Industrial
18
Aliasing Issues
• Aliasing happens automatically during
argument passing
• There are no local objects, only local
handles
• Handles have scopes, objects do not
• Object lifetime is never an issue
• There is no language support to prevent
objects from being modified (to prevent
negative effects of aliasing)
Carnegie Mellon University,
Graduate School of Industrial
19
Passing Handles
• All arguments are passed as handles
• You never pass the object itself
• Very efficient if
– You’re only reading the object
– You want to modify the outside object
• Sometimes it’s necessary to create a “local”
– Changes only affect the local object, not the
outside object
– Java doesn’t support this directly, but
provides
“cloning”
Carnegie Mellon University,
Graduate School of Industrial
20
Making Local Copies
In general, you call a method in order to produce a return
value and/or a change of state in the object that the method
is called for.
It is much less common to call a method in order to
manipulate its arguments; this is referred to a “calling a
method for its side effects”.
If you need to modify an argument during a method call
And don’t intend to modify the outside argument, then you
Should protect that argument by making a copy inside your
method.
Carnegie Mellon University,
Graduate School of Industrial
21
Cloning Objects
• To produce pass- by- value effect, explicitly
clone the object that’s passed to you
void f( Sheep x) {
x = (Sheep) x. clone();
// Now we have a local sheep object
// Any changes to x are private changes
}
Carnegie Mellon University,
Graduate School of Industrial
22
// A simple Int class
class Int {
private int i;
public Int( int i) { this. i = i; }
public void increment() { i++; }
public String toString() {
return Integer.toString( i);
}
}
Carnegie Mellon University,
Graduate School of Industrial
23
public class Cloning {
public static void main( String args[]) {
Int v[] = new Int[10];
for( int i = 0; i < 10; i++ )
v[i] = new Int(i);
for(int i = 0; i < 10; i++)
System. out. print("v[" + i + "]=" + v[i]+ " ");
System.out.println();
Int v2[] = (Int[]) v. clone();
Carnegie Mellon University,
Graduate School of Industrial
24
// Increment all v2's elements:
for(int i = 0; i < 10; i++)
v2[i].increment();
// See if it changed v's elements:
for(int i = 0; i < 10; i++)
System. out. print("v[" + i + "]=" + v[i]+ " ");
}
}
Carnegie Mellon University,
Graduate School of Industrial
25
Only A Shallow Clone Is Available for Arrays.
v[0]=0 v[1]=1 v[2]=2 v[3]=3 v[4]=4 v[5]=5 v[6]=6
v[7]=7 v[8]=8 v[9]=9
v[0]=1 v[1]=2 v[2]=3 v[3]=4 v[4]=5 v[5]=6 v[6]=7
v[7]=8 v[8]=9 v[9]=10
• Safest thing to do in this case: no guarantee that object
in array are cloneable
• If you create a new class you must write code to make
that class cloneable
• But why bother?
Carnegie Mellon University,
Graduate School of Industrial
26
// Forgetting to clone may break encapsulation
class BankAccount {
private double balance;
public BankAccount() { balance = 0; }
public BankAccount(double initialBalance) { balance = initialBalance; }
public void deposit(double amount) { balance += amount; }
public void withdraw(double amount ) { balance = balance - amount; }
public double getBalance() { return balance; }
public String toString() { return Double.toString(balance); }
Carnegie Mellon University,
Graduate School of Industrial
27
class Customer {
private BankAccount account;
private String name;
public Customer(String aName) {
name = aName;
account = new BankAccount(0);
}
public String getName() {
return name;
}
Carnegie Mellon University,
Graduate School of Industrial
28
public BankAccount getAccount()
{
return account;
}
public void addToAccount(double amt) {
account.deposit(amt);
}
public String toString() {
return name + account;
}
Carnegie Mellon University,
Graduate School of Industrial
29
// Anyone can withdraw money!
public class CustomerTest {
public static void main(String args[]) {
Customer joe = new Customer("Joeseph Smith");
BankAccount sureItsPrivate = joe.getAccount();
joe.addToAccount(1000);
sureItsPrivate.withdraw(100);
System.out.println(joe);
}
}
Joeseph Smith900.0
Carnegie Mellon University,
Graduate School of Industrial
30
Adding Clonability to a class
• Object. clone( ) is protected so you can’t normally
access it
• Must override and make it public
• Must also implement the Cloneable interface
– A flag:
interface Cloneable {} // Empty!
– Allows you to check it:
if( myHandle instanceof Cloneable) // …
– Tested by Object. clone( )
• Virtually always call Object. clone( ) in your
new clone (via super. clone( ) )
Carnegie Mellon University,
Graduate School of Industrial
31
// Allow others to clone objects of class BankAccount
class BankAccount implements Cloneable {
private double balance;
public BankAccount() { balance = 0; }
public BankAccount(double initialBalance) { balance = initialBalance; }
public void deposit(double amount) { balance += amount; }
public void withdraw(double amount ) { balance = balance - amount; }
public double getBalance() { return balance; }
public String toString() { return Double.toString(balance); }
Carnegie Mellon University,
Graduate School of Industrial
32
public Object clone() {
try {
Object clonedAccount = super.clone();
return clonedAccount;
}
catch(CloneNotSupportedException e) {
// can't happen -- we implement cloneable
return null;
}
}
}
Carnegie Mellon University,
Graduate School of Industrial
33
class Customer {
private BankAccount account;
private String name;
public Customer(String aName) {
name = aName;
account = new BankAccount(0);
}
public String getName() {
return name;
}
Carnegie Mellon University,
Graduate School of Industrial
34
public BankAccount getAccount() {
return (BankAccount)account.clone();
}
public void addToAccount(double amt) {
account.deposit(amt);
}
public String toString() {
return name + account;
}
}
Carnegie Mellon University,
Graduate School of Industrial
35
// We can only review Joe's account.
// We can change it only through the proper interface.
public class CustomerTest {
public static void main(String args[]) {
Customer joe = new Customer("Joeseph Smith");
BankAccount sureItsPrivate = joe.getAccount();
joe.addToAccount(1000);
sureItsPrivate.withdraw(100);
System.out.println(joe);
}
}
Joeseph Smith1000.0
Carnegie Mellon University,
Graduate School of Industrial
36
The Effect of Object. clone( )
• Copies the bits for the exact object (not just the
root class Object)
• Should always be the first part of your cloning
process (via super. clone( ) )
• Copies the handle values, but not what they’re
pointing to (a shallow copy)
Carnegie Mellon University,
Graduate School of Industrial
37
• To perform a deep copy you must clone the contents
of the handles as well
• Once you make clone public, it remains public in derive
classes (the protected trick may only be used once).
Carnegie Mellon University,
Graduate School of Industrial
38
Be Careful when cloning a class with references.
•We can provide a clone method for the Customer
class.
•We have to remember to clone the account object.
Carnegie Mellon University,
Graduate School of Industrial
39
class Customer implements Cloneable {
private BankAccount account;
private String name;
public Customer(String aName) {
name = aName;
account = new BankAccount(0);
}
public String getName() {
return name;
}
Carnegie Mellon University,
Graduate School of Industrial
40
public BankAccount getAccount() {
return (BankAccount)account.clone();
}
public void addToAccount(double amt) {
account.deposit(amt);
}
public String toString() {
return name + "\t" + account;
}
Carnegie Mellon University,
Graduate School of Industrial
41
public Object clone() {
try {
Object clonedCustomer = super.clone();
((Customer)clonedCustomer).account =
(BankAccount)account.clone();
return clonedCustomer;
}
Carnegie Mellon University,
Graduate School of Industrial
42
catch(CloneNotSupportedException e)
{
// can't happen we implement
// cloneable
return null;
}
}
}
Carnegie Mellon University,
Graduate School of Industrial
43
public class CustomerTest2 {
public static void main(String args[]) {
Customer list[] = new Customer[3];
Customer list2[];
list[0] = new Customer("Mike");
list[1] = new Customer("Sue");
list[2] = new Customer("Bill");
list2 = (Customer[]) list.clone();
Carnegie Mellon University,
Graduate School of Industrial
44
for(int j = 0; j < 3; j++) {
list2[j] = (Customer) list[j].clone();
list2[j].addToAccount(100);
}
for (int j = 0; j < 3; j++)
System.out.print(list[j] + "\t");
System.out.println();
for (int j = 0; j < 3; j++)
System.out.print(list2[j] + "\t");
}
}
Carnegie Mellon University,
Graduate School of Industrial
45
Inserting Clonability in a derived class
class Person {}
class Hero extends Person {}
class Scientist extends Person implements
Cloneable {
public Object clone() {
try {
return super. clone();
} catch (CloneNotSupportedException e) {
Carnegie Mellon University,
Graduate School of Industrial
46
// This should never happen:
// It's Cloneable already!
throw new InternalError();
}
}
}
class MadScientist extends Scientist {}
Carnegie Mellon University,
Graduate School of Industrial
47
public class HorrorFlick {
public static void main( String args[]) {
Person p = new Person();
Hero h = new Hero();
Scientist s = new Scientist();
MadScientist m = new MadScientist();
// p = (Person) p. clone(); // Compile error
// h = (Hero) h. clone(); // Compile error
s = (Scientist) s. clone();
m = (MadScientist) m. clone();
}
Carnegie Mellon University,
Graduate School of Industrial
48
// Snake.java
public class Snake implements Cloneable {
private Snake next;
private char c;
// Value of i == number of segments
Snake(int i, char x) {
c = x;
if(--i > 0)
next = new Snake(i, (char)(x +1));
}
Carnegie Mellon University,
Graduate School of Industrial
49
void increment() {
c++;
if(next != null)
next.increment();
}
public String toString() {
String s = ":" + c;
if(next != null)
s += next.toString();
return s;
}
Carnegie Mellon University,
Graduate School of Industrial
50
public Object clone() {
Object o = null;
try {
o = super.clone();
} catch (CloneNotSupportedException e) {}
return o;
}
Carnegie Mellon University,
Graduate School of Industrial
51
public static void main(String[] args) {
Snake s = new Snake(5, 'a');
System.out.println("s = " + s);
Snake s2 = (Snake)s.clone();
System.out.println("s2 = " + s2);
s.increment();
System.out.println(
"after s.increment, s2 = " + s2);
}
}
Carnegie Mellon University,
Graduate School of Industrial
52
C:\McCarthy\eckelbook\source\c12>java Snake
s = :a:b:c:d:e
s2 = :a:b:c:d:e
after s.increment, s2 = :a:c:d:e:f
Carnegie Mellon University,
Graduate School of Industrial
53
Homework
Why doesn’t snake.java work properly?
What changes would you make to fix it?
Carnegie Mellon University,
Graduate School of Industrial
54