您的位置:首页 > 编程语言 > Java开发

Java初识继承和多态

2017-11-22 20:18 295 查看
以前学C的时候没学好类和对象,导致对继承和多态更是不了解。现在就趁着学Java的机会重新好好学这部分的内容。

我们知道,面向对象程序设计的三个特点是封装、继承和多态。

1、封装:定义类即为对数据的封装。

2、继承:子类从父类继承可访问的数据域和方法,还可以添加一些新的方法和数据域域以满足新的需求。因此继承的好处就是代码复用。

判断是否需要继承:"is-a"关系是继承的一个明显特征。里氏替换原则定义:继承必须确保超类所拥有的性质在子类中仍然成立。即当一个子类的实例应该能够替换任何其超类的实例时,它们之间才具有is-a关系。

因此在通过扩展超类定义子类时仅需指出子类与超类的不同之处。在设计类时,应该将通用的方法放到超类中,而将具有特殊用途的方法放到子类中。

此外,要注意Java中不允许多重继承,一个类只可能来自一个父亲,即单一继承

3、多态:父类对象的地方都可以使用子类的对象,就意味着父类型的变量可以引用子类型的对象。

动态绑定:程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定。因为在程序运行时才确定具体的类(对象的实际类),而调用哪个方法是由实际类型决定的。这样不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,让程序可以选择多个运行状态。

下面是用来进行测试的代码:

public class Text {
public static void main(String[] args) {
Triangle t=new Triangle(1,1.5,1);
t.setColor("yellow");
t.setFilled(true);
System.out.println(t.getArea());
System.out.println(t.getPerimeter());
System.out.println(t.getColor());
System.out.println(t.isFilled());
Circle c=new Circle(1);
c.setColor("yellow");
c.setFilled(true);
System.out.println(c.toString());
}
}
class GeometricObject{
private String color;
private boolean filled;
private java.util.Date dateCreated;
GeometricObject(){
dateCreated=new java.util.Date();//!!!attention
}
GeometricObject(String color,boolean filled){
this.color=color;
this.filled=filled;
dateCreated=new java.util.Date();
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color=color;
}
public boolean isFilled() {
return filled;
}
public void setFilled(boolean filled) {
this.filled=filled;
}
public java.util.Date getDateCreated(){
return dateCreated;
}
public String toString() {
return "Created on "+dateCreated+"\nColor : "+color+" and filled : "+filled;
}
}
class Triangle extends GeometricObject{
private double side1;
private double side2;
private double side3;
Triangle(){
this(1.0,1.0,1.0);
}
Triangle(double side1,double side2,double side3){
this.side1=side1;
this.side2=side2;
this.side3=side3;
}
public double getSide1() {
return side1;
}
public double getSide2() {
return side2;
}
public double getSide3() {
return side3;
}
public double getArea() {
double p=(side1+side2+side3)/2;
return Math.sqrt(p*(p-side1)*(p-side2)*(p-side3));
}
public double getPerimeter() {
return side1+side2+side3;
}
public String toString() {
return "Triange : side1 = "+side1+"side2 = "+side2+" side3 = "+side3;
}
}
/*class Circle extends GeometricObject{
private double radius;
Circle(){
}
Circle(double radius){
this.radius=radius;
}
Circle(double radius,String color,boolean filled){
//super(color,filled);//attention:must be the first statement
this.radius=radius;
this.setColor(color);//!!!attention:cannot use ’ this.color=color’
this.setFilled(filled);
}
public double getRadius() {
return radius;
}
public String toString() {
return "Created on "+this.getDateCreated()+"\nColor : "+this.getColor()+" and filled : "+this.isFilled();
}
}*/
先分析一下代码,其中有几个地方要特别注意(从上至下有标注的地方):

1、GeometricObject类的每个构造方法中,都要记得初始化dateCreated。这一点很容易漏掉,特别是两个参的构造函数中会以为没有其他的数据域需要初始化。

2、super(color,filled);这句话一定要是构造方法的第一条语句!否则会引起语法错误。

这里就涉及到super关键字。它有两种用途,调用父类的构造方法和调用父类的方法,我们一般只用前面一种。因为父类的构造方法不被子类继承,只能在子类的构造方法中用关键字super调用。注意:构造方法可以调用重载的构造方法或它的父类的构造方法,但如果它们都没有被显式地调用,编译器会自动将super()作为构造方法的第一条语句。因此又牵扯到了构造方法链:构造一个类的实例时,将会调用沿着继承链的所有父类的构造方法。当构造一个子类对象时,子类构造方法会在完成自己任务之前,首先调用它父类的构造方法。

3、this.setColor(color);这句话要小心,很容易写成this.color=color;,但这是错的。父类中的私有数据域不能被除了本类之外的其他任何类访问。唯一读取和改变它们的方法就是get和set方法。

最后补充一点:

要十分注意对象转换,特别是需要进行显式转换的地方,括号别漏加错加(其他例子可见ArrayList那篇文章中的代码)。

例如:Object o=new Student(); Student b=o; 会发生编译错误->改为Student b=(Student)o;

因为向下转换(父类到子类)必须使用显式转换向编辑器表明意图。

此外,为了要保证转换成功,在尝试转换之前要确保该对象是另一个对象的实例(用运算符instanceof实现):

Object myObject=new Circle();
//...
if(myObject instanceof Circle)
System.out.println(((Circle)myObject).getRadius());
//...
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java