Thinking in Java

Chapter 5 Initialization & Clean

2018-10-06  本文已影响0人  綿綿_

Guaranteed initialization with the constructor

In Java, the class designer can guarantee initialization of every object by providing a constructor.
The name of the constructor is the same as the name of the class.

The constructor can also have arguments to allow you to specify how an object is created

In Java, creation and initialization are unified concepts—you can’t have one without the other

The constructor has no return value.

Method Overloading

Method overloading is essential to allow the same method name to be used with different argument types

Distinguishing overloaded methods

Each overloaded method must take a unique list of argument types.Even differences in the ordering of arguments are sufficient to distinguish two methods,

for example:

 static void f(String s, int i) { 
print("String: " + s + ", int: " + i);
}
 static void f(int i, String s) { 
print("int: " + i + ", String: " + s);
}

The two f( ) methods have identical arguments, but the order is different, and that’s what makes them distinct.

Overloading with primitives

If you have a data type that is smaller than the argument in the method, that data type is promoted

If your argument is wider, then you must perform a narrowing conversion with a cast. If you don’t do this, the compiler will issue an error message.

The this keyword

The this keyword—which can be used only inside a non-static method
it produces the reference to the object that the method has been called for.

If you’re calling a method of your class from within another method of your class, you don’t need to use this. You simply call the method. The current this reference is automatically used for the other method. Thus you can say:

public class Apricot { 
void pick() { /* ... */ } 
void pit() { pick(); /* ... */ }
 } ///:~

Inside pit( ), you could say this.pick( ) but there’s no need to.

The this keyword is used only for those special cases in which you need to explicitly use the reference to the current object. For example, it’s often used in return statements when you want to return the reference to the current object

Calling constructors from constructors

Normally, when you say this, it is in the sense of “this object” or “the current object,” and by itself it produces the reference to the current object. In a constructor, the this keyword makes an explicit call to the constructor that matches that argument list. Thus you have a straightforward way to call other constructors:

import static net.mindview.util.Print.*;
public class Flower {
int petalCount = 0; String s = "initial value";

Flower(int petals) { 
petalCount = petals;
print("Constructor w/ int arg only, petalCount= " + petalCount);
} 
Flower(String ss) {
print("Constructor w/ String arg only, s = " + ss); s = ss;
}
Flower(String s, int petals) { 
this(petals);
//! } Flower() { this("hi", 47);
print("default constructor (no args)"); 
void printPetalCount() {
}
//! this(11); // Not inside non-constructor! print("petalCount = " + petalCount + " s = "+ s);
}

The constructor Flower(String s, int petals) shows that, while you can call one constructor using this, you cannot call two. In addition, the constructor call must be the first thing you do, or you’ll get a compiler error message.

Cleanup: finalization and garbage collection

1. Your objects might not get garbage collected.
2. Garbage collection is not destruction.

You must perform cleanup

Java doesn’t allow you to create local objects—you must always use new .

Remember that neither garbage collection nor finalization is guaranteed.
If the JVM isn’t close to running out of memory, then it might not waste time recovering memory through garbage collection.

How a garbage collector works

The garbage collector can have a significant impact on increasing the speed of object creation.

A simple but slow garbage-collection technique is called reference counting. This means that each object contains a reference counter, and every time a reference is attached to that object, the reference count is increased. Every time a reference goes out of scope or is set to null, the reference count is decreased.Thus, managing reference counts is a small but constant overhead that happens throughout the lifetime of your program. The garbage collector moves through the entire list of objects, and when it finds one with a reference count of zero it releases that storage

Member initialization

When you define an object reference inside a class without initializing it to a new object, that reference is given a special value of null .

Constructor initialization

static data initialization

To summarize the process of creating an object, consider a class called Dog:

  1. Even though it doesn’t explicitly use the static keyword, the constructor is actually a static method. So 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.

  2. As Dog.class is loaded (creating a Class object), 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 a 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 that Dog object to their default values (zero for numbers and the equivalent for boolean and char) and the references to null.

  5. Any initializations that occur at the point of field definition are executed.

  6. Constructors are executed. As you shall see in the Reusing Classes chapter, this might actually involve a fair amount of activity, especially when inheritance is involved.

Enumerated types

A simple example:

public enum Spiciness {
NOT, MILD, MEDIUM, HOT, FLAMING 
} ///:~

This creates an enumerated type called Spiciness with five named values. Because the instances of enumerated types are constants, they are in all capital letters by convention (if there are multiple words in a name, they are separated by underscores).

To use an enum, you create a reference of that type and assign it to an instance:

public class SimpleEnumUse {
public static void main(String[] args) {
Spiciness howHot = Spiciness.MEDIUM; 
System.out.println(howHot);
}
} 
/* Output: MEDIUM *///:~

You can treat an enum as if it were any other class. In fact, enums are classes and have their own methods.

An especially nice feature is the way that enums can be used inside switch statements:

switch(degree) { 
case NOT:
System.out.println("not spicy aqt all"); 
break;
case MILD:
case MEDIUM:
System.out.println("a little hot."); 
break;
case HOT:
case FLAMING: 
default:System.out.println("maybe too hot.");
}
上一篇下一篇

猜你喜欢

热点阅读