Thinking in java 笔记1

来源:互联网 发布:支付宝软件 编辑:程序博客网 时间:2024/05/29 18:59

源代码地址:www.MindView.net


p.19 The hidden implementation

private

protected: an inheriting class has access to protected members

default: package access

public


p.28 Containers

 In some libraries, one or two generic containers is considered good
enough for all needs, and in others (Java, for example) the library has different types of
containers for different needs: several different kinds of List classes (to hold sequences),
Maps (also known as associative arrays, to associate objects with other objects),Sets (to
hold one of each type of object), and more components such as queues, trees, stacks, etc.
From a design standpoint, all you really want is a container that can be manipulated to solve
your problem. If a single type of container satisfied all of your needs, there’d be no reason to
have different kinds. There are two reasons that you need a choice of containers. First,
containers provide different types of interfaces and external behavior. A stack has a different
interface and behavior than a queue, which is different from a set or a list. One of these might
provide a more flexible solution to your problem than the other. Second, different containers
have different efficiencies for certain operations. For example, there are two basic types of
List: ArrayList and LinkedList. Both are simple sequences that can have identical
interfaces and external behaviors. But certain operations can have significantly different
costs. Randomly accessing elements in an ArrayList is a constant-time operation; it takes
the same amount of time regardless of the element you select. However, in a LinkedList it is
expensive to move through the list to randomly select an element, and it takes longer to find
an element that is farther down the list. On the other hand, if you want to insert an element
in the middle of a sequence, it’s cheaper in a LinkedList than in an ArrayList. These and
other operations have different efficiencies depending on the underlying structure of the
sequence. You might start building your program with a LinkedList and, when tuning for
performance, change to an ArrayList. Because of the abstraction via the interface List, you
can change from one to the other with minimal impact on your code.

ArrayList适合查询,LinkedList适合insert


p.30 Object creation & lifetime

For maximum runtime speed, the storage and lifetime can be determined while the
program is being written, by placing the objects on the stack (these are sometimes called
automatic or scoped variables) or in the static storage area. This places a priority on the
speed of storage allocation and release, and this control can be very valuable in some
situations. However, you sacrifice flexibility because you must know the exact quantity,
lifetime, and type of objects while you’re writing the program. If you are trying to solve a
more general problem such as computer-aided design, warehouse management, or air-traffic
control, this is too restrictive.
The second approach is to create objects dynamically in a pool of memory called the heap. In
this approach, you don’t know until run time how many objects you need, what their lifetime
is, or what their exact type is. Those are determined at the spur of the moment while the
program is running. If you need a new object, you simply make it on the heap at the point
that you need it. Because the storage is managed dynamically, at run time, the amount of
time required to allocate storage on the heap can be noticeably longer than the time to create
storage on the stack. Creating storage on the stack is often a single assembly instruction to
move the stack pointer down and another to move it back up. The time to create heap storage
depends on the design of the storage mechanism.
The dynamic approach makes the generally logical assumption that objects tend to be
complicated, so the extra overhead of finding storage and releasing that storage will not have
an important impact on the creation of an object. In addition, the greater flexibility is
essential to solve the general programming problem.
Java uses dynamic memory allocation, exclusively. 7 Every time you want to create an object,
you use the new operator to build a dynamic instance of that object.
There’s another issue, however, and that’s the lifetime of an object. With languages that allow
objects to be created on the stack, the compiler determines how long the object lasts and can
automatically destroy it. However, if you create it on the heap the compiler has no knowledge
of its lifetime. In a language like C++, you must determine programmatically when to destroy
the object, which can lead to memory leaks if you don’t do it correctly (and this is a common
problem in C++ programs). Java provides a feature called a garbage collector that
automatically discovers when an object is no longer in use and destroys it. A garbage
collector is much more convenient because it reduces the number of issues that you must
track and the code you must write. More importantly, the garbage collector provides a much
higher level of insurance against the insidious problem of memory leaks, which has brought
many a C++ project to its knees.
With Java, the garbage collector is designed to take care of the problem of releasing the
memory (although this doesn’t include other aspects of cleaning up an object). The garbage
collector “knows” when an object is no longer in use, and it then automatically releases the
memory for that object. This, combined with the fact that all objects are inherited from the
single root class Object and that you can create objects only one way—on the heap—makes
the process of programming in Java much simpler than programming in C++. You have far
fewer decisions to make and hurdles to overcome.



p.42

Where storage lives
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 its stack pointer. The stack pointer is moved
down to create new memory and moved up to release that memory. This is an
extremely 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. 2
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 are streamed objects, in which objects are turned into streams of
bytes, generally to be sent to another machine, and persistent 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 for lightweight persistence, and
mechanisms such as JDBC and Hibernate provide more sophisticated support for
storing and retrieving object information in databases.

0 0
原创粉丝点击