多态性
理解:顾名思义,可以理解为一种事物的多种形态
多态性的应用:
-
对象的多态性:父类的引用指向子类的对象
- 当父类调用被子类重写方法后,实际执行的是子类重写父类的方法 ---- 虚拟方法调用
- 有了对象多态性之后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法
- 虚拟方法:
- 在子类中对父类方法进行重写,在多态情况下,此时父类的方法称之为虚拟方法
-
多态性使用的前提:
- 类的继承关系
- 方法的重写
-
多态性使用的好处:
-
当一个父类为
A
,其含有两个子类B
和C
,且子类B
和C
都对A
中方法进行了重写;当不具备多态性时,要调用三个类中同名方法时,需要构建三个重载方法进行调用;具备多态之后,只需构建以父类为形参的方法,将子类实例化对象传递给父类引用,实际运行时,调用的也是子类中重写的方法 -
实例:
public class Case1 { public static void main(String[] args){ Case1 test=new Case1(); //此时可以通过申明一个方法执行三种不同功能 test.show(new Animal()); test.show(new Dog()); test.show(new Cat()); } void show(Animal animal){ animal.eat(); animal.shout(); } } class Animal{ void eat(){ System.out.println("动物吃!"); } void shout(){ System.out.println("动物叫!"); } } class Dog extends Animal{ void eat(){ System.out.println("狗吃骨头!"); } void shout(){ System.out.println("汪!汪!汪!"); } } class Cat extends Animal{ void eat(){ System.out.println("猫吃鱼!"); } void shout(){ System.out.println("喵!喵!喵!"); } }
-
-
对象的多态性,只适用于方法,不适用于属性
- 当父类与子类具有同名属性时,默认初始化值设为不同,在将父类引用指向子类对象之后,
父类.属性
执行的是父类中的属性 - 多态情况下,不可以调用子类特有的属性和方法
- 当父类与子类具有同名属性时,默认初始化值设为不同,在将父类引用指向子类对象之后,
-
多态是运行时行为还是编译时行为?
- 多态是运行时行为,在多态情况下,父类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用是在编译期无法确定的。
instanceof 操作符
背景: 多态情况下,内存中实际加载了子类特有的属性和方法,但由于变量申明类型为父类,导致编译时,只能调用父类中的属性和方法,子类中特有的属性和方法不能调用
如何调用子类特有的属性和方法?
- 使用强制类型转换(向下转型)
- 使用强制类型转换时可能会出现异常,我们要注意在多态时,赋予父类的子类对象与当前接受的子类类型的异同
instanceof
关键字的使用:a instanceof A
:判断对象对象a是否是类A的实例- 避免在向下转型(强制转换)时出现异常,在转换之前使用
instanceof
进行判断 - 若
a instanceof A
为true
,则a instanceof B
也为true,其中B
为A
的父类
==
的区别
- 基本数据类型,比较的是变量值是否相等
- 引用数据类型,比较的是变量的地址值是否相同
方法调用–可变个数形参方法
public class Test{
void show(int a,int... arr){
System.out.println("可变形参")
}
void show(int a,int b,int c){
System.out.println("确定参数")
}
}
show(1,2,3);
//调用的为第二个方法,因为第二个方法参数确定,优先调用
Object类的使用
Object
类是所有java
类的根父类
- 没有定义特定的属性
- 定义了一个空参构造器
- 需要注意的一些常见方法
equals()
toString()
getClass()
==
与equals()
的区别
==
既可以比较基本类型也可以比较引用类型。对于基本类型就是比较值,对于引用类型就是比较内存地址equals
的话,它是属于java.lang.Object
类里面的方法,如果该方法没有被重写过默认也 是==
;我们可以看到String
等类的equals
方法是被重写过的,而且String
类在日常开发中 用的比较多,久而久之,形成了equals
是比较值的错误观点- 具体要看自定义类里有没有重写
Object
的equals
方法来判断 - 通常情况下,重写
equals
方法,会比较类中的相应属性是否都相等
equals()
重写
重点是比较两个对象的内容是否都相等
重写实例:
package day12case;
public class Case2 {
public static void main(String[] args) {
Animal an1=new Animal(1,"blue");
Animal an2=new Animal(1,"blue");
System.out.println(an1.equals(an2));
}
}
class Animal{
private int age;
private String color;
public Animal(){
}
public Animal(int age,String color){
this.age=age;
this.color=color;
}
public void show(){
System.out.println("Animal age is: "+age+" color is "+color);
}
//重写equals方法
public boolean equals(Object obj){
if(this==obj)
return true;
if(obj instanceof Animal){
Animal animal=(Animal) obj;
return animal.age==this.age && animal.color.equals(this.color);
//属性为基本数据类型用==
//引用数据类型用
}
return false;
}
}
toString()
的使用
-
当我们输出一个对象的引用时,实际上就是调用当前对象的
toString()
-
//实例化对象,类为Animal Animal animal=new Animal(); System.out.println(animal); System.out.println(animal.toString()); //以上两条语句运行的结果一致
-
-
Object
类中toString()
的定义:
-
String
,Data
等类都对toString()
方法进行了重写 -
我们自定类时,也可以重写
toString()
方法,使其返回我们感兴趣的实体内容
单元测试方法的使用
-
Eclipse
添加JUnit4
-
选中当前工程
-
右键选择
build path
-
添加
Libraries
-
-
创建
Java
类,进行单元测试Java
类的要求:- 类的权限为
public
- 此类提供无参构造器
- 类的权限为
-
在类中定义测试方法
此时的测试方法:
- 权限修饰符为
public
- 没有返回值和形参
- 权限修饰符为
-
在单元测试的方法上添加注解
@Test
,并导入对应的包`` -
可以在测试方法体内测试相关代码
-
完成代码编写后,左键双击单元测试方法名,右键
run as
–JUnit Test
-
注意事项:测试类名最好包含
Test
字段,要不然导入相关包时会出错
包装类(Wrapper)的使用
定义:
针对八种基本数据类型定义相应的引用类型——包装类
使得基本数据类型也具有面向对象特性,可以调用对应的属性和方法
基本数据类型与包装类以及String
类之间的相互转换
包装类常见面试题:
1.![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/98ba8cff616656976fdf75b39cfe12a3.png#pic_center)
2.![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/f865c9a7b46d6c624604af7f1f9c5241.png#pic_center)
原因:
-
第一个结果为
flase
,对于引用数据类型,==
比较的是对象的地址 -
第二个结果为
true
,因为为了提高性能,在Integer
内部定义了IntegerCache
结构,IntegerCache
中定义了Integer[]
,保存了从-128~127
范围内的整数,如果使用自动装箱的方式,给Integer
赋值的范围在-128~127
范围内,可以直接使用数组中元素,不用再new
新的值,所以两者的地址相同
- 第三个结果为
false
,原因可有1,2
综合得到
据类型,==
比较的是对象的地址
-
第二个结果为
true
,因为为了提高性能,在Integer
内部定义了IntegerCache
结构,IntegerCache
中定义了Integer[]
,保存了从-128~127
范围内的整数,如果使用自动装箱的方式,给Integer
赋值的范围在-128~127
范围内,可以直接使用数组中元素,不用再new
新的值,所以两者的地址相同[外链图片转存中…(img-2Ytbw2t6-1629531134867)]
-
第三个结果为
false
,原因可有1,2
综合得到