1 / 42

6: Reusing Classes (复用代码是 java 众多引人注目的功能之一)

6: Reusing Classes (复用代码是 java 众多引人注目的功能之一).

selah
Download Presentation

6: Reusing Classes (复用代码是 java 众多引人注目的功能之一)

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 6: Reusing Classes(复用代码是java众多引人注目的功能之一) That’s the approach used in procedural languages like C, and it hasn’t worked very well. Like everything in Java, the solution revolves around the class. You reuse code by creating new classes, but instead of creating them from scratch, you use existing classes that someone has already built and debugged. One of the most compelling(引人注目) features about Java is code reuse. But to be revolutionary, you’ve got to be able to do a lot more than copy code and change it(仅仅拷贝和加以修改是不够的). The trick(窍门)is to use the classes without soiling(污染)the existing code.

  2. In this chapter you’ll see two ways to accomplish this. The first is quite straightforward: you simply create objects of your existing class inside the new class. This is called composition, because the new class is composed of objects of existing classes. You’re simply reusing the functionality of the code, not its form. The second approach is more subtle. It creates a new class as a type of an existing class. You literally take the form of the existing class and add code to it without modifying the existing class. This magical act(神奇的行为) is called inheritance, and the compiler does most of the work. Inheritance is one of the cornerstones(基石) of object-oriented programming.

  3. 6.1 Composition syntax SprinklerSystem private WaterSource source; publicstaticvoid main( .. ) WaterSource WaterSource() new sprinklers 将WaterSource置于新类中

  4. 6.1 Composition syntax Until now, composition has been used quite frequently. You simply place object references inside new classes. publicclass SprinklerSystem { private String valve1, valve2, valve3, valve4; private WaterSource source; privateint i; privatefloat f; public String toString() { return "valve1 = " + valve1 + "\n" + "valve2 = " + valve2 + "\n" + "valve3 = " + valve3 + "\n" + "valve4 = " + valve4 + "\n" + "i = " + i + "\n" + "f = " + f + "\n" + "source = " + source; } //: c06:SprinklerSystem.java // Composition for code reuse. class WaterSource { private String s; WaterSource() { System.out.println("WaterSource()"); s = new String("Constructed"); } public String toString() { return s; } }

  5. publicstaticvoid main(String[] args) { SprinklerSystem sprinklers = new SprinklerSystem(); System.out.println(sprinklers); } } ///:~ Primitives that are fields in a class are automatically initialized to zero; But the object references are initialized to null; (对象引用会被初始化为null) if you try to call methods for any of them, you’ll get an exception.

  6. It makes sense(这是有意义的) that the compiler doesn’t just create a default object for every reference, because that would incur(招致)unnecessary overhead(负担)in many cases. If you want the references initialized, you can do it: • At the point the objects are defined(在定义对象的地方). This means that they’ll always be initialized before the constructor is called. • In the constructor for that class(在构造器中). • Right before you actually need to use the object(在使用之前). This is often called lazy initialization. It can reduce overhead in situations where object creation is expensive and the object doesn’t need to be created every time.

  7. All three approaches are shown here: //: c06:Bath.java// Constructor initialization with composition.class Soap { private String s; Soap() { System.out.println("Soap()"); s = new String("Constructed"); } public String toString() { return s; }} One reference 2、在构造器中

  8. public class Bath { private String // Initializing at point of definition: s1 = new String("Happy"), s2 = "Happy", s3, s4; private Soap castille; private int i; private float toy; public Bath() { System.out.println("Inside Bath()"); s3 = new String("Joy"); i = 47; toy = 3.14f; castille = new Soap(); } 1、在对象定义的地方 2、在构造器中

  9. 3、在要用之前。 public String toString() { if(s4 == null) // Delayed initialization: s4 = new String("Joy"); return "s1 = " + s1 + "\n" + "s2 = " + s2 + "\n" + "s3 = " + s3 + "\n" + "s4 = " + s4 + "\n" + "i = " + i + "\n" + "toy = " + toy + "\n" + "castille = " + castille; } public static void main(String[] args) { Bath b = new Bath(); System.out.println(b); } } ///:~

  10. 6.2 Inheritance syntax(继承语法) • Inheritance is an integral(不可缺少的) part of Java (and all OOP languages). It turns out(总是在产生)that you’re always doing inheritance when you create a class, because unless you explicitly inherit from some other class, you implicitly inherit from Java’s standard root class Object. The syntax for composition is obvious, but to perform inheritance there’s a distinctly different form. When you inherit, you say “This new class is like that old class.”

  11. //: c06:Detergent.java// Inheritance syntax & properties.(清洁剂)class Cleanser { private String s = new String("Cleanser");public void append(String a) { s += a; }public void dilute() { append(“ dilute()”); }public void apply() { append(“ apply()”); }public void scrub() { append(“ scrub()”); }public String toString() { return s; } public static void main(String[] args) { Cleanser x = new Cleanser(); x.dilute(); // 稀释x.apply(); x.scrub(); System.out.println(x); } }

  12. (去垢剂) public class Detergent extends Cleanser {// Change a method:public void scrub() { (这个方法的输出变的有两部分) append(" Detergent.scrub()"); super.scrub(); // Call base-class version}// Add methods to the interface: public void foam() { append(" foam()"); }// Test the new class: public static void main(String[] args) { Detergent x = new Detergent(); x.dilute(); x.apply(); x.scrub(); x.foam(); System.out.println(x); System.out.println("Testing base class:"); Cleanser.main(args); } } ///:~

  13. 派生类的输出 基类的输出

  14. This demonstrates a number of features. (这个程序示范了JAVA的许多特性)First, in the Cleanser append() method, Strings are concatenated to s using the += operator, which is one of the operators (along with ‘+’) that the Java designers “overloaded” to work with Strings.(将字符串重载)Second, both Cleanser and Detergent contain a main() method. You can create a main() for each one of your classes, and it’s often recommended to code this way so that your test code is wrapped (预先包装的)in with the class. (有main( ) 便于测试程序)

  15. It’s important that all of the methods in Cleanser are public. • Note that Cleanser has a set of methods in its interface: append(), dilute(), apply(), scrub(), and toString(). Because Detergent is derived fromCleanser (via the extends keyword), it automatically gets all these methods in its interface, even though you don’t see them all explicitly defined in Detergent. You can think of inheritance, then, as reusing the class.

  16. In Detergent.main() you can see that for a Detergent object, you can call all the methods that are available in Cleanser as well as in Detergent (i.e., foam()). • 如果没有访问权限修饰符,成员的缺省访问权限是“包访问”。

  17. 1、阅读下面的程序并写出类MyClass3的所有成员,并写明它们定义自哪里。1、阅读下面的程序并写出类MyClass3的所有成员,并写明它们定义自哪里。 class MyClass1{ private int pro11; double pro12; } class MyClass2 extends MyClass1{ private double pro12; int pro21; } class MyClass3 extend MyClass2{ private int pro21; double pro31; } 只能在超类重用 没有修饰就是包限制 修改这个程序,表明类MyClass3的所有成员 要用到main()函数

  18. public class MyClass{ public static void main(String args[]){ MyClass3 x=new MyClass3(); x.pro11=55; x.pro12 =3.14; x.pro21 =77; x.pro31 = 3.1415926; System.out.println(x.pro21); System.out.println(x.pro31); }} Pro21被去掉了private

  19. 2、定义—个类MyRectangle代表矩形,为矩形定义getLength方法(获得矩形的长度)、getWidth方法(获得矩形的宽度)、setLength方法(设置矩形的长度)、setWidth方法(设置矩形的宽度)、getArea方法(求矩形的面积)和toString方法(显示矩形的格式); 为矩形派生出一个子类MySquare代表正方形,并对getArea和toString进行重写。并编写程序进行测试。

  20. public class MyRectangle{ static int l; static int w; public MyRectangle(){ } public MyRectangle(int Length,int Width){ l=Length; w=Width; } public double getLength(){ return l; } public double getWidth(){ return w; } public static double getArea(){ return l*w; } public String toString(){ return "the area is"+getArea()+"nn"; } public double setLength(int Length){ l=Length; return l; } public double setWidth(int Width){ w=Width; return w; } public static void main(String args[]){ MyRectangle x=new MyRectangle(3,6); System.out.println(getArea()); System.out.println(x.toString()); }} public class MySquare extends MyRectangle{ public MySquare(){ } public MySquare(int Length,int Width){ l=Length; w=Width; } public static void main(String args[]){ MySquare x=new MySquare(6,6); System.out.println(getArea()); System.out.println(x.toString()); }}

  21. Initializing the base class (初始化基类) It’s essential that the base-class subobject be initialized correctly, and there’s only one way to guarantee this: perform the initialization in the constructor by calling the base-class constructor, which has all the appropriate knowledge and privileges to perform the base-class initialization. Java automatically inserts calls to the base-class constructor in the derived-class constructor. The following example shows this working with three levels of inheritance:

  22. //: c06:Cartoon.java// Constructor calls during inheritance.import com.bruceeckel.simpletest.*; class Art {Art() { System.out.println("Art constructor"); } } class Drawing extends Art { Drawing() { System.out.println("Drawing constructor"); } } publicclass Cartoon extends Drawing { privatestatic Test monitor = new Test();publicCartoon() { System.out.println("Cartoon constructor"); }publicstaticvoid main(String[] args) { Cartoon x = new Cartoon(); monitor.expect(new String[] {"Art constructor", "Drawing constructor","Cartoon constructor" }); } } ///:~ 类构造器 Art constructor Drawing constructor Cartoon constructor

  23. Constructors with arguments(带参数的构造器) • The preceding example has default constructors; that is, they don’t have any arguments. It’s easy for the compiler to call these because there’s no question about what arguments to pass. • If your class doesn’t have default arguments, or if you want to call a base-class constructor that has an argument, you must explicitly write the calls to the base-class constructor using the super keyword and the appropriate argument list:

  24. //: c06:Chess.java// Inheritance, constructors and arguments.import com.bruceeckel.simpletest.*; class Game { Game(int i) { System.out.println("Game constructor"); } } class BoardGame extends Game { BoardGame(int i) { super(i); System.out.println("BoardGame constructor"); } } publicclass Chess extends BoardGame {privatestatic Test monitor = new Test(); Chess() {super(11); System.out.println("Chess constructor"); }publicstaticvoid main(String[] args) { Chess x = new Chess(); } } ///:~ 类构造器 If you don’t call the base-class constructor in BoardGame(), the compiler will complain that it can’t find a constructor of the form Game(). In addition, the call to the base-class constructor must be the first thing you do in the derived-class constructor. (The compiler will remind you if you get it wrong.) monitor.expect(new String[] {"Game constructor", "BoardGame constructor","Chess constructor" });

  25. Plate DinnerPlate Utensil Custom Spoon PlaceSetting Fork Knife It is very common to use composition and inheritance together. The following example shows the creation of a more complex class, using both inheritance and composition, along with the necessary constructor initialization: • 6.3 Combining composition and inheritance 要好好的研究这个程序!

  26. 6.3.1 Guaranteeing proper cleanup • Java doesn’t have the C++ concept of a destructor, a method that is automatically called when an object is destroyed. The reason is probably that in Java, the practice is simply to forget about objects rather than to destroy them, allowing the garbage collector to reclaim the memory as necessary. you can’t know when the garbage collector will be called, or if it will be called. So if you want something cleaned up for a class, you must explicitly write a special method to do it, and make sure that the client programmer knows that they must call this method.

  27. In main(), you can see two keywords that are new, and won’t officially(正式地) be introduced until Chapter 9: try and finally. The try keyword indicates that the block that follows (delimited by curly braces) is a guarded region(保护区), which means that it is given special treatment. One of these special treatments is that the code in the finally clause following this guarded region is always executed(总是被执行), no matter how the try block exits. (With exception handling, it’s possible to leave a try block in a number of nonordinary ways.) Here, the finally clause is saying “always call dispose() for x(一定要为X调用…), no matter what happens.” These keywords will be explained thoroughly in Chapter 9.

  28. 6.6 Incremental development(增量开发) • One of the advantages of inheritance is that it supports incremental development. • You can introduce new code without causing bugs in existing code; in fact, you isolate new bugs inside the new code. By inheriting from an existing, functional class and adding fields and methods (and redefining existing methods), you leave the existing code—that someone else might still be using—untouched and unbugged. • If a bug happens, you know that it’s in your new code, which is much shorter and easier to read than if you had modified the body of existing code. • It’s rather amazing how cleanly the classes are separated(类被隔离的如此干净,实在令人惊奇。).

  29. It’s important to realize that program development is an incremental process, just like human learning. You can do as much analysis as you want, but you still won’t know all the answers when you set out on a project. You’ll have much more success—and more immediate feedback—if you start out to “grow” your project as an organic, evolutionary(进化的) creature, rather than constructing it all at once like a glass-box skyscraper.

  30. import java.util.*; classInstrument { publicvoid play() {} staticvoid tune(Instrument i) { // ... i.play(); } } // Wind objects are instruments // because they have the same interface: publicclass Wind extends Instrument { publicstaticvoid main(String[] args) { Wind flute = new Wind(); Instrument.tune(flute); // Upcasting } } ///:~ 6.7 Upcasting(向上转型) • The most important aspect of inheritance is not that it provides methods for the new class. It’s the relationship expressed between the new class and the base class. This relationship can be summarized by saying, “The new class is a type of the existing class.” The act of converting a Wind reference into an Instrument reference is called upcasting.

  31. Instrumnt Wind Why “upcasting”? • The reason for the term is historical, and based on the way class inheritance diagrams have traditionally been drawn: with the root at the top of the page, growing downward. (Of course, you can draw your diagrams any way you find helpful.) The inheritance diagram for Wind.java is then: Casting from a derived type to a base type (由导出类转型为基类)moves up on the inheritance diagram, so it’s commonly referred to as upcasting. Upcasting is always safe because you’re going from a more specific type to a more general type. That is, the derived class is a superset of the base class. It might contain more methods than the base class, but it must contain at least the methods in the base class. 导出类是基类的一个超集。

  32. 6.8 The final keyword • Java’s final keyword has slightly different meanings depending on the context, but in general it says “This cannot be changed.” You might want to prevent changes for two reasons: design or efficiency. Because these two reasons are quite different, it’s possible to misuse(误用) the final keyword. • The following sections discuss the three places where final can be used: for data, methods, and classes.

  33. 6.8.1 Final data 6.8.2 Final methods6.8.2 Final classes When you say that an entire class is final (by preceding its definition with the final keyword), you state that you don’t want to inherit from this class or allow anyone else to do so. In other words, for some reason the design of your class is such that there is never a need to make any changes(永远不需要), or for safety or security reasons you don’t want subclassing.

  34. //: c06:Jurassic.java// Making an entire class final.class SmallBrain {}finalclass Dinosaur {int i = 7;int j = 1; SmallBrain x = new SmallBrain(); void f() {} }//! class Further extends Dinosaur {}// error: Cannot extend final class 'Dinosaur‘publicclass Jurassic {publicstaticvoid main(String[] args) { Dinosaur n = new Dinosaur(); n.f(); n.i = 40; n.j++; } } ///:~

  35. 6.11 Summary • Despite the strong emphasis on inheritance in object-oriented programming, when you start a design you should generally prefer composition during the first cut and use inheritance only when it is clearly necessary. Composition tends to be more flexible. In addition, by using the added artifice of inheritance with your member type, you can change the exact type, and thus the behavior, of those member objects at run time. Therefore, you can change the behavior of the composed object at run time. • When designing a system, your goal is to find or create a set of classes in which each class has a specific use and is neither too big (encompassing so much functionality that it’s unwieldy to reuse) nor annoyingly small (you can’t use it by itself or without adding functionality).

  36. 7 Polymorphism(多态) • Polymorphism is the third essential feature of an object-oriented programming language, after data abstraction and inheritance. 你唱-- 我唱-- 大家唱-- 1 2 3 4

  37. // 动物排队import java.util.*;class Animal{ void showMsg(){} void move(){}}class Dog extends Animal{ void showMsg(){System.out.print("这是一只小狗!\t");}void move(){System.out.println("请站到左边队伍去.");}}class Cat extends Animal{ void showMsg(){System.out.print(" 这是一只小猫!\t");}void move(){System.out.println("请站到中间队伍去.");}}class Horse extends Animal{ void showMsg(){System.out.print(" 这是一只小马!\t");}void move(){System.out.println("请站到右边队伍去.");}}//随机产生一个动物class RandomGenAnimals{ private Random rand=new Random(); public Animal next(){switch(rand.nextInt(3)){ default:case 0: return new Dog();case 1: return new Cat();case 2: return new Horse();}}}public class Animals{ private static RandomGenAnimals gen=new RandomGenAnimals(); public static void main(String args[]){Animal dongwu[]=new Animal[10];for(int i=0;i<dongwu.length;i++) dongwu[i]=gen.next();for(int i=0;i<dongwu.length;i++){ dongwu[i].showMsg(); dongwu[i].move(); } }} public class Animals{ private static RandomGenAnimals gen=new RandomGenAnimals(); public static void main(String args[]){Animal dongwu[]=new Animal[10];for(int i=0;i<dongwu.length;i++) dongwu[i]=gen.next();for(int i=0;i<dongwu.length;i++){ dongwu[i].showMsg(); dongwu[i].move();

More Related