1.5 多态
*多态(polymorphic)
*方法或对象具有多种形态,是面向对象的第三大特征,多态是建立在封装和继承基础之上的
1.多态的具体体现
1.方法的多态
(重写和重载体现了多态)
2.对象的多态
1.一个对象的编译类型和运行类型可以不一致
Animal animal = new Dog(); //animal编译类型是Animal,运行类型是Dog
animal = new Cat();
2.编译类型在定义对象时,就确定了,不能改变
3.运行类型是可以变化的
4.编译类型看定义时=号的左边,运行类型看 = 号的右边
class Cat extends Animal
{public void cry(){System.out.println("小猫喵喵叫")}
}class Animal
{public void cry(){System.out.println("动物在叫")}
}main()
{Animal animal = new Cat();animal.cry(); //小猫喵喵叫//若此时改为Dog类,则会执行Dog类下的方法animal = new Dog();animal.cry();
}
2.多态的细节
1.多态的前提:两个对象(类)存在继承关系
2.本质:父类的引用指向了子类的对象
3.语法:父类类型 引用名 = new 子类类型();
4.特点:编译类型看左边,运行类型看右边
5.如果子类中写有父类没有的方法,那么如果运用了多态,就调用不了子类特有的成员方法
3.多态的向上转型
*(子类转换成父类)
*父类也可以是爷爷类(基类)
4.多态的向下转型
1.语法: 子类类型 引用名 = (子类类型) 父类引用
2.只能强转父类的引用,不能强转父类的对象
3.要求父类的引用必须指向的是当前目标类型的对象
4.当向下转型后,可以调用子类类型中所有的成员
main()
{Animal animal = new Cat(); //原来的animal的运行类型是Cat对象,所以可以在下面强转为Cat类型Cat cat = (Cat) animal;//强转父类引用为为子类 这样就可以调用子类的特有成员方法
}
5.注意事项和细节
1.属性没有重写直说,属性的值看编译类型
class Base
{int money = 10;
}class Sub extends Base
{int money = 20;
}main()
{Base base = new Base();base.money;//10Sub sub = new Sub();sub.money;//20
}
2.instanceof 比较操作符,用于判断对象的运行类型是否为XX类型或XX类型的子类型
class AA{}//父类
class BB extends AA{}//子类main()
{BB bb = new BB();System.out.println(bb instanceof BB);//bb是不是BB的类型,返回结果为boolean值System.out.println(bb instanceof AA);//aa 编译类型 AA,运行类型BBAA aa = new BB();System.out.println(aa instanceof AA);//trueSystem.out.println(aa instanceof BB);//true
}
6.动态绑定机制
1.当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
2.当调用对象属性时,没有动态绑定机制,哪里声明(函数里面的成员属性为函数所在类下的成员属性),哪里使用
class A
{public int i = 10;public int sum(){return getI() + 10;}public int sum1(){return i +10;}public int getI(){return i;}
}class B extends A
{public int i =20;public int sum(){return i +20;}public int getI(){return i;}public int sum1(){return i +10;}
}main()
{A a = new B();//向上转型System.out.println(a.sum());//40System.out.println(a.sum1());//30
}
7.多态的应用
1.多态数组
*数组的定义类型为父类类型,里面保存的实际元素类型为子类类型
class Teacher extends Person
{String name;int salary;public void say(){}public void teach(){}
}class Student extends Person
{String name;int score;public void say(){}public void study(){}
}class Person
{public void say(){}
}main()
{Person[] persons = new Person[5];persons[0] = new Person("jack", 20);persons[1] = new Student("jack",18,100);persons[2] = new Teach("scott" ,30 ,20000);for(int i = 0;i<3;i++){System.out.println(persons[i].say());//动态板顶机制if(persons[i] instancof Student){Student student = (Student)persons[i];//向下转型student.study();}else if(persons[i] instanceof Teacher){Teacher teacher = (Teacher)persons[i];teacher.teach();} else{System.out.println("你的类型有误,请自己检查...")}}
}
2.多态参数
*方法定义的形参类型为父类类型,实参类型允许为子类类型
1.6 Object类
1.equals方法
* == 是一个比较运算符
1.==:既可以判断基本类型,又可以判断引用类型
2.==:如果判断基本类型,判断的是值是否相等
3.==:如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象
4.equals:是Object类的方法,只能判断引用类型
5.默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等。比如Integer,String
2.重写equals方法
class Person
{private String name;private int age;private char gender;//重写Object的equals方法public boolean equals(Object obj){if(this == obj){return true;}}//类型判断if(obj instanceof Person){//是Person,我们才比较Person p = (Person)obj;return this.name.equals(p.name) && this.age == p.age && this.gender == p.gender;}//如果不是Person类型,则直接返回falsereturn false;
}
1.7 hashCode
*hashCode返回该对象的哈希码值
*总结:
1.提高具有哈希结构的容器的效率
2.两个引用,如果指向的是同一个对象,则哈希值肯定是一样的
3.两个引用,如果指向的是不同对象,则哈希值是不一样的
4.哈希值主要根据地址号来的,不能完全将哈希值等价于地址
1.8 toString
*返回该对象的字符串表示
*基本介绍
1.默认返回:全类名(包名 + 类名) + @ + 哈希值的十六进制
2.当直接输出一个对象时,toString会被默认调用
System.out.println(monster);
System.out.println(monster.toString());//这两个是等价的
1.9 finalize
1.当对象被回收时,系统自动调用该对象的finalize方法,子类可以重写该方法,做一些释放资源的操作
2.什么时候被回收:当某个对象没有任何引用时,则jvm就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁对象前,会先调用finalize方法
3.垃圾回收机制的调用,是由系统来决定,也可以通过System.gc()主动触发垃圾回收机制
main()
{Car bmw = new("宝马");bmw = null;System.gc(); //主动调用垃圾回收器
}
1.10 断点调试(debug)
1.在开发中,新手程序员在查找错误时,这时老程序员就会温馨提示,可以用断点调试,一步一步的看原码执行的过程,发现错误
2.在断点调试过程中,是运行状态,是以对象的运行类型来执行的
1.断点调试介绍
1.断点调试是指在程序的某一行设置一个断点,调试时,程序运行到这一行就会停住,然后可以一步一步往下调试,调试过程中可以看各个变量当前的值
2.断点调试的快捷键
F7(跳入) :跳入方法内
F8(跳过) :逐行执行代码
shift + F8(跳出)
F9(resume,执行到下一个断点)