⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tij303.htm

📁 这也是我们java老师给我们的thinking in java的一些资料
💻 HTM
📖 第 1 页 / 共 5 页
字号:
doStuff(c);
doStuff(t);
doStuff(l);</PRE></FONT></BLOCKQUOTE><p><br></p>
<p>the calls to <b>doStuff(&#160;) </b>automatically work correctly, regardless of the exact type of the object. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_164" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>This is a rather amazing trick. Consider the line:<br></p>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>doStuff(c);</PRE></FONT></BLOCKQUOTE><p><br></p>
<p>What&#146;s happening here is that a <b>Circle</b> is being passed into a method that&#146;s expecting a <b>Shape</b>. Since a <b>Circle</b> <i>is</i> a <b>Shape</b> it can be treated as one by <b>doStuff(&#160;)</b>. That is, any message that <b>doStuff(&#160;)</b> can send to a <b>Shape</b>, a <b>Circle</b> can accept. So it is a completely safe and logical thing to do. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_165" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>We call this process of treating a derived type as though it were its base type <a name="Index102"></a><i>upcasting</i>. The name <a name="Index103"></a><i>cast </i>is used in the sense of casting into a mold and the <i>up</i> comes from the way the inheritance diagram is typically arranged, with the base type at the top and the derived classes fanning out downward. Thus, casting to a base type is moving up the inheritance diagram: &#147;upcasting.&#148; <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_166" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p align="center"><a name="Index104"></a><a name="Index105"></a><img src="TIJ312.png" 	alt="TIJ312.png" border="0" ><br></p>
<p>An object-oriented program contains some upcasting somewhere, because that&#146;s how you decouple yourself from knowing about the exact type you&#146;re working with. Look at the code in <b>doStuff(&#160;)</b>: <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_167" title="Send BackTalk Comment">Feedback</a></font><br></p>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>  s.erase();
  <font color=#009900>// ...</font>
  s.draw();</PRE></FONT></BLOCKQUOTE><p><br></p>
<p>Notice that it doesn&#146;t say &#147;If you&#146;re a <b>Circle</b>, do this, if you&#146;re a <b>Square</b>, do that, etc.&#148; If you write that kind of code, which checks for all the possible types that a <b>Shape</b> can actually be, it&#146;s messy and you need to change it every time you add a new kind of <b>Shape</b>. Here, you just say &#147;You&#146;re a shape, I know you can <b>erase(&#160;) </b>and <b>draw(&#160;) </b>yourself, do it, and take care of the details correctly.&#148; <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_168" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>What&#146;s impressive about the code in <b>doStuff(&#160;)</b> is that, somehow, the right thing happens. Calling <b>draw(&#160;)</b> for <b>Circle</b> causes different code to be executed than when calling <b>draw(&#160;) </b>for a <b>Square</b> or a <b>Line</b>, but when the <b>draw(&#160;)</b> message is sent to an anonymous <b>Shape</b>, the correct behavior occurs based on the actual type of the <b>Shape</b>. This is amazing because, as mentioned earlier, when the Java compiler is compiling the code for <b>doStuff(&#160;)</b>, it cannot know exactly what types it is dealing with. So ordinarily, you&#146;d expect it to end up calling the version of <b>erase(&#160;)</b> and <b>draw(&#160;) </b>for the base class <b>Shape</b>, and not for the specific <b>Circle</b>, <b>Square</b>, or <b>Line</b>. And yet the right thing happens because of polymorphism. The compiler and run-time system handle the details; all you need to know right now is that it does happen, and more importantly, how to design with it. When you send a message to an object, the object will do the right thing, even when upcasting is involved. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_169" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h3>
<a name="_Toc375545197"></a><a name="_Toc473421287"></a><a name="_Toc24775521"></a><a name="Heading1111"></a>Abstract
base classes and interfaces</h3>
<p>Often in a design, you want the base class to present <i>only</i> an interface for its derived classes. That is, you don&#146;t want anyone to actually create an object of the base class, only to upcast to it so that its interface can be used. This is accomplished by making that class <i>abstract </i>by using the <b>abstract</b> keyword. If anyone tries to make an object of an <b>abstract</b> class, the compiler prevents it. This is a tool to enforce a particular design. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_170" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>You can also use the <b>abstract</b> keyword to describe a method that hasn&#146;t been implemented yet&#151;as a stub indicating &#147;here is an interface method for all types inherited from this class, but at this point I don&#146;t have any implementation for it.&#148; An <b>abstract </b>method may be created only inside an <b>abstract </b>class. When the class is inherited, that method must be implemented, or the inheriting class becomes <b>abstract</b> as well. Creating an <b>abstract</b> method allows you to put a method in an interface without being forced to provide a possibly meaningless body of code for that method. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_171" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>The <b>interface</b> keyword takes the concept of an <b>abstract</b> class one step further by preventing any method definitions at all. The <b>interface</b> is a very handy and commonly used tool, as it provides the perfect separation of interface and implementation. In addition, you can combine many interfaces together, if you wish, whereas inheriting from multiple regular classes or abstract classes is not possible. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_172" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h2>
<a name="_Toc375545198"></a><a name="_Toc408018395"></a><a name="_Toc408018408"></a><a name="_Toc312373795"></a><a name="_Toc24775522"></a><a name="Heading1115"></a>Object
creation, use &amp; lifetimes</h2>
<p>Technically, OOP is just about abstract data typing, inheritance, and polymorphism, but other issues can be at least as important. This section will cover these issues. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_173" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>One of the most important factors of objects is the way they are created and destroyed. Where is the data for an object and how is the lifetime of the object controlled? There are different philosophies at work here. C++ takes the approach that control of efficiency is the most important issue, so it gives the programmer a choice. For maximum run-time 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 <i>automatic</i> or <i>scoped</i> variables) or in the static storage area. This places a priority on the speed of storage allocation and release, and control of these 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. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_174" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>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. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_175" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>Java uses the second approach, exclusively.<sup><a name="fnB7" href="#fn7">[7]</a></sup> Every time you want to create an object, you use the <b>new</b> keyword to build a dynamic instance of that object. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_176" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>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&#146;t do it correctly (and this is a common problem in C++ programs). Java provides a feature called a <i>garbage collector</i> 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 important, 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). <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_177" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h3>
<a name="_Toc24775523"></a><a name="Heading1122"></a>Collections and
iterators</h3>
<p>If you don&#146;t know how many objects you&#146;re going to need to solve a particular problem, or how long they will last, you also don&#146;t know how to store those objects. How can you know how much space to create for those objects? You can&#146;t, since that information isn&#146;t known until run time. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_179" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>The solution to most problems in object-oriented design seems flippant: You create another type of object. The new type of object that solves this particular problem holds references to other objects. Of course, you can do the same thing with an array, which is available in most languages. But this new object, generally called a <i>container</i> (also called a <i>collection</i>, but the Java library uses that term in a different sense so this book will use &#147;container&#148;), will expand itself whenever necessary to accommodate everything you place inside it. So you don&#146;t need to know how many objects you&#146;re going to hold in a container. Just create a container object and let it take care of the details. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_180" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>Fortunately, a good OOP language comes with a set of containers as part of the package. In C++, it&#146;s part of the Standard C++ Library and is sometimes called the Standard Template Library (STL). Object Pascal has containers in its Visual Component Library (VCL). Smalltalk has a very complete set of containers. Java also has containers in its standard library. In some libraries, a generic container 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 <b>List</b> classes (to hold sequences), <b>Map </b>classes (also known as <i>associative arrays</i>, to associate objects with other objects), and <b>Set</b> classes (to hold one of each type of object). Container libraries may also include queues, trees, stacks, etc. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap01_181" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>All containers have some way to put things in and get things out; there are usually methods to add elements to a container, and others to fetch those elements back out. But fetching elements can be more problematic, because a single-selection method is restrictive. What if you want to manipulate or compare a set of elemen

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -