第五章 面向对象(中)
Java 面向对象学习的三条主线:
Java 类及类的成员:属性,方法,构造器,代码块,内部类
面向对象的三大特征:封装性,继承性,多态性,(抽象性)
其他关键字:this,super,static,final,abstract,interface,import等
5.5 面向对象特征之三:(多态性)
5.5.1 多态性的概述
多态性,指一个事物的多种形态,是面向对象中最重要的概念,
在Java中的体现:
对象的多态性:父类的引用指向子类的对象
可以直接应用在抽象类和接口上
5.5.2 多态性的使用
Java引用变量有两个类型:编译时类型和运行时类型。编译时类型由声明该变量时使用的类型决定,运行时变量由实际赋给该变量的对象决定,简称:编译时,看左边,运行时,看右边。
若编译时类型和运行时类型不一致,就出现了对象的多态性(Polymorphism)
多态情况下,“看左边”:看的是父类的引用(父类中不具备子类持有的方法)
“看右边“:看的是子类的对象(实际运行的是子类重写父类的方法)
对象的多态性只适应方法,不适应属性
5.5.3 多态性的使用前提
①.有类的继承 ②.有方法的重写
5.5.4 虚拟方法调用(Virtual Method Invocation)
正常的方法调用
Person e= new Person();
e.getInfo();
虚拟方法调用(多态情况下)
子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父类根据付给它的不同子类对象,动态调用属于子类的方法。这样的方法调用在编译器是无法确定的。
Person e= new Student();
e.getInfo(); //调用Student类的getInfo()方法
编译时类型和运行时类型
编译时e为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类的getInfo()方法。 ——动态绑定
运行时行为,证明见上
5.5.5 instanceof 操作符
x instanceof A:检验x是否为类A的对象,返回值为boolean型。
要求x所属的类与类A必须是子类和父类的关系,否则编译错误。
如果x属于类A的子类B,x instanceof A值也为true。
public class InstanceTest {
public static void main(String[] args) {
InstanceTest instanceTest = new InstanceTest();
instanceTest.method(new Student());
}
public void method(Person e){
String info = e.getInfo();
System.out.println(info);
if (e instanceof Graduate){
System.out.println("a graduated student");
System.out.println("a student");
System.out.println("a person");
}else if (e instanceof Student){
System.out.println("a student");
System.out.println("a person");
}else {
System.out.println("a person");
}
}
}
5.5.6 向下转型
5.5.7 多态性的使用实例
public class Test {
public static void main(String[] args) {
show(new Cat()); // 以 Cat 对象调用 show 方法
show(new Dog()); // 以 Dog 对象调用 show 方法
Animal a = new Cat(); // 向上转型
a.eat(); // 调用的是 Cat 的 eat
Cat c = (Cat)a; // 向下转型
c.work(); // 调用的是 Cat 的 work
}
public static void show(Animal a) {
a.eat();
// 类型判断
if (a instanceof Cat) { // 猫做的事情
Cat c = (Cat)a;
c.work();
} else if (a instanceof Dog) { // 狗做的事情
Dog c = (Dog)a;
c.work();
}
}
}
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void work() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void work() {
System.out.println("看家");
}
}
public class GeometricObject {//几何图形
private String color;
private double weight;
public GeometricObject(String color, double weight) {
this.color = color;
this.weight = weight;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public double findArea(){
return 0.0;
}
}
public class Circle extends GeometricObject{
private double radius;
public Circle(double radius,String color, double weight) {
super(color, weight);
this.radius=radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
@Override
public double findArea() {
return Math.PI*radius*radius;
}
}
public class MyRectangle extends GeometricObject{
private double width;
private double height;
public MyRectangle(double width,double height,String color, double weight) {
super(color, weight);
this.height=height;
this.width=width;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
@Override
public double findArea() {
return height*width;
}
}
/*
* 定义一个测试类GeometricTest,
* 编写equalsArea方法测试两个对象的面积是否相等(注意方法的参数类型,利用动态绑定技术),
* 编写displayGeometricObject方法显示对象的面积(注意方法的参数类型,利用动态绑定技术)。
*
*/
public class GeometricTest {
public static void main(String[] args) {
GeometricTest geometricTest=new GeometricTest();
Circle circle=new Circle(2,"white",1.0);
Circle circle1=new Circle(3,"white",1.0);
boolean isEquals = geometricTest.equalsArea(circle,circle1);
System.out.println(isEquals);
MyRectangle myRectangle= new MyRectangle(2,3,"black",1.0);
System.out.println(geometricTest.displayGeometricObject(myRectangle));
}
public double displayGeometricObject(GeometricObject o) {//GeometricObject o = new Circle(...)
return o.findArea();
}
public boolean equalsArea(GeometricObject o1, GeometricObject o2) {
return o1.findArea() == o2.findArea();
}
}
5.5.8 继承成员变量和继承方法的区别:实例说明:
①.若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中:编译看左边,运行看右边
②.对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量:编译运行都看左边
5.6 Object类的使用
5.6.1 Object类的概述
Object类是所有Java类的根父类,只声明了一个空参的构造器
如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类
5.6.2 Object类的方法
Object类中的功能(属性,方法)就具有通用性。
属性:无
方法:equal() / toString() / getClass() / hashCode() / clone() / finalize() / wait() / notify() / notifyAll()
5.6.3 equal()方法的使用
面试题: == 和equals( )的区别
①.” == “可以使用在基本数据类型变量和引用数据类型变量中
如果比较的是基本数据类型,比较两个变量保存的数据是否相等。(不一定类型要相同)
如果比较的是引用型数据变量,比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体(类型要相同)
基本数据类型比较
引用型数据变量
②. equals( )是一个方法,而非运算符,只能适用于引用数据类型
Object类中的equlas( )的定义:
public boolean equals(Object obj) {
return (this == obj);
}
//说明:Object类中定义的equlas( )和 == 的作用是相同的,比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体
而String,Date,File,包装类等都重写了Obejct类中的equals( )方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的”实体内容“是否相同。
public class test {
public static void main(String args[]) {
Kids kids1 = new Kids(1);
Kids kids2 = new Kids(1);
boolean equals = kids1.equals(kids2);//false
System.out.println(equals);
String s1 = new String("a");
String s2 = new String("a");
boolean equals1 = s1.equals(s2);//true
System.out.println(equals1);
}
}
5.6.4 重写equlas( )方法
通常情况下,我们自定义类中使用equlas( )方法也是为了比较”实体内容“是否相同,那么我们就需要对在自定义类中对equlas( )方法进行重写,重写的原则是比较两个对象的实体是否相同。
//自定义类中equals()方法的重写
//Class :自定义类的类名
//a :自定义类中的变量名
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Class cla = (Class) o;
return a == cla.a;
}
5.6.5 equlas( )方法的练习实例
//练习1
import java.util.Objects;
public class Oder {
private int orderId;
private String orderName;
public Oder() {
}
public Oder(int orderId, String orderName) {
this.orderId = orderId;
this.orderName = orderName;
}
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
//重写Object父类的equals()方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Oder oder = (Oder) o;
return orderId == oder.orderId && Objects.equals(orderName, oder.orderName);
}
}
public class OderTest {
public static void main(String[] args) {
Oder oder1 = new Oder(88, "lisi");
Oder oder2 = new Oder(88, "lisi");
System.out.println(oder1.equals(oder2));//结果为:true
}
}