一 多态:可以理解为事物存在的多种形态
1> 多态的体现
父类的引用指向了自己的子类对象。
父类的引用也可以接收自己的子类对象。
2> 多态的前提: 必须是类与类之间有关系。要么继承,要么实现。
通常还有一个前提:存在覆盖。
3> 多态的好处:
多态的出现大大的提高程序的扩展性。
4> 多态的弊端:
提高了扩展性,但是只能使用父类的引用访问父类中的成员。
5> 多态的应用
多态的扩展性代码体现:
abstract class Animal {
//各种动物吃的方式不同,抽取方法
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void catchMouse() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void kanJia() {
System.out.println("看家");
}
}
class Pig extends Animal {
public void eat() {
System.out.println("饲料");
}
public void gongDi() {
System.out.println("拱地");
}
}
// -----------------------------------------
class DuoTaiDemo {
public static void main(String[] args) {
// Cat c = new Cat();
// c.eat();
// Dog d = new Dog();
// d.eat();
// 没有使用多态时,需要根据参数的类型去调用相应的方法
/*
Cat c1 = new Cat();
function(c1);
function(new Dog());
function(new Pig());
*/
// 父类的引用指向了自己的子类对象。
Animal c = new Cat();
c.eat();
function(new Cat());
function(new Dog());
function(new Pig());
}
// 父类的引用也可以接收自己的子类对象。
// 多态的出现大大的提高程序的扩展性,后期只要传入动物,就可以
public static void function(Animal a)// Animal a = new Cat();
{
a.eat(); // 不同动物已经并复写了eat方法
// a.catchMouse(); //提高了扩展性,但是只能使用父类的引用访问父类中的成员。
}
二 类型转换:
只有当转换的父类引用指向自己的子类对象时,该引用可以被提升。
向上转型 Animal a= new Cat();
向下转型Cat c =(Cat)a;
多态自始至终都是子类对象在做着变化
当想使用子类的特有方法时,需要向下转型。
注意:
Animal a = new Animal();
Cat c = (Cat)a; 将父类对象转成子类类型,是不可能的,难道只要是动物就能转成猫么?
转型示例:
abstract class Animal{
public abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void catchMouse() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void kanJia() {
System.out.println("看家");
}
}
class Pig extends Animal {
public void eat() {
System.out.println("饲料");
}
public void gongDi() {
System.out.println("拱地");
}
}
// -----------------------------------------
class DuoTaiDemo2 {
public static void main(String[] args) {
// Animal a = new Cat();//类型提升,向上转型。
// a.eat();
// 强制将父类的引用。转成子类类型,向下转型。
//Cat c = (Cat)a;
// c.catchMouse();
/*我们能转换的是父类应用指向了自己的子类对象时,该引用可以被提升,也可以被强制转换。
多态自始至终都是子类对象在做着变化。
下面代码将父类对象转成子类类型,是不可能的,难道只要是动物就能转成猫么?
Animal a = new Animal();
Cat c = (Cat)a;
*/
function(new Dog());
function(new Cat());
}
public static void function(Animal a)// Animal a = new Cat();
{
a.eat();
if (a instanceof Cat) {
Cat c = (Cat) a;
c.catchMouse();
} else if (a instanceof Dog) {
Dog c = (Dog) a;
c.kanJia();
}
/*
* instanceof : 用于判断对象的类型。 对象 intanceof 类型(类类型 接口类型)
*/
}
}
多态应用:主板与扩展设备的示例
package cn.xushuai.Test;
/*沒有使用接口的情況,每次有新设备都需要定义独立的设备,
class MainBoard{
public void run(){
System.out.println("mainboard run");
}
public void useNetCard(NetCard c){
c.open();
c.close();
}
}
class NetCard{
public void open(){
System.out.println("netcard open");
}
public void close(){
System.out.println("netcard close");
}
}
*/
//各种设备的使用规则,只需扩展设备去遵循,实现方法即可,提高了程序的扩展性。
interface PCI {
public void open();
public abstract void run();
}
class MainBoard {
public void userPCI(PCI p) {
if (p != null) { // 防止空指针异常,检测是否有设备
p.open();
p.run();
}
}
}
class NetCard implements PCI {
public void open() {
System.out.println("网卡 打开正常!");
}
public void run() {
System.out.println("网卡 开始 run.......!");
}
}
class SoundCard implements PCI {
@Override
public void open() {
System.out.println("声卡 打开正常");
}
@Override
public void run() {
System.out.println("声卡 开始 run.........!");
}
}
public class MainBoardDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
MainBoard mb = new MainBoard();
mb.userPCI(new SoundCard());
mb.userPCI(new NetCard());
}
}
三. 多态中(父类引用指向子类对象)成员的特点
1 非静态成员函数的特点:(因为存在覆盖)
1> 在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有,编译失败。
2> 在运行时期:参阅对象所属的类中是否有调用的方法。
(动态绑定:this所指对象去调用方法)
简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。
2. 成员变量的特点:无论编译和运行,都参考左边(引用型变量所属的类)。
3. 静态成员函数的特点:无论编译和运行,都参考做左边。
(静态绑定:静态方法一进内存就绑定在其所属类上了,所属于类)
原因:静态方法不需要对象,其决定于引用变量的所属类,所以一般不会覆盖静态方法。
四 Object 和Class类
1> Object:是所有对象的直接后者间接父类,传说中的上帝。
该类中定义的肯定是所有对象都具备的功能。
2> Object类中已经提供了对对象是否相同的比较方法。
如果自定义类中也有比较相同的功能,没有必要重新定义。
只要沿袭父类中的功能,建立自己特有比较内容即可。这就是覆盖。
3> new A对象时会加载A.class文件,class文件中有文件名A,构造函数,和一些 方法,是这一类对象的共性,
所以用Class类来描述这一类对象(类文件对象)。
五 包
对类文件进行分类管理,给类提供多层命名空间
写在程序文件的第一行
类名的全称是: 包名.类名
包也是一种封装形式
1. 为了简化类名的书写,使用一个关键字:import.i,mport 导入的是包中的类。
2. 建议,不要写通配符 * ,需要用到包中的哪个类,就导入哪个类。
3. 建立定包名不要重复,可以使用url来完成定义,url是唯一的
4. 包访问权限总结:
1> 包与包之间进行访问,被访问的包中的类以及类中的成员,需要public修饰。
2> 不同包中的子类还可以直接访问父类中被protected权限修饰的成员。
3> 包与包之间可以使用的权限只有两种,public protected。
5. 包访问权限图示
作用域 当前类 同一package 子孙类 其他package
public √ √ √ √
protected √ √ √ ×
friendly √ √ × ×
private √ × × ×