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

Java(2):Java SE疯狂复习之多态

2016-12-21 16:48 190 查看

0. 引言

一鼓作气,再而衰,三而竭。要考研了,好好复习。(为什么别人考研,我这么紧张?)
Review:Java SE疯狂复习第1篇
据说,多态虽然用得不多(估计是低端码农们用得不多了,要设计什么大型兼容通用的框架的话,还是用一用有利于团队合作和开发),
但是,它在OOP程序员应聘的时候,却占有核心地位。
所以,本文就花了很大的篇幅和笔墨,来总结多态现象。
同样的,因为借鉴了太多别人的东西,所以文章类型就选为”转载“了。

1. 多态

OOP的核心,多态(polymorphism )。

1. 多态性:访问子类可以通过访问父类:(不是很能理解他在说什么)【尽快查证】
Animal cat =new Cat();
Animal dog =new Dog();
2. 在使用多态的时候,如果有使用覆盖函数,那么被覆盖的方法(即是父类中的的那个相应的方法)是要存在的。
3.  多态:一个引用(类型)在不同情况下的多种状态,可使代码更加灵活
4. java允许父类的引用变量引用它子类的实例,是自动完成的

这里先放上一个经典案例。

/**
* 功能演示:多态的演示
* 如果子类重写了父类的方法,
* 如果   父类  变量=new 子类
*     变量.方法    // 如果这个方法子类重写了则调用子类的方法,
*     如果没有重写则调用父类的方法
*/

package com.qcy.test;

public class Polymorphism_eg_1 {

/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
/*	Cat cat=new Cat();
cat.cry();
Dog dog=new Dog();
dog.cry();
Animal an=new Cat();   //多态即定义一个父类的变量指向子类
an.cry();
an.eat();
an=new Dog();
an.cry();
an.eat(); */
Animal an = new Animal();
an.eat();
an.cry();

Master master=new Master();
master.feed(new Dog(), new Bone());  //多态
master.feed(new Cat(), new Fish());

}

}
class Food
{
String name;
public void showName()
{

}
}
class Fish extends Food
{
public void showName()
{
System.out.println("鱼");
}
}
class Bone extends Food
{
public void showName()
{
System.out.println("骨头");
}
}
//主人来
class Master
{
//给动物喂食物
public void feed(Animal an, Food f)
{
an.eat();
f.showName();
}
}
//动物类Animal
class Animal
{
String name;
int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//动物会叫
public void cry()
{
System.out.println("不知道怎么叫");
}
public void eat()
{
System.out.println("我不到吃什么");
}

}
class Dog extends Animal
{
public void cry()
{
System.out.println("汪汪叫");
}
public void eat()
{
System.out.println("狗喜欢吃骨头");
}

}
class Cat extends Animal
{
public void cry()
{
System.out.println("喵喵叫");
}
public void eat()
{
System.out.println("猫喜欢吃鱼");
}
}

运行结果是这样的。
我不到吃什么 // Animal父类的方法eat; 父类很抽象(共性),并不知道有什么特性。多态是由其子类的特性体现出来的(late binding, dynamic binding)。
不知道怎么叫 // 父类的方法cry;
狗喜欢吃骨头 // Dog继承了父类Animal,并根据狗这个class的特性,override了父类的方法eat;
骨头 // Bone继承了父类Food,并根据骨头这个class的特性,override了父类的方法;
猫喜欢吃鱼 // Cat继承了父类Animal,并根据猫这个class的特性,override了父类的方法eat;

注意。居然可以这样写。父类 变量名 = new 子类。(如果C++要实现多态的话,恐怕要用ref或pointer,再加virtual function了)
在上面,标红的文字,都是对”多态性“的描述。

2. 抽象类

1. 父类方法的不确定性,用抽象类修饰这个方法,abstract。
2. 抽象类还是可以一样被继承
3. 当一个类继承的类是抽象的类时候,就要把抽象类中的所有的抽象方法全部方法实现
4. 用abstract关键词来修饰的时候,一定是抽象类和抽象方法
5. 在使用中不多,公司笔试的时候考很多
6. 抽象类不能被实例化,只有被继承以后再去实例化
7. 抽象类不一定要包含abstract方法,但就算没有abstract方法,也不能实例化它
8. 一旦类包含了abstract方法,这个类必须声明为abstract
9. 抽象方法不能有主体“{ }”
看起来,和第1大点里,Animal那个例子很类似。
注意区别!
abstract class Animal
{
String name;
int age;
abstract public void cry();

}
//当一个类继承的类是抽象的类时候,就要把抽象类中的所有的抽象方法全部方法实现
class Cat extends Animal
{
public void cry()
{
//do nothing
System.out.println("喵喵叫");

}
}


3. 接口与抽象接口

java不允许多继承。如果想要实现多继承的效果,可以去实现多个接口。接口已经是抽象的了(已经不能被实例化了),那抽象接口是什么?(暂时还没有体会)有点像C++里的虚函数和纯虚函数(虚基类)。【有待对比】
据某人的笔记,10. 接口就是给出一些没有内容的方法,封装到一起,到某个类要使用的时候,再根据具体情况把这些方法写出来。举个例子。
Person接口。
/**
*
*/
package com.qcy.inter;

