#Thinking in Java#读书笔记

最近在看Thinking in Java, 在这个贴子里摘录一些内容.

-----------------------------------------------------------------------------------------


(This UML diagram indicates composition with the filled diamond, which states there is one car. I will typically use a simpler form: just a line, without the diamond, to indicate an association.5

上图中的实心菱形表示"构造", 声明那是一辆车, 如果没有实心菱形, 只是一条直线的话则表示"联系". 


-----------------------------------------------------------------------------------------



(The arrow in this UML diagram points from the derived class to the base class. As you will see, there is commonly more than one derived class.) 

上图中的箭头从"派生类"指向"基础类", 通常会有多个派生类. 


-----------------------------------------------------------------------------------------



You have two ways to differentiate your new derived class from the original base class. The first is quite straightforward: You simply add brand new methods to the derived class. These new methods are not part of the base-class interface. This means that the base class simply didn’t do as much as you wanted it to, so you added more methods. This simple and primitive use for inheritance is, at times, the perfect solution to your problem. However, you should look closely for the possibility that your base class might also need these additional methods. This process of discovery and iteration of your design happens regularly in object-oriented programming. 

The second and more important way to differentiate your new class is tochangethe behavior of an existing base-class method. This is referred to asoverridingthat method. 

有两种方法可以使派生类和基础类区别开来, 一是在派生类中直接添加需要的方法, 就像上图Triangle 类中的 FlipVertical() 和 FlipHorizontal(). 第二种方法是Override基础类中的方法, 改变已有的基础类方法的behavior.


To override a method, you simply create a new definition for the method in the derived class. You’re saying, “I’m using the same interface method here, but I want it to do something different for my new type.” 

只要在派生类中给要override的method创造一个新的定义就可以了. 如上图所示.


-----------------------------------------------------------------------------------------


程序运行中的内存分类:
  1. Registers. This is the fastest storage because it exists in a place different from that of other storage: inside the processor. However, the number of registers is severely limited, so registers are allocated as they are needed. You don’t have direct control, nor do you see any evidence in your programs that registers even exist (C & C++, on the other hand, allow you to suggest register allocation to the compiler). 
  2. The stack. This lives in the general random-access memory (RAM) area, but has direct support from the processor via itsstack pointer. The stack pointer is moved down to create new memory and moved up to release that memory. This is anextremely fast and efficient way to allocate storage, second only to registers. The Java system must know, while it is creating the program, the exact lifetime of all the items that are stored on the stack. This constraint places limits on the flexibility of your programs, so while some Java storage exists on the stack—in particular, object references—Java objects themselves are not placed on the stack. 
  3. The heap. This is a general-purpose pool of memory (also in the RAM area)where all Java objects live. The nice thing about the heap is that, unlike the stack, the compiler doesn’t need to know how long that storage must stay on the heap. Thus, there’s a great deal of flexibility in using storage on the heap. Whenever you need an object, you simply write the code to create it by using new, and the storage is allocated on the heap when that code is executed. Of course there’s a price you pay for this flexibility: It may take more time to allocate and clean up heap storage than stack storage (if you even could create objects on the stack in Java, as you can in C++). 
  4. Constant storage. Constant values are often placed directly in the program code, which is safe since they can never change. Sometimes constants are cordoned off by themselves so that they can be optionally placed in read-only memory (ROM), in embedded systems.
  5. Non-RAM storage. If data lives completely outside a program, it can exist while the program is not running, outside the control of the program. The two primary examples of this arestreamed objects, in which objects are turned into streams of bytes, generally to be sent to another machine, andpersistent objects, in which the objects are placed on disk so they will hold their state even when the program is terminated. The trick with these types of storage is turning the objects into something that can exist on the other medium, and yet can be resurrected into a regular RAM-based object when necessary. Java provides support forlightweight persistence, and mechanisms such as JDBC and Hibernate provide more sophisticated support for storing and retrieving object information in databases. 

-----------------------------------------------------------------------------------------



关于primitive type:

The reason for the special treatment is that to create an object with new—especially a small, simple variable—isn’t very efficient, because new places objects on the heap. For these types Java falls back on the approach taken by C and C++. That is, instead of creating the variable by using new, an “automatic” variable is created that is not a reference. The variable holds the value directly, and it’s placed on the stack, so it’s much more efficient. 


Java规定了Primitive type的 size, 并且是固定不变的, 这也是Java具有良好可移植性(portable)的原因之一. 

各种Primitive type 见下图:


  • All numeric types are signed
  • The size of the boolean type is not explicitly specified; it's only defined to be able to take the literal values true or false.
  • The wrapper classes for the primitive data types allow u to make a non-primitive object on the heap to represent that primitive type.                                                     For example:     char c = 'x';          Character ch = new Character(c);         Character ch = new Character('x');
  • Java SE5 autoboxing will automatically convert from a primitive to a wrapper type:     

    Character ch = ‘x’;        char c = ch;    
    

  • High-precision numbers: BigInteger & BigDecimal
-----------------------------------------------------------------------------------------

Fields

A field is an object of any type that you can talk to via its reference, or a primitive type. If it is a reference to an object, you must initialize that reference to connect it to an actual object (using new )


class DataOnly {
int i;
double d;
boolean b;
}


Primitive type default value:

                      
    


This guarantee doesn’t apply to local variables—those that are not fields of a class. Thus, if within a method definition you have: 

int x; 

Then x will get some arbitrary value (as in C and C++); it will not automatically be initialized to zero. You are responsible for assigning an appropriate value before you use x. If you forget, Java definitely improves on C++: You get a compile-time error telling you the variable might not have been initialized. (Many C++ compilers will warn you about uninitialized variables, but in Java these are errors.) 

! [局部变量并不属于field, 不会赋default值]


-----------------------------------------------------------------------------------------



Static

When you say something is static, it means that particular field or method is not tied to any particular object instance of that class. So even if you’ve never created an object of that class you can call a static method or access a static field. With ordinary, non-static fields and methods, you must create an object and use that object to access the field or method, since non-static fields and methods must know the particular object they are working with

There are two ways to refer to a static variable. As the preceding example indicates, you can name it via an object, by saying, for example, st2.i. You can also refer to it directly through its class name, something you cannot do with a non-static member 

Using the class name is the preferred way to refer to a static variable. Not only does it emphasize that variable’s static nature, but in some cases it gives the compiler better opportunities for optimization. 


An important use of static for methods is to allow you to call that method without creating an object. This is essential, as you will see, in defining the main( ) method that is the entry point for running an application. 

[static很重要的应用之一就是main()方法, 作为程序的entry point.]


-----------------------------------------------------------------------------------------



Shift Operators

The left-shift operator (<<) produces the operand to the left of the operator after it has been shifted to the left by the number of bits specified to the right of the operator (inserting zeroes at the lower-order bits). The signed right-shift operator (>>) produces the operand to the left of the operator after it has been shifted to the right by the number of bits specified to the right of the operator. The signed right shift >> uses sign extension: If the value is positive, zeroes are inserted at the higher-order bits; if the value is negative, ones are inserted at the higher-order bits. Java has also added the unsigned right shift >>>, which uses zero extension: Regardless of the sign, zeroes are inserted at the higher-order bits.

If you shift a char, byte, or short, it will be promoted to int before the shift takes place, and the result will be an int. Only the five low-order bits of the right-hand side will be used. This prevents you from shifting more than the number of bits in an int. If you’re operating on a long, you’ll get a long result. Only the six low-order bits of the right-hand side will be used, so you can’t shift more than the number of bits in a long


-----------------------------------------------------------------------------------------


Promotion

In general, the largest data type in an expression is the one that determines the size of the result of that expression; if you multiply a float and a double, the result will be double; if you add an int and a long, the result will be long


-----------------------------------------------------------------------------------------


Infinite loop:

for(;;) 

for(; true ;) 

or

while(true)


-----------------------------------------------------------------------------------------


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. 


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. 

[同一class中的method可以直接call, this会自动应用到这些method]

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

---

this还可以用于多个constructor之间的调用, 不过有一些限制:

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.

the compiler won’t let you call a constructor from inside any method other than a constructor 

 

//: initialization/Flower.java
// Calling constructors with "this"
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);
//! this(s); // Can’t call two!
this.s = s; // Another use of "this"
print("String & int args");
}
Flower() {
this("hi", 47);
print("default constructor (no args)");
}
void printPetalCount() {
//! this(11); // Not inside non-constructor!
print("petalCount = " + petalCount + " s = "+ s);
}
public static void main(String[] args) {
Flower x = new Flower();
x.printPetalCount();
}
} /* Output:
Constructor w/ int arg only, petalCount= 47
String & int args
default constructor (no args)
petalCount = 47 s = hi
*///:~

