今天我们来讲解面向对象部分的最后一块知识点。
先来讲讲面向对象语言的第三大特征——多态。
多态
多态就是 (同一个父类类型) 父类可以表示任意的子类对象
同一种事务,在不同时刻表现不同的状态.
实现多态条件:
1.要有继承,父类可以表示子类,他们之间是有关系的。
2.要有重写(特指的抽象的方法), 重写过来后,调用的就是子类自己的方法实现。
3.父类引用指向子类对象。
简单来说呢,多态用的最多的一种表现是当编译期类型是父类,运行期类型是子类时,被称为父类引用指向子类对象。
代码如下:
class Animal{ }
class Cat extends Animal{ }
Animal cat =new Cat();
Animal 的引用指向Cat的对象。
除此之外呢,还有在多态环境下三种不同的使用。
第一种
是多态环境下对成员方法的调用:
class Animal{
void show() {
System.out.println(“Anmial");
}
}
class Cat extends Animal{
void show() {
System.out.println(“cat");
}
}
/以下是在主方法中运行
Animal x = new Cat()
x.show()
运行之后我们会惊奇的发现x.show()方法居然打出来的是cat。
这里我们就要先讲一下编译期间和运行期间了。
编译期间正是指的是我们在敲代码的时候。
而运行期间顾名思义指的是在运行代码的时候。
在多态环境下 编译期间 类型是父类类型,调用的是父类中定义的方法。
运行期间, 运行时指向的是具体的子类对象,运行时调用的是子类的方法。
所以总而言之,在多态环境下对成员方法的调用,就是编译期间看左边,运行期间看右边。
第二种
多态环境下对静态成员方法的调用
class Animal{
static void show() {
System.out.println(“Animal");
}
}
class Cat extends Animal {
static void show() {
System.out.println(“Cat");
}
}
//以下是主方法使用
Animal x = new Cat()
x.show()
这里的x.show()调用的是Animal类中的静态方法,总结一下就是编译期间和运行期间都看左边。
第三种
多态环境下对成员变量的调用
同第二种,编译和运行期间都看左边。
方法参数具有多态性
abstract public class Animal {
abstract public void eat();
public void feedanimal(Animal animal){
animal.eat();
}
}
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃饭");
}
}
public class Text extends Dog {
public static void main(String[] args) {
Text text=new Text();
Animal dog=new Dog();
text.feedanimal(dog);
}
}
这段代码之中,方法的形式参数类型是父类类型,而传递的实际参数可以是任意子类的对象。此点正是展现了方法参数多态性的好处:提高代码的扩展性。
多态性的向上转型和向下转型
其实向上转型和向下转型我们之前就接触过,只是没有见过这种字眼。举个例子就像之前的基础类型转换。小字节向大字节转换就是向上转型,而大字节向小字节转换就是向下转型。
其实多态性中的向上转型和向下转型很简单。
向上转型:其实就像之前代码中的Animal dog=new Dog();这一句就是向上转型,是子类类型自动转为父类类型。
向上转型的作用是:提高程序的扩展性。
向下转型:向下转型的作用是:为了使用子类中的特有方法。众所周知,子类可以使用父类中的方法,而父类无法使用子类的方法。我们只有向下转型了之后才能使父类使用子类中的方法。
具体用法如同数据转换中的强制转换。
public class Animal{
}
public class Dog extends Animal{
public void run(){
System.out.println("狗在跑")
}
public class Text{
public static void main(String[] args){
Animal animal=new Animal();
Dog dog=(Dog)animal;
dog.run();
}
final关键字
final可以修饰类, 属性,方法
修饰类: 不能被定义为抽象类或是接口,不可被继承。 例如String
修饰方法: final修饰的方法不能被子类重写
修饰属性:定义就必须直接赋值或者在构造方法中进行赋值,并且后期都不能修改。
其中final属性赋值也有几条说明
1.在声明时同时赋值,往往与static一起使用。
2.声明时不赋值,必须在构造方法中逐一赋值。
总而言之,保证创建每一个对象的时候,final属性的值是确定的。
最后,对参数进行final修饰,可以有效的防止数据在方法体中被修改。
接口
从本质上讲,接口是一种特殊的抽象类,这种抽象类中包含抽象方法。
我们先来浅浅的认识一下接口。
接口的定义:使用 interface 关键字用来声明一个接口。
[访问修饰符] interface 接口名称 [extends 其他的接口名1,….其他的接口名n]
{
// 声明常量 抽象方法 静态方法 默认方法
}
接口的使用:类使用implements关键字实现接口。在类声明中,Implements关键字放在class声明后面。
[访问修饰符] class 类名 implements 接口名1,接口名2……{ }
结合继承:
[访问修饰符] class 类名 extends 父类名 implements 接口名1,接口名2……{ }
话不多说,上代码 。
public interface Myinterface {
void eat();
void fly();
}
public class InterfaceDemo implements Myinterface{
@Override
public void eat() {
System.out.println("正在吃饭");
}
@Override
public void fly() {
System.out.println("正在起飞");
}
public static void main(String[] args) {
InterfaceDemo interfaceDemo=new InterfaceDemo();
interfaceDemo.eat();
interfaceDemo.fly();
}
}
这里讲几个接口的注意事项
1.接口中定义成员变量,默认是静态常量。
2.接口中定义的无方法体的方法,默认抽象方法。
3.jdk8之后添加了静态方法,默认方法。
再就是接口的特性:
1.接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字
2.接口中方法可以是抽象的,静态的,默认的
3.接口中声明的属性默认为 public static final 的
4.接口不是被类继承了,而是要被类实现
5.接口不能实例化对象
6.与继承关系类似,接口与实现类之间存在多态性
7.一个接口能继承其它多个接口
8.当类实现接口的时候,类要实现接口中所有的抽象方法。否则,类必须声明为抽象的类。
总算我们结束了面向对象方面的学习。大家要好好的理解对象与对象好好相处。因为这是java的一大特色。最后,记得多做练习。