`
KellyLin1115
  • 浏览: 4682 次
  • 性别: Icon_minigender_2
  • 来自: 上海
最近访客 更多访客>>
社区版块
存档分类
最新评论

Initialization & Cleanup

 
阅读更多
Guaranteed initialization with the 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.
The constructor is an unusual type of method because it has no return value.
The new expression does return a reference to the newly created object, but the constructor itself has no return value.

Method overloading

Distinguishing overloaded methods
Each overloaded method must take a unique list of argument types.

Overloading on return values
Why only class names and method argument lists? Why not distinguish between methods based on their return values?
void f() {}
int f() { return 1; }
However, you can also call a method and ignore the return value. So if you call the method this way:
f();
how can Java determine which f( ) should be called?

Default constructors
f 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.

The this keyword
Banana a = new Banana(),
               b = new Banana();
a.peel(1);
b.peel(2);

How can that method know whether it’s being called for 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 some 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—produces the reference to the object that the method has been called for. You can treat the reference just like any other object reference. Keep in mind that 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.

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 takes on a different meaning when you give it an argument list. It makes an explicit call to the constructor that matches that argument list.

Since the name of the argument s and the name of the member data s are the same, there’s an ambiguity. You can resolve it by using this.s, to say that you’re referring to the member data.

The meaning of static
You cannot call non-static methods from inside static methods2 (although the reverse is possible)

Cleanup: finalization and garbage collection
Suppose your object allocates “special” memory without using new. The garbage collector only knows how to release memory allocated with new, so it won’t know how to release the object’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 your object, it will first call finalize( ), and only on the next garbage-collection pass will it reclaim the object’s memory.

What is finalize() for?
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 in 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. Inside the non-Java code, C’s malloc( ) family of functions might be called to allocate storage, and unless you call free( ), that storage will not be released, causing a memory leak. Of course, free( ) is a C and C++ function, so you’d need to call it in a native method inside your finalize( ).

The termination condition
In general, you can’t rely on finalize( ) being called, and you must create separate “cleanup” methods and call them explicitly. So it appears that finalize( ) is only useful for obscure memory cleanup that most programmers will never use. However, there is an interesting use of finalize( ) that does not rely on it being called every time. This is the verification of the termination condition of an object.
If any portions of the object are not properly cleaned up, then you have a bug in your program that can be very difficult to find. finalize( ) can be used to eventually discover this condition, even if it isn’t always called.

How a garbage collector works
To understand garbage collection in Java, it’s helpful learn how garbage-collection schemes work in other systems.
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 (however, reference counting schemes often release an object as soon as the count goes to zero). 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, garbage collection is not based on reference counting. Instead, 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. Note that there is no problem with detached self-referential groups—these are simply not found, and are therefore automatically garbage.

In the approach described here, the JVM uses an adaptive garbage-collection scheme, and what it does with the live objects that it locates depends on the variant currently being used. One of these variants is stop-and-copy. The program is first stopped (this is not a background collection scheme). Then, each live object is copied from one heap to another, leaving behind all the garbage. In addition, as the objects are copied into the new heap, they are packed end-to-end, thus compacting the new heap.

There are two issues that make these so-called “copy collectors” inefficient. The first is the idea that you have two heaps and you slosh all the memory back and forth between these two separate heaps, maintaining twice as much memory as you actually need. Some JVMs deal with this by allocating the heap in chunks as needed and simply copying from one chunk to another.
The second issue is the copying process itself. Once your program becomes 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, which is wasteful. To prevent this, some JVMs detect that no new garbage is being generated and switch to a different scheme (this is the “adaptive” part). This other scheme is called mark-and-sweep, and it’s what earlier versions of Sun’s JVM used all the time. 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 follows the same logic of starting from the stack and static storage, and tracing through all the references to find live objects. However, each time it finds a live object, that object is marked by setting a flag in it, but the object isn’t collected yet. Only when the marking process is finished does the sweep occur. During the sweep, the dead objects are released. However, no copying happens, so if the collector chooses to compact a fragmented heap, it does so by shuffling objects around.

Mark-and-sweep also requires that the program be stopped.

As previously mentioned, in the JVM described here memory is allocated in big blocks. If you allocate a large object, it gets its own block. Strict stop-and-copy requires copying every live object from the source heap to a new heap before you can free the old one, which translates to lots of memory. With blocks, the garbage collection can typically copy objects to dead blocks as it collects. Each block has a generation count to keep track of whether it’s alive. In the normal case, only the blocks created since the last garbage collection are compacted; all other blocks get their generation count bumped if they have been referenced from somewhere. This handles the normal case of lots of short-lived temporary objects. Periodically, a full sweep is made—large objects are still not copied (they just get their generation count bumped), and blocks containing small objects are copied and compacted. The JVM monitors the efficiency of garbage collection and if it becomes a waste of time because all objects are long-lived, then it switches to mark-andsweep. Similarly, the JVM keeps track of how successful mark-and-sweep is, and if the heap starts to become fragmented, it switches back to stop-and-copy. This is where the “adaptive” part comes in, so you end up with a mouthful: “Adaptive generational stop-and-copy mark-andsweep.”

There are a number of additional speedups possible in a JVM. An especially important one involves the operation of the loader and what is called a just-in-time (JIT) compiler. A JIT compiler partially or fully converts a program into native machine code so that it doesn’t need to be interpreted by the JVM and thus runs much faster. When a class must be loaded (typically, the first time you want to create an object of that class), the .class file is located, and the bytecodes for that class are brought into memory. At this point, one approach is to simply JIT compile all the code, but this has two drawbacks: It takes a little more time, which, compounded throughout the life of the program, can add up; and it increases the size of the executable (bytecodes are significantly more compact than expanded JIT code), and this might cause paging, which definitely slows down a program. An alternative approach is lazy evaluation, which means that the code is not JIT compiled until necessary. Thus, code that never gets executed might never be JIT compiled. The Java HotSpot technologies in recent JDKs take a similar approach by increasingly optimizing a piece of code each time it is executed, so the more the code is executed, the faster it gets.

Member initialization
boolean false
char []
byte 0
short 0
int 0
long 0
float 0.0
double 0.0
reference null
the char value is a zero, which prints as a space

Order of initialization
The variable definitions may be scattered throughout and in between method definitions, but the variables are initialized before any methods can be called—even the constructor.

static data initialization
You can’t apply the static keyword to local variables, so it only applies to fields.

static initialization occurs only if it’s necessary. If you don’t create a Table object and you never refer to Table.bowl1 or Table.bowl2, the static Bowl bowl1 and bowl2 will never be created. They are initialized only when the first Table object is created (or the first static access occurs). After that, the static objects are not reinitialized.

The order of initialization is static member/static clause first, then the non-static member/instance initilization. then constructor.


分享到:
评论

相关推荐

    Think in C++ 英文版(含卷一、卷二)

    6: Initialization & Cleanup 7: Function Overloading & Default Arguments 8: Constants 9: Inline Functions 10: Name Control 11: References & the Copy-Constructor 12: Operator Overloading 13: Dynamic ...

    TIJ4 Initialization Cleanup

    TIJ4 Initialization Cleanup

    Thinking_In_C#英文正式版

    第5章“Initialization & Cleanup”(初始化与清理)涉及对象的构造函数和析构函数,以及资源清理的重要性。第6章“Coupling and Cohesion”(耦合与内聚)则探讨了设计模块化程序的指导原则,这是编写可维护代码的...

    Think in C# .Net

    5. **第 5 章:Initialization & Cleanup** —— 阐述了对象初始化和清理的相关知识,包括构造函数、析构函数等。 6. **第 6 章:Coupling and Cohesion** —— 分析了模块之间的耦合性和内聚性,解释了良好的软件...

    think in C sharp

    初始化与清理 (Initialization & Cleanup) - **第5章:初始化与清理**(151页)讨论了对象生命周期管理,包括构造函数、析构函数等。 #### 6. 耦合与内聚 (Coupling and Cohesion) - **第6章:耦合与内聚**(215页...

    Thinking in CSharp

    - **第五章:初始化与清理**(Initialization & Cleanup):本章着重于C#中的对象生命周期管理,包括如何初始化对象以及在对象不再需要时如何进行适当的清理工作,这对于避免内存泄漏等问题至关重要。 - **第六章:...

    thinking in Java guide solutio

    Initialization & Cleanup (初始化与清理) - **初始化过程**:对象创建后如何进行初始化。 - **析构函数**:虽然Java没有析构函数,但可以通过finalizer实现类似的功能。 - **静态初始化块与非静态初始化块**:分别...

    Thinking in C++ VolumeI.pdf

    初始化与清理 (Initialization & Cleanup) 本章详细介绍了对象的初始化和清理过程: - **构造函数与析构函数**:解释了构造函数和析构函数的作用及使用方法。 - **内存管理**:讨论了内存分配和释放的重要性,以及...

    ucln_cmn.rar_UP

    它可能会包含函数声明,如`void ucln_cmn_init()`(初始化清理机制)和`void ucln_cmn_cleanup()`(执行清理操作)。此外,可能还会有枚举类型定义来标识不同类型的清理事件,或者是宏定义以控制调试信息的开关。 2...

    Defer:C的Defer陈述式

    int x __attribute__((cleanup(cleanup))) = 42; // ... return 0; } ``` 虽然这些方法可以实现类似`defer`的功能,但它们并没有内置的异常处理支持。在C++中,可以使用RAII(Resource Acquisition Is ...

    nls_cp863.rar_translation

    5. **Initialization and Cleanup**:初始化和清理函数,用于加载和卸载转换模块。 6. **Testing and Debugging**:可能包含一些测试用例和调试辅助函数,确保转换的准确性和兼容性。 在实际应用中,这样的转换库...

    C语言函数大全.CHM

    C语言函数大全,CHM,中文版。 C语言各种函数具体描述,有例证. 函数名: bar 功 能: 画一个二维条形图 用 法: void far bar(int left, int top, int right, int .../* clean up */ closegraph(); return 0; }

    python code patterns

    ### Initialization and Cleanup (初始化与清理) #### Initialization (初始化) - **构造函数**:使用`__init__`方法完成对象创建时的初始化工作。 - **属性设置**:在构造函数中为对象设置初始状态。 - **其他初始...

Global site tag (gtag.js) - Google Analytics