黑马程序员_java面向对象(三) 多态

时间:2023-02-18 08:15:53


         ------- android培训java培训java学习型技术博客期待与您交流! ---------- 

                              多态

1、接口(interface

      定义:是抽象方法和常量值的集合;

      格式:interface 类名{}

      接口中的成员修饰符是固定的:

    成员常量:public static final

接口里面定义变量是全局常量,而且上面三个关键字都可以省略,而且只能是 public static final

    成员函数:public abstract

接口里面定义的方法都是抽象的,而且上面的两个关键字也是可以省略的

接口中的成员都是public

      从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。

      接口的出现将“多继承”通过另一种形式体现出来,即“多实现”。通过implements实现接口;

      举例:interface Demo {

public static final int id = 1;

public abstract void start();

public abstract void run();

public abstract void stop();

    }

      特点:接口是对外暴露的规则;

    接口是程序的功能扩展;

    接口可以用来多实现;

    接口的出现降低耦合性(实现了模块化开发,定义好规则,每个人实现自己的模块,大大提高了开发效率)

    类与接口之间是实现关系,而且类可以继承一个类的同时,可以实现多个相互之间没有关系的接口;

    多个无关的类可以实现同一个接口;

    接口与接口之间可以有继承关系;

    接口与实现类之间存在多态性,与继承关系类似;

      用法:我们可以定义一个类来实现接口,使用implements关键字;

    实现一个接口需要实现接口中所有的方法,抽象类除外;

    可以使用匿名内部类来实现一个接口;

        接口可以继承接口,使用extends关键字。 接口不能继承抽象类,因为抽象类中可能有不抽象的方法;

2、继承和实现:

      类与类之间称为继承:

    类无论是抽象还是非抽象,内部都可以定义非抽象方法,这个方法可以直接被子类继承使用。

      类与接口是实现关系:

            因为接口中的方法都是抽象的,必须由子类实现才可以实例化,所以就用了这个关键字implements

      接口与接口之间是继承关系:

    一个接口可以继承另一个接口,并添加新的属性和抽象方法,并且接口可以多继承

      单继承和多实现:

    类只能单继承,而接口可以多实现;

    java将多继承机制进行改良,通过多实现接口的形式来体现

    为什么不支持多继承呢?

因为继承的多个父类中定义了相同的方法,而方法内容不同,jvm无法判断选择哪个父类的方法,有安全隐患

而多实现就没有这个问题,既是是多个接口中都有相同的方法,但是他们都没有方法体

    多实现的好处:

一个类继承另一个类的同时可以实现多个接口,多实现的好处是扩展了功能

接口的出现打破了单继承的局限性;

3、接口和抽象类:

      共性:都是不断抽取出来的抽象的概念;

      区别:抽象类体现继承关系,一个类只能单继承。接口体现实现关系,一个类可以多实现;

    抽象类是继承用extends,是 "is a "关系。接口是实现用implements,是 "like a"关系;

    抽象类中定义体系中的基本共性功能。接口通常定义体系中对象的扩展功能;

    抽象类中可以定义非抽象方法,供子类直接使用。接口中都是抽象方法;

    抽象类中的变量和方法没有默认修饰符,接口中的变量默认public static final,方法默认为public abstract

4、多态(polymorphic)

      某类事物存在多种形态。 在面向对象语言中,我们可以将函数的形参定义为一个父类类型,而在真正调用该函数时这

      个父类类型的子类对象都可以传入,根据传入的子类对象不同,函数可以运行多种形态。

      多态的特点:

    成员函数:在编译时要查看引用变量所属的类中是否有所调用的方法;

      在运行时要查看对象所属的类中是否有所调用的方法;

      编译看左边运行看右边

    成员变量:只看引用变量所属的类;

      编译和运行都看等号左边;

    静态函数:只看引用变量所属的类;

      编译和运行都看等号左边;

      应用程序不必为每一个子类编写功能调用,只需要对父类进行处理即可,可以大大提高程序的可复用性。

      子类的功能可以被父类的变量调用,这叫向后兼容,可以提高程序的可扩充性和可维护性。 

      判断对象是否属于该类型通过一个关键字来完成instanceof : 对象 instanceof 类型  

  用于判断该对象是否所属于该类型;

      体现:父类或者接口的引用指向或者接收自己的子类对象;

      作用:多态的存在提高了程序的扩展性和后期可维护性

      前提:父类引用指向子类对象;需要存在继承或者实现关系;要有覆盖操作(重写);

      弊端:父类调用的时候只能调用父类里的方法,不能调用子类的方法,因为不知道将来会有什么样的子类继承父类;

    实例

abstract class Animal {
	abstract void eat();
}

class Activities {
	void doActivity(Animal a) {
		if (a != null) {
			a.eat();
		}
		if (a instanceof Cat) {
			((Cat) a).catchMouse();
		} else if (a instanceof Dog) {
			((Dog) a).kanJia();
		} else if (a instanceof Pig) {
			((Pig) a).sleep();
		}
	}
}

class Cat extends Animal {
	@Override
	void eat() {
		System.out.println("吃鱼");
	}

	void catchMouse() {
		System.out.println("抓老鼠");
	}
}

class Dog extends Animal {
	@Override
	void eat() {
		System.out.println("吃骨头");
	}

	void kanJia() {
		System.out.println("看家");
	}
}

class Pig extends Animal {
	@Override
	void eat() {
		System.out.println("吃饲料");
	}

	void sleep() {
		System.out.println("老是睡觉");
	}
}

public class DuoTaiDemo1 {
	public static void main(String[] args) {
		
		// new Activities().doActivity(null);
		
		Animal a = new Cat();//类型提升,向上转型
		a.eat();
		//如果想要调用猫的特有方法,如何操作??
		//强制将父类的应用转成子类类型,向下转型
		Cat c = (Cat)a;
		c.catchMouse();
		
		/**
		 * 注意:前往不能将父类对象转成子类类型
		 * Animal a = new Animal();
		 * Cat c = (Cat)a;
		 * 我们能转换的是父类引用执行了自己子类对象是,该应用可以被提升
		 * 多态自始至终都是子类对象在做着变化
		 */
		
		//下面代码是利用Activities类创建对象完成对Cat,Dog,Pig进行的活动
		new Activities().doActivity(new Cat());
		new Activities().doActivity(new Dog());
		new Activities().doActivity(new Pig());
	}
}


5、内部类(Inner Class

      在类里面定义的类称之为内部类(内置类、嵌套类)。内部类是外部类的一个成员,内部类的出现再次打破了java

      单继承的局限性。 创建内部类对象时必须先创建一个外部类对象,通过一个外部类对象才能创建内部类对象;

  外部类名.内部类名 变量名 = new 外部类名().new 内部类名();

      内部类的class文件名为:外部类名$内部类名.class

     

      访问特点:

  内部类可以直接访问外部类中成员,包括私有成员,因为在使用内部类时一定有外部类对象,且只对应一个;

      外部类名.this.成员名

  而外部类要访问内部类中的成员必须要建立内部类的对象;因为在使用外部类时有可能还没有创建内部类对象

      即使创建了,一个外部类对象也可能对应多个内部类对象

      局部内部类:

    定义在方法中的类,只能在方法中使用,而且使用的代码只能在声明的代码下面;

    局部内部类只能在该内部类的方法内实例化,不可以在此方法外对其实例化;

    局部内部类不能定义静态成员。需创建外部类对象才能使用,static不创建对象就能使用,这是矛盾的;

    可以直接访问外部类中的成员;同时可以访问所在局部中的局部变量,但必须是被final修饰的;

因为方法的局部变量位于栈上,方法运行之后生命周期结束,不能再被访问,局部变量成为历史。

但是该方法结束之后,在方法内创建的内部类对象可能仍然存在于堆中!例如,对它的引用被传递

到其它某些代码,并存储在一个成员变量内, 那么方法结束之后还能访问这个对象。这时变量被销毁了,

对象还在,如果在对象的某个方法内访问这个变量就访问不到了。用final修饰这个变量后,变量

会一直存储在内存中,方法运行结束之后不被销毁;

      成员内部类:

    定义在成员位置上的内部类,在类中方法外;

    创建对象方式:外部类名.内部类名 对象名 外部类对象.内部类对象

    当内部类中定义了静态成员,该内部类必须是static的。

    当外部类中的静态方法访问内部类时,内部类也必须是static的。

    成员内部类之所以可以直接访问外部类的成员,是因为内部类中都持有一个外部类对象的引用:外部类名.this

    可用的修饰符有:finalabstractpublicprivateprotectedstatic

      静态内部类:

    可以使用static修饰一个类中的成员内部类;在类中方法外;

    静态内部类不用创建外部类对象就可以直接创建对象:外部类名.内部类名 变量名 = new 外部类名.内部类名();

    静态内部类可以定义静态成员:因为静态内部类可以直接使用,无需创建外部类对象。

    静态内部类中不能访问外部非静态成员:因为创建静态内部类不需要外部类对象,也就是有可能没有创建外部类对象,

    使用外部类非静态成员必须有外部类对象;

      匿名内部类:就是内部类的简化写法

    前提:内部类可以继承或实现一个外部类或者接口;

    格式:new 外部类名或者接口名(){覆盖类或者接口中的代码(也可以自定义内容)}

  先创建一个外部类或接口的子类,然后根据这个类或接口创建一个对象;

    建立匿名内部类的关键点是重写父类的一个或多个方法,而不是创建新的方法:

因为用父类的引用不可能调用父类本身没有的方法,创建新的方法是多余的;

    匿名内部类的使用:

通常在使用方法是接口类型参数,并该接口中的方法不超过三个时,可以将匿名内部类作为参数传递;

简化书写,如果阅读实在费劲的话,可以写有名字的内部类;






          ------- android培训java培训java学习型技术博客期待与您交流! ----------