Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(六)之Initialization & Cleanup

  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.

Guaranteed initialization with the constructor

  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.)

Method overloading

  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).

  Distinguishing overloaded methods

  How can Java know which method you mean? There‘s a simple rule: Each overloaded method must take a unique list of argument types

  Overloading with primitives

  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.

  Overloading on return values

  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?

Default constructors

  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

THe this keyword

  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;

  Calling constructors from contructors

  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.

  The meaning of static

  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.

Cleanup:finalization and garbage collection

  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.

  What is finalize() for

  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?

  You must perform cleanup

  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.

  The termination condition

  发现未释放资源的bug

  How a garbage collector works

  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

Member initialization

  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.

  Specifying initialization

  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.

Constructor initialization

  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.

  Order of initialization

  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. 子类的构造器

  Explicit static initialization

  static {//...}

  Non-static instance initialization

  {//...}

Array initialization

  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,};

  Variable argument lists

  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.

Enumerated types

  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:

Summary

  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.

时间: 2024-10-07 05:55:31

Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(六)之Initialization & Cleanup的相关文章

Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(二)之Introduction to Objects

The genesis of the computer revolution was a machine. The genesis of out programming languages thus tends to look like that machine. 计算机革命起源于机器,因此编程语言的产生也始于对机器的模仿 Computers are mind amplification tools and a different kind of expressive medium. 计算机是大

Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十三)之Strings

Immutable Strings Objects of the String class are immutable. If you examine the JDK documentation for the String class, you’ll see that every method in the class that appears to modify a String actually creates and returns a brand new String object c

Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十一)之Holding Your Objects

To solve the general programming problem, you need to create any number of objects, anytime, anywhere. So you can't rely on creating a named reference to hold each one of your objects. Java has several ways to hold objects: 1. the compiler-supported

Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(八)之Polymorphism

Polymorphism is the third essential feature of an object-oriented programming language,after data abastraction and inheritance. It provides another dimension of separation of interface from implementation, to decouple what from how. Polymorphism allo

Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(八)之Reusing Classes

The trick is to use the classes without soiling the existing code. 1. composition--simply create objects of your existing class inside the new class. simply reusing the functionality of the code, not its form 2.inheritance--creates a new class as a t

Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记四)之Operators

At the lowest level, data in Java is manipulated using operators Using Java Operators An operator takes one or more argument and produces a new value. The arguements are in a different form than ordinary method calls, but the effect is the same. + :

Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十四)之Type Information

Runtime type information (RTTI) allow you to discover and use type information while a program is running This take two forms: 1. "traditional" RTTI, which assumes that you have all the types available at compile time, 2. the reflection mechanis

Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十二)之Error Handling with Exceptions

The ideal time to catch an error is at compile time, before you even try to run the program. However, not all errors can be detected at compile time. To create a robust system, each component must be robust. By providing a consistent error-reporting

Java编程思想第四版读书笔记——第十三章 字符串

Java编程思想第四版读书笔记--第十三章 字符串 字符串的操作是计算机程序设计中最常见的行为. 关键词: StringBuilder ,StringBuffer,toString(),format转换,正则表达式, 1.不可变String String对象时不可变的.每当把String对象作为方法的参数时,都会复制一份引用.(其实就是对函数中参数列表中参数的操作不会影响外面的原参数) 如下: import static net.mindview.util.Print.*; public cla