1、学习目标学习目标n理解多态性的概念n理解继承层次结构中对象间的关系n区分抽象类与具体类n抽象类和抽象方法的声明和使用n接口的声明和实现nfinal类和final方法n嵌套类的概念和使用n基本数据类型的包装类6.1 6.1 多态性概念和实例多态性概念和实例 n多态性(Polymorphism)n在超类中定义的属性或行为,被子类继承之后,可以具有不同的数据类型或表现出不同的行为。n这使得同一个属性或行为在超类及其各个子类中具有不同的语义。定义Shape s;s.draw(g);/s调用draw()方法,s指向对象不同会画出不同的图形(圆或矩形或三角形)n多态性也是泛指在程序中同一个符号在不同的情况
2、下具有不同解释的现象。Circledraw()draw()Triangle Rectangledraw()draw()Shapevoid draw();draw()draw()6.1 6.1 多态性概念和实例多态性概念和实例 6.1 多态性概念和实例(续)多态性概念和实例(续)n实现多态性的条件:n继承n抽象方法n引用Shape(抽象类)public abstract void draw();Circle public void draw()./画圆 Rectanglepublic void draw()./画矩型 Shape s;Circle c1=new Circle();Rectangl
3、e r1=new Rectangle();s=c1;s.draw();/画圆 s=r1;s.draw();/画矩型 6.2 继承层次结构中对象间的关系继承层次结构中对象间的关系n继承层次结构中的子类对象可以视为超类的对象,这样就可以将子类对象赋给超类变量。n然而,超类对象并不是其任何子类的对象,即不能将超类对象赋给子类引用。6.2 继承层次结构中对象间的关系(续)继承层次结构中对象间的关系(续)例如:Point3 point=new Point3(30,50);Circle4 circle=new Circle4(120,89,2.7);Point3 pointRef=circle;(允许)P
4、oint3 pointRef=new Circle4(120,12,0)(允许)pointRef.toString();/call Circle4.toString();pointRef=point;pointRef.toString()/call Point.toString();Circle circle=point;/不允许,编译出错 Circle4Point3与引用变量指向的对象相关n强制类型转换Point3 point=new Point3(30,50);Circle circle=(Circle)point;circle.getX();circle.getRadius();/run
5、-time error将point对象强制转换成Circle对象,circle.getX()语句是正确的,而circle.getRadius()语句在运行时会产生错误。因为circle引用指向的point对象无getRadius方法。例6-1:举例说明了继承层次结构中对象间的关系。6.2 继承层次结构中对象间的关系继承层次结构中对象间的关系(续)(续)/Point3.javapublic class Point3 private int x;/将超类中的成员变量x声明为private private int y;/将超类中的成员变量x声明为private public Point3()publ
6、ic Point3(int xValue,int yValue)x=xValue;y=yValue;public String toString()return +getX()+,+getY()+;/Circle3.javapublic class Circle3 extends Point3 private double radius;public Circle3()public Circle3(int xValue,int yValue,double radiusValue)super(xValue,yValue);/显式调用超类的构造方法 setRadius(radiusValue);.
7、public String toString()/调用超类的toString方法 return Center=+super.toString()+;Radius=+getRadius();/HierarchyRelationshipTest1.javaimport javax.swing.JOptionPane;public class HierarchyRelationshipTest1 public static void main(String args)Point3 point=new Point3(30,50);Circle3 circle=new Circle3(120,89,2.
8、7);String output=Call Point3s toString with superclass+reference to superclass object:n+point.toString();output+=nnCall Circle3s toString with subclass+reference to subclass object:n+circle.toString();Point3 pointRef=circle;/子类对象的引用赋给一个超类类型的变量 output+=nnCall Circle3s toString with superclass+referen
9、ce to subclass object:n+pointRef.toString();JOptionPane.showMessageDialog(null,output);System.exit(0);例6-2 超类对象的引用赋给一个子类类型的变量,引起错误。/HierarchyRelationshipTest2.javapublic class HierarchyRelationshipTest2 public static void main(String args)Point3 point=new Point3(30,50);Circle3 circle;circle=point;/超
10、类对象的引用赋给一个子类类型的变量,是不允许的。6.3 6.3 抽象类和抽象方法抽象类和抽象方法 n6.3.1 抽象类和具体类的概念 n6.3.2 抽象方法的声明 n6.3.3 抽象类的声明 n6.3.4 抽象类程序设计的举例 6.3.1 抽象类和具体类的概念抽象类和具体类的概念n抽象类抽象类abstract:每个抽象类抽象类中至少包含一个抽象方法。n抽象类只能作为继承层次结构中的超类,所以这些类称为抽象超类。不能实例化抽象类的对象。n抽象类的目的:提供一个合适的超类,以派生其他类。n具体类具体类concrete:用于实例化对象的类。这种类实现它们声明的所有方法所有方法。n抽象超类是一般类,它
11、们仅仅指定子类的共同点,并不创建出真实的对象。例如,如果我们要“绘制形状”,那我们将绘制什么形状呢?具体类为实例化对象提供了合理的细节。6.3.2 抽象方法的声明抽象方法的声明n用关键字abstract声明抽象方法:public abstract void draw();抽象方法并不提供实现。包含抽象方法的类必须声明为抽象类。抽象超类的所有具体子类都必须为超类的抽象方法提供具体实现。6.3.3 抽象类的声明抽象类的声明n使用关键字abstract声明抽象类。形如:public abstract class Shape.抽象类通常包含一个或多个抽象方法(静态方法不能为抽象方法)。n抽象超类不能实
12、例化。但可以使用抽象超类来声明引用变量,用以保存抽象类所派生的任何具体类的对象。程序通常使用这种变量来多态地操作子类对象。6.3.4 抽象类程序设计的举例抽象类程序设计的举例 例6-3 抽象类的程序设计示例该例子所使用到的类的层次结构如图6-1所示。类的层次以抽象超类Shape为开始,派生出Point类,然后由Point类派生出Circle类,再由Circle类派生出Cylinder类。其中Shape以斜体字出现表示它是抽象类。图6-1 Shape类的层次结构/Shape.javapublic abstract class Shape extends Object /定义Shape为抽象类 p
13、ublic double getArea()return 0.0;public double getVolume()return 0.0;public abstract String getName();/定义getName为抽象方法/Point.javapublic class Point extends Shape private int x;private int y;public Point()public Point(int xValue,int yValue)x=xValue;y=yValue;.public String getName()/覆盖覆盖Shape类中的类中的getN
14、ame方法方法 return Point;public String toString()return +getX()+,+getY()+;/Circle.javapublic class Circle extends Point private double radius;public Circle()public Circle(int x,int y,double radiusValue)super(x,y);setRadius(radiusValue);.public String getName()return Circle;public String toString()return
15、 Center=+super.toString()+;Radius=+getRadius();/Cylinder.javapublic class Cylinder extends Circle private double height;public Cylinder()public Cylinder(int x,int y,double radius,double heightValue)super(x,y,radius);setHeight(heightValue);.public String getName()return Cylinder;public String toStrin
16、g()return super.toString()+;Height=+getHeight();/AbstractInheritanceTest.javaAbstractInheritanceTest.javapublic class AbstractInheritanceTest public class AbstractInheritanceTest public static void main(String args)public static void main(String args)DecimalFormat twoDigits=new DecimalFormat(0.00);D
17、ecimalFormat twoDigits=new DecimalFormat(0.00);Point point=new Point(7,11);Point point=new Point(7,11);Circle circle=new Circle(22,8,3.5);Circle circle=new Circle(22,8,3.5);Cylinder cylinder=new Cylinder(20,30,3.3,10.75)Cylinder cylinder=new Cylinder(20,30,3.3,10.75);String output=String output=poin
18、t.getName()point.getName()+:+:+point point+n+n+circle.getName()circle.getName()+:+:+circle circle+n+n+cylinder.getName()cylinder.getName()+:+:+cylindercylinder+n;+n;Shape arrayOfShapes=new Shape 3;Shape arrayOfShapes=new Shape 3;/声明声明ShapeShape类型的数组类型的数组 arrayOfShapes 0 =pointarrayOfShapes 0 =point;
19、/将将PointPoint对象的引用对象的引用pointpoint赋给赋给ShapeShape类型的数组元素类型的数组元素1 1 arrayOfShapes 1 =circle;arrayOfShapes 1 =circle;/将将CircleCircle对象的引用对象的引用circlecircle赋给赋给ShapeShape类型的数组元素类型的数组元素2 2 arrayOfShapes 2 =cylinderarrayOfShapes 2 =cylinder;/将将CylinderCylinder对象的引用对象的引用cylindercylinder赋给赋给ShapeShape类型的数组元素类
20、型的数组元素3 3for(int i=0;i arrayOfShapes.length;i+)for(int i=0;i arrayOfShapes.length;i+)output+=nn+output+=nn+arrayOfShapes i.getName()arrayOfShapes i.getName()+:+:+arrayOfShapes i.toString()arrayOfShapes i.toString()+nArea=+nArea=+twoDigits.format(+twoDigits.format(arrayOfShapes i.getArea()arrayOfShap
21、es i.getArea()+nVolume=+nVolume=+twoDigits.format(+twoDigits.format(arrayOfShapes i.getVolume()arrayOfShapes i.getVolume(););JOptionPane.showMessageDialog(null,output);JOptionPane.showMessageDialog(null,output);6.4 接口的声明和实现接口的声明和实现 n6.4.1 接口的概念 n6.4.2 接口的声明n6.4.3 接口的实现n6.4.4 接口的程序设计举例 6.4.1 接口的概念接口的
22、概念n接口:用于声明一组类的公共操作的接口。n接口由常量和一组抽象方法组成。接口中不包括变量和有具体实现的方法。接口只是声明了功能是什么(方法头),而并没有定义如何实现这个功能,功能的实现(即方法体)是在继承这个接口的各个子类中完成的.n接口支持多重继承,nJava把对接口功能的继承称为“实现(implement)”。n接口与抽象类到底有什么区别:(1)接口不能实现任何方法,而抽象类可以。(2)类可以实现许多接口,但只有继承一个父类。(3)接口不是类分级结构的一部分,没有联系的类可以实现相同的接口。6.4.1 接口的概念(续)接口的概念(续)6.4.2 接口的声明接口的声明n定义接口的一般格式
23、如下:public interface 接口名 extends 父接口名列表 /常量声明 public final static 类型 变量名=常量值;/抽象方法声明 public abstract 返回类型 方法名(参数列表);接口支持多重继承:public interface Shape public final static double PI=3.1416;public abstract void draw(Graphics g);6.4.2 接口的声明接口的声明(续续)6.4.3 接口的实现接口的实现n为了声明一个类来实现一个接口,在类的声明中要包括一条implements语句。cl
24、ass ClassName extends ParentClass implements interface1,interface2 /接口中方法的实现6.4.4 接口的程序设计举例接口的程序设计举例该例子中各类之间的层次关系如图6-1,仅仅区别在于用接口Shape替代了抽象超类Shape。例6-4接口程序设计示例public interface Shape /声明了Shape接口 public double getArea();/声明getArea方法 public double getVolume();/声明getVolume方法 public String getName();/声明ge
25、tName方法Shape类的层次结构/Point.javapublic class Point extends Object implements Shape private int x;private int y;public Point()public Point(int xValue,int yValue)x=xValue;y=yValue;.public double getArea()/实现Shape接口中的getArea方法 return 0.0;public double getVolume()/实现Shape接口中的getVolume方法 return 0.0;public S
26、tring getName()/实现Shape接口中的getName方法 return Point;public String toString()/覆盖Object类中的toString方法 return +getX()+,+getY()+;/Circle.javapublic class Circle extends Point private double radius;public Circle()public Circle(int x,int y,double radiusValue)super(x,y);setRadius(radiusValue);.public double g
27、etArea()public double getArea()/覆盖超类中的覆盖超类中的getAreagetArea方法方法return Math.PI return Math.PI*getRadius()getRadius()*getRadius();getRadius();public String getName()public String getName()/覆盖超类中的覆盖超类中的getNamegetName方法方法return Circle;return Circle;public String toString()public String toString()/覆盖超类中的覆
28、盖超类中的toStringtoString方法方法 return Center=+super.toString()+;Radius=return Center=+super.toString()+;Radius=“+getRadius();+getRadius();/Cylinder.javapublic class Cylinder extends Circle private double height;public Cylinder()public Cylinder(int x,int y,double radius,double heightValue)super(x,y,radius
29、);setHeight(heightValue);.public double getArea()public double getArea()/覆盖超类中的覆盖超类中的getAreagetArea方法方法 return 2 return 2*super.getArea()+getCircumference()super.getArea()+getCircumference()*getHeight();getHeight();public double getVolume()public double getVolume()/覆盖超类中的覆盖超类中的getVolumegetVolume方法方法
30、 return super.getArea()return super.getArea()*getHeight();getHeight();public String getName()public String getName()/覆盖超类中的覆盖超类中的getNamegetName方法方法 return Cylinder;return Cylinder;/InterfaceTest.javapublic class InterfaceTest public static void main(String args)DecimalFormat twoDigits=new DecimalFor
31、mat(0.00);Point point=new Point(7,11);Circle circle=new Circle(22,8,3.5);Cylinder cylinder=new Cylinder(20,30,3.3,10.75);String output=point.getName()+:+point+n+circle.getName()+:+circle+n+cylinder.getName()+:+cylinder+n;Shape arrayOfShapes=new Shape 3;arrayOfShapes 0 =point;arrayOfShapes 1 =circle;
32、arrayOfShapes 2 =cylinder;for(int i=0;i arrayOfShapes.length;i+)output+=nn+arrayOfShapes i.getName()+:+arrayOfShapes i.toString()+nArea=+twoDigits.format(arrayOfShapes i.getArea()+nVolume=+twoDigits.format(arrayOfShapes i.getVolume();.6.5 final方法和方法和final类类 n常量常量:变量声明为final,说明该变量是常量,不能在声明后进行修改,并且在声明
33、时必须对它进行初始化。nfinal方法方法:方法的声明中有final。n子类不能重载超类中声明为final的方法。n因为子类不可能重载private方法,所以声明为private的方法隐式地为final方法。n声明为static的方法也隐式地为final方法,因为只能重载非静态方法。nfinal类类:类的声明中包含final。final类不能为超类。nfinal类中所有方法都隐式地为final方法。String类是final类的一个例子。不能扩展该类,使用字符串的程序可以调用String对象在Java API中指定的函数。将类声明为final还可以防止程序员创建绕过安全限制的子类。6.6 嵌套
34、类嵌套类 n6.6.1 内部类的概念n6.6.2 内部类的声明n6.6.3 匿名内部类声明n6.6.4 嵌套类的程序设计举例6.6.1 内部类的概念内部类的概念n嵌套在其它类里面的类称为内部类(inner class)。n外层的类成为外部类(outer class).n内部类主要用于事件处理。6.6.2 内部类的声明内部类的声明n内部类的声明格式如下:修饰符 class outerClass修饰符 class innerClass例子6-5 内部类使用的例子 TestWindow.java 程序的显示界面使用javax.swing包中的JFrame类生成。定义扩展JFrame的子类TestWi
35、ndow.程序运行输出结果如下:import java.awt.*;import java.awt.event.*;import javax.swing.*;private public class TestWindow extends JFrame private JLabel aLabel;private JTextField aField,displayField;private JButton computeButton,exitButton;public TestWindow()/set up GUI /call JFrame constructor to set title bar
36、 string super(内部类的使用:计算一个数的平方);/use inherited method getContentPane to get windows content pane Container container=getContentPane();container.setLayout(new FlowLayout();/change layout aLabel=new JLabel(输入一个整数:);aField=new JTextField(10);container.add(aLabel);container.add(aField);displayField=new J
37、TextField(30);displayField.setEditable(false);container.add(displayField);computeButton=new JButton(计算平方);container.add(computeButton);exitButton=new JButton(退出);container.add(exitButton);/create an instance of inner class ActionEventHandler ActionEventHandler handler=new ActionEventHandler();comput
38、eButton.addActionListener(handler);/register computeButton event handler /register exitButton event handler exitButton.addActionListener(handler);setSize(400,140);setVisible(true);/end constructor public static void main(String args)TestWindow window=new TestWindow();/end main/inner class declaratio
39、n for handling JButton eventsinner class declaration for handling JButton events private class ActionEventHandler implements ActionListener private class ActionEventHandler implements ActionListener /method to handle action events/method to handle action events public void actionPerformed(ActionEven
40、t event)public void actionPerformed(ActionEvent event)if(event.getSource()=exitButton)if(event.getSource()=exitButton)System.exit(0);System.exit(0);else if(event.getSource()=computeButton)else if(event.getSource()=computeButton)String a=aField.getText();String a=aField.getText();int ai=Integer.parse
41、Int(a);int ai=Integer.parseInt(a);ai=ai ai=ai*ai;ai;String b=String.valueOf(ai);String b=String.valueOf(ai);displayField.setText(a+displayField.setText(a+的平方是的平方是:+:+b);b);/end method actionPerformed/end method actionPerformed /end inner class ActionEventHandler/end inner class ActionEventHandler /e
42、nd class TestWindow/end class TestWindow在组件上打回车键激发ActionEvent事件,调用actionPerformed方法的执行 /event.getSource():返回用户正在交互的GUI组件名 6.6.3 匿名内部类声明匿名内部类声明n匿名内部类:是指定义的内部类没有类名,所以当程序中使用匿名内部类时,在定义匿名内部类的地方创建该类的一个对象。匿名内部类的声明格式如下:new InterfaceName()/define inner classnew ParentName()/define inner classclass 无名类 implem
43、ents Interfacename new 无名类()class 无名类 extends ParentName new 无名类()例子:TestWindow1.java (新)computeButton.addActionListener(new ActionListener()public void actionPerformed(ActionEvent event)String a=aField.getText();int ai=Integer.parseInt(a);ai=ai*ai;String b=String.valueOf(ai);displayField.setText(a+
44、的平方是的平方是:+b);/end method actionPerformed );ActionEventHandler handler=new ActionEventHandler();computeButton.addActionListener(handler);/register computeButton event handler class ActionEventHandler implements ActionListener class ActionEventHandler implements ActionListener public void actionPerfor
45、med(ActionEvent event)public void actionPerformed(ActionEvent event)./end method actionPerformed/end method actionPerformed /end inner class ActionEventHandler/end inner class ActionEventHandler /end class TestWindow/end class TestWindow computeButton.addActionListener(new ActionEventHandler();/regi
46、ster exitButton event handler exitButton.addActionListener(new ActionListener()public void actionPerformed(ActionEvent event)System.exit(0);/terminate the application /end method actionPerformed );6.6.4 嵌套类的程序设计举例嵌套类的程序设计举例该程序包含两个文件Time.java和TimeTestWindow.java。Time.java文件定义了一个Time类。TimeTestWindow.j
47、ava文件中定义了一个内部类ActionEventHandler和一个匿名内部类。通过内部类和匿名内部类来处理用户对时间的设置事件。hourField=new JTextField(10);hourField.addActionListener(new ActionListener()public void actionPerformed(ActionEvent event).);n在声明和使用嵌套类时,应该注意以下事项:(1)包含嵌套类的类在编译时,将为每个类产生单独的.class文件。嵌套类文件名为OuterClassName$InnerClassName.class。匿名内部类的文件名为
48、OuterClassName$#.class,#从1开始,编译时,每遇到一个匿名内部类,#递增1。(2)带有名称的内部类可以声明为public、protected、包访问或private,并且它们的使用限制与其他类成员相同。(3)内部类能以OuterClassName.this的形式访问其外部类的this引用。(4)外部类负责创建内部类的对象。为创建另一个类的内部类对象,首先创建该外部类的一个对象,并将该对象的引用赋给外部类类型的变量(我们假设它是outref)。然后使用如下形式创建内部类的对象:OuterClassName.InnerClassName innerRef=outref.new
49、 InnerClassName();(5)静态嵌套类不需创建外部类的对象,静态嵌套类不能访问外部类的非静态成员。6.6.4 嵌套类的程序设计举例(续)嵌套类的程序设计举例(续)6.7 基本数据类型的包装类基本数据类型的包装类 n在Java中,类型分成两类:基本类型和引用类型。n每个基本类型都有一个相应的位于java.lang包中的包装类。每个包装类使你能够像操作对象一样操作基本类型。n基本类型:boolean、char、byte、short、int、long、float和doublen对应的包装类:Boolean、Char、Byte、Short、Integer、Long、Float和Doubl
50、e。n每个包装类均声明为final,因此它们的方法隐式地为final方法,并且不能重载这些方法。许多处理基本类型的方法一般声明为类型包装类的静态方法。如果程序需要操作基本类型的值,可以通过类名来调用这些静态方法。6.7 基本数据类型的包装类(续)基本数据类型的包装类(续)例如,以下代码是将一个字符串转变为一个double值:String str=”28.8”;number1=Double.parseDouble(str);其中parseDouble为Double类型包装类的一个静态方法,我们直接通过类名.静态方法名来进行调用。将str这个参数中的字符串转变为Double型的数据。小结小结 n多