标签:
Two of these safety issues are initialization and cleanup.
initialization -> bug
cleanup -> running out of resources (most notably, memory)
Java adopted the constructor, and in addition has a garbage collector that automoatically releases memory resources when they are no longer begin used.
In Java, the class designer can guarantee initialization of every object by providing a constructor.
Note that the coding style of making the first letter of all methods lowercase does not apply to constructors, since the name of the constructor must match the name of the class exactly.
A constructor that takes no arguments is called the default constructor ( Java documents use the term no-arg constructor)
Constructors eliminate a large class of problems and make the code easier to read.
In Java, creation and initialization are unified concepts--you can‘t have one without the other.
The constructor is an unusual type of method because it has no return type. This is distinctly different from a void return value, in which the method returns nothing but you still have the option to make it return something else. Constructors return nothing and you don‘t have an option ( the new expression does return a reference to the newly created object, but the constructor itself has no return value.)
You refer to all object and methods by using names.
Well-chosen names create a system that is easier for people to understand and change.
Often, the same word expresses a number of different meanings--it‘s overloaded.
You don‘t need unique identifiers--you can deduce meaning from context.
Most programming languages require you to have a unique identifier for each method. So you could not have one method called print() for printing integers and another called print() for printing floats--each method requires a unique name.
In Java, another factor forces the overloading of method names: the constructor. Because the constructor‘s name is predetermined by the name of the class, there can be only one constructor name
method overloading is essential to allow the same method name to be used with different argument types (or argument list).
How can Java know which method you mean? There‘s a simple rule: Each overloaded method must take a unique list of argument types
A primitive can be automatically promoted from a smaller type to a larger one, and this can be slightly confusing in combination with overloading.
If you have a data type that is smaller than the argument in the method, that data type is promoted
char produces a slightly different effect,since if it doesn‘t find an exact char match, it is promoted to int.
The methods take narrower primitive values. 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.
void f() {}
int f() { return 1;}
when you call a method and ignore the return value, how can Java determine which f() should be called?
If you create a class that has no constructors, the compiler will automatically create a default constructor for you
However, if you define any constructors (with or without arguments), the compiler will not synthesize one for you
a.peel(1);
b.peel(2);
If there‘s only one method called peel(), how can that method know whether it‘s being called for the the object a or b?
To allow you to write the code in a convenient object-oriented syntax in which you "send a message to an object," the compiler does som undercover work for you. There‘s a secret first argument passed to the method peel(), and that argument is the reference to the object that‘s being manipulated. So the two method calls become something like:
Banana.peel(a,1);
Banana.peel(b,2);
Suppose you‘re inside a method and you‘d like to get the reference to the current object. Since that reference is passed secretly by the compiler, there‘s no identifier for it. However, for this purpose there‘s a keyword: this.
The this keyword-which can be used only inside a non-static method
以下情况需要显示指定this:
return this;
peel(this);
this.code = code;
this(arg...);
In a contructor, the this keyword takes on a different meaning when you give it an argument list. It makes an explicit call to the constructor that matches that arugment list.
While you can call one constructor using this, you cannot call two.
The constructor call must be the first thing you do.
The constructor call can not from inside any method other than a constructor.
Static means that there is no this for that particular method.
static are not object-oriented. However, statics are pragmatic, and there are times when you genuinely need then,so whether or not they are "proper OOP" should be left to the theoreticians.
Now consider an unusual case: Suppose your object allocates "special" memory without using new. The garbage collector only know how to release memory allocated with new, so it won‘t know how to release the objects‘s "special" memory.
To handle this case, Java provides a method called finalize() that you can define for your class.
When the garbage collector is ready to release the storage used for you object, it will first call finalize(), and only on the next garbage-collection pass will it reclaim the object‘s memory.
finalize()的调用时机由垃圾回收器决定,不可控。
If there is some activity that must be performed before you no longer need an object, you must perform that activity yourself. Java has no destructor or similar concept, so you must create an ordinary method to perform this cleanup.
1. Your objects might not get garbage collected.
2. Garbage collection is not destruction.
3. Garbage collection is only about memory.
So an activity that is associated with garbage collection, most notably you finalize() method, must also be only about memory and its deallocation.
The need for finalize() is limited to special cases in which your object can allocate storage in some wary other than creating an object.
It would seem that finalize() is in place because of the possibility that you‘ll do something Clike by allocating memory using a mechanism other than the normal one on Java.
This can happen primarily through native methods, which are a way to call non-Java code from Java. C and C++ are the only languages currently supported by native methods, but since they can call subprograms in other languages, you can effectively call anything.
C‘s malloc() --allocate storage
C‘s free() --release memory (inside your finalize())
So finalize() is not the appropriate place for normal cleanup to occur. Where should normal cleanup be performed?
the presence of a garbage collector does not remove the need for or the utility of destructors.(And you should never call finalize() directly, so that‘s not a solution.) If you want som kind of cleanup performed other than storage release, you must still explicitly call an appropriate method in Java, which is the equivalent of a C++ destructor withou the convenientce.
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.
发现未释放资源的bug
The trick is that the garbage collector steps in, and while it collects the garbage it compacts all the objects in the heap so that you’ve effectively moved the “heap pointer” closer to the beginning of the conveyor belt and farther away from a page fault. The garbage collector rearranges things and makes it possible for the high-speed, infinite-free-heap model to be used while allocating storage.
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.
The garbage collectors moves through the entire list of objects, and when it finds one with a reference count of zero it releases that storage
The one drawback is that if objects circularly refer to each other they can have nonzero reference counts while still being garbage.Locating such self-referential groups requires significant extra work for the garbage collector. Reference counting is commonly used to explain one kind of garbage collection, but it doesn’t seem to be used in any JVM implementations.
In faster schemes, it is based on the idea that any non-dead object must ultimately be traceable back to a reference that lives either on the stack or in static storage. The chain might go through several layers of objects.
Thus, if you start in the stack and in the static storage area and walk through all the references, you’ll find all the live objects. For each reference that you find, you must trace into the object that it points to and then follow all the references in that object, tracing into the objects they point to, etc., until you’ve moved through the entire Web that originated with the reference on the stack or in static storage.
stop-and-copy: stop program,copy the objects from one heap to another, references be changed
inefficient reasons:
1. need two heaps , slosh all the memory back and forth between these tow separate heaps.(Some JVMs deal with this by allocating the heap in chunks as needed and simply copying from one chunk to another.)
2. Once program become stable, it might be generating little or no garbage. Despite that, a copy collector will still copy all the memory from one place to another.
mark-and-sweep: finds all live object, and mark by setting a flag in each, then sweep. So if the collector chooses to compact a fragmented heap, it does so by shuffling objects around.
For general use, mark-and-sweep is fairly slow, but when you know you’re generating little or no garbage, it’s fast.
Mark-and-sweep also requires that the program be stopped
Adaptive generational stop-and-copy mark-and-sweep
an uninitialized local variable is probably a programmer error, and a default value would have covered that up. Forcing the programmer to provide an initialization value is more likely to catch a bug.
If a primitive is a field in a class, however, things are a bit different. As you saw in the Everything Is an Object chapter, each primitive field of a class is guaranteed to get an initial value.
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.
simply to assign the value at the point you define the variable in the class.
This approach to initialization is simple and straightforward. It has the limitation that every object of the type will get these same initialization values. Sometimes this is exactly what you nedd, but at other times you need more flexibility.
There’s one thing to keep in mind, however: You aren’t precluding the automatic initialization, which happens before the constructor is entered.
//: initialization/Counter.java
public class Counter {
int i;
Counter() { i = 7; }
// ...
} ///:~
then i will first be initialized to 0, then to 7.This is true with all the primitive types and with object references, including those that are given explicit initialization at the point of definition.
the variables are initialized before any methods can be called—even the constructor.
初始化顺序:
1. 父类的static属性或static代码块(按编写顺序)
2. 子类的static属性或static代码块(按编写顺序,含覆盖父类的属性)
3. 父类属性或non-static代码块(按编写顺序)
4. 父类的构造器
5. 子类属性或non-static代码块(按编写顺序)
6. 子类的构造器
static {//...}
{//...}
int[] a; 和 int a[]; 都是有效的
int[] a1 = { 1, 2, 3, 4, 5 };
int[] a1 = new int[5];
Integer[] i = {1,2};
Integer[] ii = {1,2,};
Integer[] iii = new Integer[]{1,2,};
void printArray(Object[] args)
void printArray(Object... args) //no longer have to explicitly write out the array syntax—the compiler will actually fill it in for you when you specify varargs.You’re still getting an array, which is why print( ) is able to use foreach to iterate through the array.
printArray(new A(), new A(), new A());
printArray((Object[])new Integer[]{ 1, 2, 3, 4 }); //an array be passed to printArray( ). Clearly, the compiler sees that this is already an array and performs no conversion on it.
printArray(); //passing zero arguments is ok
You should generally only use a variable argument list on one version of an overloaded method. Or consider not doing it at all.
the enum keyword, which makes your life much easier when you need to group together and use a set of enumerated types.
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).
The compiler automatically adds useful features when you create an enum. For example, it creates a toString( ) so that you can easily display the name of an enum instance. The compiler also creates an ordinal( ) method to indicate the declaration order of a particular enum constant, and a static values( ) method that produces an array of values of the enum constants in the order that they were declared:
Although enums appear to be a new data type, the keyword only produces some compiler behavior while generating a class for the enum, so in many ways 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:
the garbage collector does add a runtime cost, the expense of which is difficult to put into perspective because of the historical slowness of Java interpreters. Although Java has had significant performance increases over time, the speed problem has taken its toll on the adoption of the language for certain types of programming problems.
Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(六)之Initialization & Cleanup
标签:
原文地址:http://www.cnblogs.com/linnicke/p/5055621.html