/**
* @author qcy
*
*/
public interface PersonInter {

void speaking();

}
Student类。
/**
*
*/
package com.qcy.test;

import com.qcy.inter.PersonInter;

/**
* @author qcy
*
*/
public class Student implements PersonInter{

@Override
public void speaking() {
// TODO Auto-generated method stub
System.out.println("student speaking");
}

}Teacher类。
/**
*
*/
package com.qcy.test;

import com.qcy.inter.PersonInter;

/**
* @author qcy
*
*/
public class Teacher implements PersonInter {

@Override
public void speaking() {
// TODO Auto-generated method stub
System.out.println("teacher speaking");
}

}
和第1大点中,Animal能实例化不一样。
上面,Animal是一个class,是可以实例化的。作为父类,它的派生类(子类)可以去override它的成员方法,也可以不override。
这里,只要是接口,就不能被实例化。如果某些class要去implement这个接口,必须去override在接口里声明过的方法。此时,多态表现为不同的class也许有不同的实现方式。
再举一个更诡异的例子!
package com.qcy.test;

public class Inter_demo_1 {
public static void main(String[] args)
{
Computer computer=new Computer();
Camera camera=new Camera();
Phone phone=new Phone();
computer.useUsb(camera);
computer.useUsb(phone);
}

}

interface Usb
{
//声明了两个方法
//开始工作
public void start();
//停止工作
public void stop();

}

//照相机,实现Usb接口
//一个类实现接口就要把所有的方法全部实现!
class Camera implements Usb
{
public void start()
{
System.out.println("我是照相机,我开始工作了!");
}
public void stop()
{
System.out.println("我是照相机,我停止工作了!");

}

}

//手机类

class Phone implements Usb
{
public void start()
{
System.out.println("我是手机,我开始工作了!");
}
public void stop()
{
System.out.println("我是手机,我停止工作了!");

}

}

//计算机
class Computer
{
//开始使用USB接口
public void useUsb(Usb usb)//体现多态
{
usb.start();
usb.stop();

}
}

运行结果。
我是照相机,我开始工作了!
我是照相机,我停止工作了!
我是手机,我开始工作了!
我是手机,我停止工作了!

这种写法很诡异!!但是也不是不能理解。
注意useUsb(Usb usb)这个函数。形式参数是个接口!但实际参数却是一个实现了这个接口的类!
语法规定,就这么写了。多态是OOP的一个现象,大概也可以理解为语法现象了……
这也是体现多态性的一个例子。
要这样写,或者这样做,估计也只会在什么大型、超大型的工程里去用了。
比如,要写一个什么通用的框架(e.g. spring)。
大概,是一种”规范性“,”通用性“,”代码写作的一致性“和”兼容性“的体现吧。——qcy的感想。因为这好像不是必须的啊,因为要实现这个功能,完全也可以不这样写嘛。只是说有这个东西,好像开发起来配合起来写作起来,更愉快,更高效,更统一。

11.接口不能被实例化
12.接口中的所有方法都不能有主体
13.抽象类里面是可以有实现了的方法的
14.接口中的所有方法都不能有主体,即都不能被实现
15.接口是更加抽象的抽象类!!!!
16.一个类继承抽象类或是使用接口,那么就要实现所有的抽象方法
17.一个类可以实现多个接口
18.接口中可以有变量(但是不能用private,protected修饰)
19.接口中的变量本质上都是静态的,而且是final,不管你加不加static,所以可以直接使用:接口名.变量名
20.在 java开发中,经常把常用的变量定义在接口中作为全局变量使用
  访问形式:接口名.变量名
21.一个接口不能继承其它的类,但是可以继承别的接口
22.接口体现了程序设计的多态和高内聚低耦合的思想

其他琐碎的感想

1. 实现接口和继承父类的区别:
java是单继承,一个类只允许继承一个父类,这种单继承的机制可以保证类的纯洁性,比C++的多继承机制简洁
实现接口可以看做是对单继承的一种补充
继承是层次式的,不太灵活,修改某个类就会打破这种继承的平衡,但是接口就不会,因为只针对实现接口的类才起作用

2. 前期绑定:在程序运行之前就进行绑定,由编译器和连接程序实现,又叫静态绑定,如static方法和final方法,包括private方法,它是隐式fi nal的
3. 后期绑定:在运行的时候根据对象的类型进行绑定,由方法调用机制实现,因此又叫动态绑定,或是运行时绑定,除前期绑定外的所有方法都属于后期绑定

4. final概念:final可以修饰变量和方法
当不希望父类的某些方法被子类覆盖的时,可以用final修饰
当不希望类的某个变量的值被修改,可以用final修饰(有点像C++里的const)
当不希望类被继承时,可以用final修饰

5. final修饰的变量一般用下划线书写
如果一个变量是final的,那么定义时候必须赋初值
6. final修饰的变量又叫常量,一般用XX_XX_XX命名
7. final什么时候用:
出于安全的考虑,类的某个方法不允许修改
类不会被其它的类继承
某些变量值是固定不变的,比如PI。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: