面向对象 多态
为什么需要多态?
说的模糊一点留点想象空间,
就是在做之前,不要把话说死,说的模糊一点想象空间大一点,真做的时候再具体化。在国家层面也有,叫“模糊战略”。
如何实现多态?
java中如何实现多态?使用多态的好处?
引用变量的两种类型:
编译时类型(模糊一点,一般是一个父类)
由声明时的类型决定。
运行时类型(运行时,具体是哪个子类就是哪个子类)
由实际对应的对象类型决定。通过动态绑定调用该对象的方法。动态绑定会使我们的程序编写更加灵活,但是会减慢程序运行速度。这也是JAVA比C++/C慢的主要原因之一。
多态:如果编译时类型和运行时类型不一致,就会造成多态。
多态性是OOP中的一个重要特性,主要是用来实现动态联编的,换句话说,就是程序的最终状态只有在执行过程中才被决定而非在编译期间就决定了。这对于大型系统来说能提高系统的灵活性和扩展性。
多态可以让我们不用关心某个对象到底是什么具体类型,就可以使用该对象的某些方法,从而实现更加灵活的编程,提高系统的可扩展性。
多态的使用要点
要点:
多态是方法的多态,属性没有多态性。
编写程序时,如果想调用运行时类型的方法,只能进行类型转换。不然通不过编译器的检查。但是如果两个没有关联的类进行强制转换,会报:ClassCastException。 比如:本来是狗,我把它转成猫。就会报这个异常。
多态的存在要有3个必要条件:要有继承,要有方法重写,父类引用指向子类对象
对象的转型(casting)
为什么需要强制转换类型?
引用变量只能调用它编译类型的方法,不能调用它运行类型的方法。这时,我们就需要进行类型的强制转换!
³ 一个父类的引用类型变量可以“指向”其子类的对象。
³ 一个父类的引用不可以访问其子类对象新增加的成员(属性和方法)。
³ 可以使用 引用 变量 instanceof 类名 来判断该引用型变量所“指向”的对象是否属于该类或该类的子类。
³ 子类的对象可以当作基类的对象来使用称作向上转型(upcasting),反之称为向下转型(downcasting)
final
修饰变量: 被他修饰的变量不可改变。一旦赋了初值,就不能被重新赋值。 修饰成员变量:
修饰局部变量: //final修饰局部变量的初始化 final int gg = 20; final int hh; hh=50;
final修饰的是引用变量时,只是引用值不能改变。对应的对象内部的属性仍然可变。 final Dog dog = new Dog(); // dog = new Dog(); //报错! dog.age = 77; //仍然可以修改dog指向对象的属性 常量的命名: 一般不用驼峰写法,而是全部大写加下划线分割。比如: final int DOG_AGE=18; |
public class Test { static final int a; //常量要进行初始化,如果采用系统默认值的话,就失去了存在的意义。 //因此必须显式初始化,可以直接赋值或初始化块中或构造函数中。 //但只能赋值一次! final int b; final int c; final int d=19; static { a=3; }
{ c=50; }
public Test() { // TODO Auto-generated constructor stub b=20; }
public static void main(String[] args) { //final修饰局部变量的初始化 final int gg = 20; final int hh; hh=50;
//final修饰引用变量时,只是引用值不能改变。对应的对象内部的属性仍然可变。 final Dog dog = new Dog(); // dog = new Dog(); //报错! dog.age = 77; //仍然可以修改dog指向对象的属性
} } |
修饰方法: 该方法不可被子类重写。但是可以被重载! 在上面Animal、Dog、Cat中,Animal中的shout方法中增加final。则Dog和Cat中shout方法不能存在了!
如果父类方法是private final,那么对子类完全不可见;子类也就可以定义自己的同名的方法。这个不是重写了,而是子类自己新定义的方法。 |
|
修饰类: 修饰的类不能有子类,不能被继承。比如:Math、String。 |
|
抽象类
为什么需要抽象类? 如何定义抽象类?
是一种模版模式。抽象类为所有子类提供了一个通用模版,子类可以在这个模版基础上进行扩展。 通过抽象类,可以避免子类设计的随意性。 比如我们上面设计的:Animal、Dog、Cat类。Dog类能不能不重写shout方法呢? 是可以的。没有严格规定必须重写shout方法。对不对?事实上,像shout这样的方法,每个动物的叫声都是不一样的,所以最好把它的实现交给特定的子类来做。 有人说,我能不能在Animal类提供一个shout方法的空实现。但是,子类仍然是可重写、也可不重写该方法。因此,自由度还是比较大。就是说,父类的模版对子类没有严格的限制。 通过抽象类,我们就可以做到严格限制子类的设计,使子类之间更加通用。代码如下: abstract class Animal { abstract void shout(); } class Dog extends Animal { void shout() { // TODO Auto-generated method stub System.out.println("旺旺旺!"); }
}
|
package object;
public class Test { public static void main(String[] args) { Animal animal = new Animal(); //抽象类不能new,但是可以作为引用类型。
} }
abstract class Animal { abstract void shout();
} class Dog extends Animal {
@Override void shout() { // TODO Auto-generated method stub System.out.println("旺旺旺!"); }
void aa(){ System.out.println("aaaa"); } }
|
抽象类的使用要点
有抽象方法的类只能定义能抽象类
抽象类不能实例化,及不能用new来实例化抽象类。
抽象类可以包含属性、方法、构造方法。但是构造方法不能用来new实例,只能用来被子类调用。
抽象类只能用来继承。
抽象方法必须被子类实现。
抽象类和普通父类的区别,就在于包含抽象方法,抽象方法必须被子类实现,从而可以对子类的设计进行规范。抽象类的作用说白了就是:
实现了规范和具体实现的分离。通过abstract方法定义规范,然后要求子类必须定义具体实现。引用变量仍然可以定义为抽象类,这样就可以规范地实现多态了。