多态
/**
多态:多种形态
函数具备多态性,同一函数名,参数列表不一样,存在形式不一样 同样一个函数有些放在父类,有些放在子类
重点讲对象,对象本身也存在多态性。
重点讲的是对象的多态性
*/
class 动物(){}
class 猫() extends 动物 {}
class 狗() extends 动物 {}
猫 x = new 猫();
//建立本类对象,并通过本类的引用指向本类的对象 猫即时猫,又是动物,具备不同的形态 一个对象具备多种形态
//动物父类,父类创建变量指向了子类对象-多态的体现,动物类型型的指向,体现父类型的指向子对象,父类引用指向子类的对象,表象就是体现了多态。已经开始使用多态
动物 x = new 猫();//一个对象,两种形态
//猫这类事物既具备猫的形态,又具备着动物形态,这就是对象的多态性
//简单说,就是一个对象对应着不同类型
//多态在代码中的体现就是父类或者接口的引用指向其子类对象
/*
将内容封装变成对象,指挥对象做事情,已经将事情简单化
但是对象多了,又变复杂了
指挥更多对象做事情,找对象的共性,直接让共性的事物调用,又一次复杂事情简单化
多态提高了对象的扩展性,就是你的代码后期要不断的改动升级要不断地修改,麻烦,为了提高后期可维护性,搞个动物在里面,只要是其子类都可以往里面穿
多态的好处:
1、提高了代码的扩展性,前期定义的代码可以使用后期的内容 --多态性
子类好覆盖
*/
abstract class Animal{
abstract void eat()'
}
class Dog extengds Animal{
void eat(){
System.out.println("啃骨头");
}
void lookHome(){
System.out.println("看家");
}
}
class Cat extengds Animal{
void eat(){
System.out.println("吃鱼");
}
void catchMouse(){
System.out.println("捉老鼠");
}
}
class Pig extengds Animal{
void eat(){
System.out.println("吃猪饲料");
}
}
/*
多态的局限性:
前期定义的内容不能使用(调用)后期子类的特有内容。(因为前期不知道后期有什么功能,只能用子类调用)
多态前提:
1、必须有关系,继承、实现
2、要有覆盖(我已经定义功能,你是要有这些功能的具体实现)
*/
class DuoTaiDemo(){
public void method(Animal a){//Animal a = new Dog();a不断指向其子类对象
c.eat();
}
/*
public void method(Cat c){
c.eat();
}
public void method(Dog g){
g.eat();
}
*/
public static void main(String[] args) {
Animal a = new Cat();
a.eat();
a.catchMouse();//编译失败,animal没有抓老鼠,肯定animal中其他子类没有这个功能,也就不能定义在父类里面。
Cat c = new Cat();
Dog c = new Dog();
c.eat();
method(new Cat());
method(new Dog());
//如果还想调用猪,还要加个猪的方法
//无论猫还是狗都具有eat方法
}
}
class DuoTaiDemo(){
public static void main(String[] args) {
//Cat c = new Cat();
//c.eat();
//c.catchMouse();
//舍弃了特有功能,为了提高扩展性
Animal a = new Cat();//byte b = 3; int x = b;b类型提升到了int类型;自动类型提升,猫对象自动提升为动物类型,必须用动物的身份去操作了,就产生了局限性,不能使用动物的特有类型,特有功能无法访问
//作用:就是可以限制对特有功能的访问。现在就是用动物的功能,没有必要用猫狗特有功能。专业讲,向上转型,猫荣升为动物
//如果还想用具体动物猫的特有功能,你可以将对象进行向下转型
Cat c =(Cat)a;
a.eat();
a.catchMouse();//就不能使用了,向下转型就可以使用子类对象的特有功能
//为什么要向下转型?目的是为了使用子类中的特有方法。向上是限制,不需要有其他功能。
//假设动物能创建对象,动物引用可以指向很多子类对象
/*
注意:对于转型,自始至终都是子类对象在做着类型的变化
*/
Animal a = new Animal();//真创建了动物对象,能把动物对象创建成猫嘛
Cat c =(Cat)a;
}
}
/*
毕老师和毕姥爷的故事
*/
class 毕姥爷(){
void 讲课(){
System.out.println("管理");
}
void 讲课(){
System.out.println("钓鱼");
}
}
class 毕老师 extends 毕姥爷(){
void 讲课(){
System.out.println("Java");
}
void 看电影(){
System.out.println("看电影");
}
}
class DuoTaiDemo(){
public static void main(String[] args) {
毕老师 x = new 毕老师();
x.讲课();
x.看电影();
毕姥爷 x = new 毕老师(); //父类型
x.讲课();
x.钓鱼();
毕姥爷 x = (毕老师)new 毕老师();//本类型
}
}
/*
想吃饭都可以,想要抓老鼠,只有猫才能抓老鼠
instanceof 通常再向下转型之前用于健壮性判断
*/
class DuoTaiDemo(){
public void method(Animal a){//Animal a = new Dog();a不断指向其子类对象
//多个物种就要多个判断,像这种挨个判断的几乎没有,一个父类n多子类,判断麻烦
//我们如果使用子类的特有方法,意味着向下转型,所以转型之前,加逻辑判断,加强代码的健壮性
a.eat(); //怎么判断是什么类型对?对于对象类型
if(a instanceof Cat){//instanceof用于判断对象的具体类型,只能用于引用数据类型判断
Cat c = (Cat)a;
c.catchMouse();//但是调用方法的时候,往里面传入了一只狗,但是这是猫特有的
}else if(a instanceof Dog){
Dog d = (Dog)a;
d.lookHome();
}
}
public static void main(String[] args) {
method(new Dog());//狗没有猫的特有方法,但是传了狗的对象
}
}
/*
多态时成员的特点:
1、成员变量
编译时:参考引用型变量所属的类中是否有调用的成员变量,有,编译通过,无编译失败,类文件都产生不了
运行时:参考引用型变量所属的类中是否有调用的成员变量,并运行该所属类中的成员变量
简单说:编译和运行都参考等号的左边,就可以了
作为了解,因为开发情况不可能出现,父类有直接拿来用
2、成员函数 -- 重点(非静态的,和对象相关,会动态绑定在某一对象上,谁调用就绑定谁)
编译时:参考引用型变量所属的类中是否有调用的函数,有,编译通过,无编译失败,类文件都产生不了
运行时:参考对象所属类中是否有调用的函数
简单说:编译看左边,运行看的右边,就可以了
注意:一出现多态,专业来讲,向上转型,将子类型隐藏,就不使用子类持有的方法
3、静态函数
编译时:参考引用型变量所属的类中是否有调用的静态方法
运行时:参考引用型变量所属的类中是否有调用的静态方法
简单说:编译和运行都看左边
其实对于静态方法,是不需要对象的,直接用类名调用即可
4、构造函数用于子类的实现过程(不存在)
*/
class Fu{
//int num = 3;
void show(){
System.out.println("Fu show");
}
static void method(){
System.out.println("Fu static Method");
}
}
Class Zi extends Fu{
//int num = 4;
void show(){
System.out.println("Zi show");
}
static void method(){
System.out.println("Zi static Method");
}
}
class DuoTaiDemo(){
public static void main(String[] args) {
Fu f = new Zi();//调用不依赖对象,依赖引用。依赖左边
/*
静态怎么变成了父,不是覆盖吗?静态方法就在方法的静态区里面,一家在都存在,而且都有自己所属,固定的
类一加载就存在,被类名所调用,根本不需要对象,立刻就有所属,静态绑定
个人认为静态方法不涉及多态性,对象的多态性,没有对象啊
*/
f.method();
Fu.method();//不需要实例对象,类名调用即可
f.show();//子父类中出现了一模一样的方法时候,覆盖操作。父类的应用掉方法为啥还是子类的方法呢?提升了了类型,但是运行方法还是以右边为准
/*
动态绑定的特点 :最终看的是应用型变量遂定的对象,会把show方法绑定到指定的对象运行
因为show方法本身是非静态,依赖对象,以当前对象为主,this持有指向对象
*/
//如果父类没有show,可以调用吗?父类没有方法,怎么调用,编译失败
/*
Zi z = new Zi();//4
System.out.println(z.num);
Fu f = new Zi();//3 子类提升为父类了,就要找父类的属性
System.out.println(f.num);
//父类没有了num,报错
*/
}
}
Object
/*
子类在new对象的时候,调用默认构造函数,初始化,找父类,找super,父类里面本来有构造函数,父类里面也有super,找的就是Object
Object Java中所有类的根类
java以对象为主,不断向上抽象而来的,具备着所有对象都具备的共性内容。
任意对象都具有共性内容,都可以调用。
常用的共性功能:
equals 判断两个对象是否相等 返回布尔值类型 参数是一个对象,任何对象都具备这个方法,只要明确另外一个对象。另外个对象是什么不用管,不能明确对象,为了可以传任意对象,提高其扩展性。多态
*/
class Fu{
Fu(){
super();
}
}
class Zi extends Fu{
Zi(){
super();
}
}
class {
public static void main(String[] args) {
}
}
class Person{
private int age;
Person(int age){
this.age = age;
}
//想比较Person的年龄,时候是同龄人
public boolean compare(Person p){
return this.age = p.age;
}
//对象有这个功能,可以保留声明,要保持特有的具体内容
public boolean equals (Object obj){
if(!(obj instanceof Person) ){
//return false;//如果故意给不同类型,抛异常。抛编译时异常还是运行异常,传的不是正确的类型 ,直接抛异常,不进入方法
throw new ClassCastException("类型错误");//异常名和我们异常没什么关系
}
Person p = (Pesrson)obj;
return this.age == p.age;
}
class Demo{
}
/*
一般都会覆盖此方法,根据对象特有内容,建立判断对象是否相同的依据
为什么不直接把父类这个方法抽象?如果抽象,你就必须什么都不干的情况去覆盖。我又个默认实现,你有特别需要自己腹写
*/
class ObjectDemo{
public static void main(String[] args) {
Person p1 = new Person(20);//Object obj = p2 向上转型,隐藏子类的特有内容
Person p2 = new Person(20);
Person p1 = p1;
Demo d = new Demo();
System.out.println(p1==p2);//比较的地址值 假
/*
*/
System.out.println(p1.equals(p2));//假 比较俩对象是否相等
System.out.println(p1.equals(p3));//假 比较俩对象是否相等 比较的也是地址
System.out.println(p1.equals(d));//转型异常,接受范围广用的类型多,要做健壮性判断
}
}