多态性
理解多态性:可以理解为一个事物的多种形态。
对象的多态性:
父类的引用指向子类的对象
(或子类的对象赋给父类的引用)
示例:
Person p1 = new Person( );
Person p2 = new Man( ); // 对象的多态性 Man继承Person
多态的使用:
当父类的引用调用同名同参数的方法时(重写方法),实际执行的是子类重写父类的方法 —— 虚拟方法调用
示例:
Man man = new Man(); // 创建的对象
man.eat();
p2.eat(); // 编译时看左边,运行时看右边
有了对象的多态性以后,我们在编译时,只能调用父类中声明的方法,但在运行时,实际执行的是子类重写父类的方法。
实例:
public class Animal {
public static void main (String[] args){
Animal test = new Animal();
test.func(new Dog());
// 运行结果: 狗 爱吃火腿 汪汪汪!
}
public void func(Animal animal){
animal.eat();
animal.shout();
}
public void eat(){
System.out.println("动物吃饭");
}
public void shout(){
System.out.println("动物叫声");
}
}
class Dog extends Animal{
public void eat(){
System.out.println("狗 爱吃火腿");
}
public void shout(){
System.out.println("汪汪汪!");
}
}
多态性的使用前提:
①类的继承关系
②方法的重写
说明
1)对象的多态性只适用于方法,属性不具有多态性
2)父类与子类中的同名属性是共存的,在编译时就已经确定(编译与运行都看左边),所以不具有多态性
实例
public class Test{
public static void main(String[] args) {
Animal myDog = new Dog(); // 多态: 父类引用指向子类对象
System.out.println(myDog.makeSound()); // 运行结果: 汪汪汪
System.out.println(myDog.sound); // 运行结果: 动物叫声
}
}
// 父类
class Animal {
public String sound = "动物叫声";
public String makeSound() {
return sound;
}
}
// 子类
class Dog extends Animal {
public String sound = "汪汪汪";
@Override
public String makeSound() {
return sound;
}
}
instanceof关键字
如何调用子类特有的属性和方法:
向下转型:使用强制类型转换符。
Man m1 = (Man)p2; // 强制类型转换 p2是Person类的引用,Man继承Person
m1.earnMoney( );
说明
1)使用强制转换时,可能出现ClassCastException的异常。
2)不相干的两个类不能转换
示例:
Women w1 = (Women)m1; // 异常 ClassCastException
w1.goShopping( );
instanceof 关键字的使用:
a instanceof A
说明
1)判断对象a是否是类A的实例
2)如果是,返回true
3)如果不是,返回false
示例
if (p2 instanceof Man){
Man m2 = (Man) p2;
m2.earnMoney( );
System.out.print("man");
}
使用情景:
为了避免在向下转型时出现ClassCastException的异常, 我们在向下转型时,先进行instanceof的判断,一旦返回true, 就向下转型,如果返回false,就不进行转型。
说明
1)a instanceof A 返回 true
2)B是A的父类,则 a instanceof B 也返回 true
示例
void getPrice(Computer com){
// instanceof 判断对象是否属于这个类
if(com instanceof NotePad){
NotePad n = (NotePad)com; // 造型 引用间的类型转换(继承关系)
n.navigation(); // 通过将父类转为子类,子类引用-子类特有的方法
说明
1)父类 Computer ,子类 NotePad
2)父类引用 com ,子类引用 n
// 创建对象
Computer com = new Computer();
NotePad notePad = new NotePad();
// 多态的使用 多态参数方法
test.getPrice(com);
test.getPrice(notePad);
Object类
java.lang.Object类
1)Object类是所有java类的根父类
2)如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Obect类。
3)Object类中的功能(属性、方法)具有通用性。
Object类
属性:无属性
方法:
equals( )、toString( )、getClass( )、hashCode( )、clone( )
wait( )、notify( )、notifyALL( )、finalize( )
构造器:Object类只声明了一个空参的构造器
方法名称 | 类型 | 描述 |
public Object( ) | 构造 | 构造器 |
public boolean equals( Object obj) | 普通 | 对象比较 |
public int hashCode( ) | 普通 | 取得hash码 |
public String toString( ) | 普通 | 对象打印时调时 |
问题:final、finally、finalize的区别?
1)final
是一个修饰符,可以用来修饰方法和变量
- 修饰类,表示类不能被继承
- 修饰方法,表示方法不能被子类覆盖
- 修饰变量,表示变量不能被修改,即常量
- 修饰方法,表示方法不能被子类覆盖
2)finally
是Java异常处理的一个组成部分,与try
和catch
一起使用,表示即使发生异常时,一定会执行finally代码块中的代码
3)finalize在Java 12中被完全移除
问题:== 与 equals 的区别
1)==
== 可以比较基本数据类型:比较变量的“值”
也可以比较引用类型:比较对象的“内存地址”
2)equals
具体要看自定义类里有没有重写Object类的equals 方法来判断
如果该方法没有被重写,也默认是==
如果重写equals方法,来比较类的相应属性是否都相等
equals( ) 方法的使用
说明
只适用于引用数据类型
Object 类中equals( ) 的定义
public boolean equals( Object obj ){
return (this == obj);
}
说明
1)Object类中定义的equals( )方法和==作用是相同的,比较俩个对象的地址值是否相同。
2)String、Date、File、包装类等都重写了Object类中的equals( )方法
重写:比较俩个对象的“实体内容”是否相等。
例:重写方法
@Override
public boolean equals (Object obj){
if ( this ==obj){
return true;
}
if( obj instanceof Customer){
Customer cust = (Customer) obj; // 造型 类型转换
// 比较俩个属性是否都相等
// 写法一:age 实参
if( this.age == cust.age && this.name.equals( cust.name)){
return true;
}else{
return false;
}
// 写法二:
return this.age == cust.age&&this.name.equals(cust.name);
}
return false;
}
toString( )方法的使用
当我们输出一个对象的引用时,实际上就是调用对象的toString( )
示例:
System.out.print(a);
System.out.print(a.toString);
// 以上两个结果是相同的
Object类中toString( )的定义:
public String toString ( ){
return getClass( ).getName( )+@+Integer.toHexString(hashCode( ));
}
说明
1)String、Date、File、包装类等都重写了Object类中的toString( )方法。使得在调用对象的toString( )时,返回“实体信息”。
自定义类也可以重写toString( )方法,当调用此方法时,返回对象的“实体内容”。
例:
@Override
public String toString(){
return year+"年"+month+"月"+day+"日";
}
hashCode( ) 方法的使用
public int hashCode( ):
返回当前调用对象的哈希码
哈希码:
(1) 也称为散列码,不同的对象在内存中分布的散列性
(2) 也称为特征码,让所有属性数据参与运算的结果码值
它是根据对象的内存中的物理地址经过哈希算法,得出的一个码值
@Override // 重写 所有属性都要参与,计算过程要有变化性
public int hashCode( ){
return 31*(x*7+y*23); // x,y是当前对象的属性
}
多态数组
大大提升兼容性,处理不同类型的对象
示例:
Person[ ] arr = new Person[5];
arr[0] = new Chinese( );
arr[1] = new American( );
多态参数方法
1)多态参数方法,可以接收任意本类及子类对象;
2)会导致对象的类型模糊
例:
test( Person p){
Chinese c = (Chinese) p ; // 造型 引用间的类型转换
}test( Chinese c){
}
test( American ){
}