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.
Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(六)之Initialization & Cleanup的更多相关文章
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(七)之Access Control
Access control ( or implementation hiding) is about "not getting it right the first time." ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十三)之Strings
Immutable Strings Objects of the String class are immutable. If you examine the JDK documentation fo ...
- 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 ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十四)之Type Information
Runtime type information (RTTI) allow you to discover and use type information while a program is ru ...
- 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 ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十一)之Holding Your Objects
To solve the general programming problem, you need to create any number of objects, anytime, anywher ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十)之Inner Classes
The inner class is a valuable feature because it allows you to group classes that logically belong t ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(九)之Interfaces
Interfaces and abstract classes provide more structured way to separate interface from implementatio ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(八)之Polymorphism
Polymorphism is the third essential feature of an object-oriented programming language,after data ab ...
随机推荐
- .NET Core技术研究-HttpContext访问的正确姿势
将ASP.NET升级到ASP.NET Core之后,相信大家都会遇到HttpContext.Current无法使用的问题.这也是我们迁移ASP.NET Core必须解决的问题. 本文我们详细讨论一下, ...
- masql数据库的表查询
昨日回顾 表与表之间建关系 一对多 换位思考 图书与出版社 先站在左表: 考虑左表的多条数据能否对应右表的一条数据 翻译:多本书能否被一个出版社出版 可以! 注意:单站在一张得出的表关系并不能明确两张 ...
- Verbal Arithmetic Puzzle
2020-01-02 12:09:09 问题描述: 问题求解: 这个问题不就是小学奥数题么?都知道要暴力枚举,但是如何巧妙的枚举才是问题的关键.在打比赛的时候,我用了全排列算法,TLE了. 借鉴了别人 ...
- RDD的Cache、Persist、Checkpoint的区别和StorageLevel存储级别划分
为了增强容错性和高可用,避免上游RDD被重复计算的大量时间开销,Spark RDD设计了包含多种存储级别的缓存和持久化机制,主要有三个概念:Cache.Persist.Checkout. 1.存储级别 ...
- 为什么你的程序配了classpath还是找不到类
classpath简介 classpath是java程序时拥有的一个系统变量,这个变量可以通过如下方式获取 System.out.println(System.getProperty("ja ...
- pikachu学习-暴力破解模块
安装好XAMPP,burpsuite,配置好pikachu我们就可以进行pikachu平台的漏洞学习 我这篇博客主要写暴力破解模块讲解,它分为4个小模块,分别是“基于表单的暴力破解”,“验证码绕过(o ...
- Java 添加、删除Excel表单控件
通过表单控件,用户可以快速地将数据填写到模板文档中,轻松引用单元格数据并与其进行交互.本文通过Java代码示例介绍如何在Excel表格中添加表单控件,包括文本框.单选按钮.复选框.组合框.微调按钮等: ...
- 物体的三维识别与6D位姿估计:PPF系列论文介绍(三)
作者:仲夏夜之星 Date:2020-04-08 来源:物体的三维识别与6D位姿估计:PPF系列论文介绍(三) 文章“A Method for 6D Pose Estimation of Free-F ...
- python常用模块 以及第三方导入
python常用模块 1模块的分类 标准模块(内置模块)( 标准库 )300 第三方模块 18万 pip install 直接通过pip安装 软件一般会被自动安装你python安装目录的这个子目录里 ...
- 1642: 【USACO】Payback(还债)
1642: [USACO]Payback(还债) 时间限制: 1 Sec 内存限制: 64 MB 提交: 190 解决: 95 [提交] [状态] [讨论版] [命题人:外部导入] 题目描述 &quo ...