-----------------------------------------------------------------------------------------


static
meaning: 

It means that there is no this for that particular method. You cannot call non-static methods from inside static methods2 (although the reverse is possible), and you can call a static method for the class itself, without any object. In fact, that’s primarily what a static method is for. It’s as if you’re creating the equivalent of a global method. However, global methods are not permitted in Java, and putting the static method inside a class allows it access to other static methods and to static fields. 


-----------------------------------------------------------------------------------------

Cleanup: finalization and garbage collection 

Garbage collector只会释放和"new"相关的内存, 所以如果你的object分配了没有使用new的special memory的话, 只用garbage collection是无法释放这些内存的. 这时就要用到 finalize()这个method.  garbage collector会首先调用 finalize(), 然后回收object的内存. 


  1. Your objects might not get garbage collected. 
  2. Garbage collection is not destruction. 
  3. Garbage collection is only about memory. 
举例: 

For example, suppose that in the process of creating your object, it draws itself on the screen. If you don’t explicitly erase its image from the screen, it might never get cleaned up. If you put some kind of erasing functionality inside finalize( ), then if an object is garbage collected and finalize( ) is called (and there’s no guarantee this will happen), then the image will first be removed from the screen, but if it isn’t, the image will remain. 


finalize()的适用情景:

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. (Native methods are covered in Appendix B in the electronic 2nd edition of this book, available at www.MindView.net.) 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( ). 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值