11.面向对象的特征三:多态性、Object类及内部的常用方法、子类对象实例化的全过程

1. 子类对象实例化的全过程(了解)

  • 从结果上来看
从结果上来看:就体现为类的继承性
 -  创建子类对象以后,子类的对象就获取了其父类,以及父类的父类,。。。。中的结构:属性、方法。
 -  在权限允许的情况下,通过子类对象就可以调用父类中继承过来的结构。
  • 从过程上来看
从过程上来看:
 -  当我们创建子类对象时,调用子类的构造器。子类的构造器一定会直接或间接的调用其父类的构造器,其父类的
 -  构造器也同样的直接或间接的调用它的父类的构造器,以此类推,一定会调用到java.lang.Object类的Object()
 -  的构造器为止。正因为调用了这些类的构造器,则会在内存中加载这些类,并提供给子类对象必要的结构来使用。
  • 注意点:
注意:虽然调用了父类的构造器,但是内存中自始至终,只创建了当前子类的对象。

在这里插入图片描述
在这里插入图片描述

2. oop的特征三:多态性

2.1多态性(向上转型)

面向对象的特征之三:多态性
  -  1.多态的理解:一种事物的多种形态
  -  2. 子类对象的多态性:子类的对象赋给父类的引用 (或父类的引用指向子类的对象)
  -  3.在多态的前提下,通过父类的引用调用方法只能是父类中声明的方法;(编译期)
    其次,真正运行时,执行的是子类重写父类的方法。(运行期)
   总结:编译看左边,运行看右边 (虚方法调用)
  - 4. 多态的使用前提:① 类的继承关系  ② 子类重写父类的方法
  - 5. 类的多态性指的“编译看左边,运行看右边”不适用于属性
  • 储备代码
public class Person {

    String name;
    int age;

    int id = 1001;

    public void eat(){
        System.out.println("人吃饭");
    }
    public void walk(){
        System.out.println("人走路");
    }

}

public class Man extends Person {

    boolean isSmoking;

    int id = 1002;

    public void eat(){
        System.out.println("男人应该多吃肉,长肌肉");
    }

    public void walk(){
        System.out.println("男人西装笔挺的走路");
    }

    public void earnMoney(){
        System.out.println("男人赚钱养家");
    }

}

public class Woman extends Person {
    boolean isBeauty;

    public void eat(){
        System.out.println("女人选择少吃,减肥~");
    }

    public void walk(){
        System.out.println("女人选择穿高跟鞋窈窕的走路");
    }

    public void goShopping(){
        System.out.println("女人选择逛街购物");
    }

}
  • 测试多态性
public class PersonTest {
    public static void main(String[] args) {

        //我们熟悉的场景:不属于多态性
        Person p1 = new Person();
        p1.eat();

        Man m1 = new Man();
        m1.eat();
        m1.earnMoney();

        int m = 10;
        int n = m;

        //基本数据类型中存在数据类型提升规则
        long l = m;
        System.out.println("##########多态的核心内容:###########");
        //子类对象的多态性:子类的对象赋给父类的引用 (或父类的引用指向子类的对象)
        Person p2 = new Man();
        Person p3 = new Woman();

        //多态的应用:虚方法调用:在多态的前提下,通过父类的引用调用方法只能是父类中声明的方法;(编译期)
        // 其次,真正运行时,执行的是子类重写父类的方法。(运行期)
        p2.eat();
        p2.walk();
//        p2.earnMoney();//编译不通过

        //属性不存在多态性
        System.out.println(p2.id);//1001
        }
 }
  • 多态性的好处,即多态的应用举例
    • 举例1:
public class AnimalTest {

    public static void main(String[] args) {
        AnimalTest test = new AnimalTest();
        Dog dog = new Dog();
        test.func(dog);

        test.func(new Cat());
    }

    public void func(Animal animal){ // Animal animal = new Dog();
        animal.eat();
        animal.jump();

        //编译不通过
//        animal.shout();

        if(animal instanceof Dog){
            Dog dog = (Dog)animal;
            dog.shout();
        }else if(animal instanceof Cat){
            Cat cat = (Cat)animal;
            cat.catchFish();
        }
    }
	//由于多态性的出现,就不需要定义如下的方法了
//    public void func(Dog dog){
//        dog.eat();
//        dog.jump();
//    }
//
//    public void func(Cat cat){
//        cat.eat();
//        cat.jump();
//    }
//
//    //....

}

class Animal{

    public void eat(){
        System.out.println("动物进食");
    }

    public void jump(){
        System.out.println("动物跳");
    }

}

class Dog extends Animal{
    public void eat(){
        System.out.println("狗吃骨头");
    }

    public void jump(){
        System.out.println("狗急跳墙");
    }

    public void shout(){
        System.out.println("狗吠");
    }
}
class Cat extends Animal{
    public void eat(){
        System.out.println("猫吃老鼠");
    }

    public void jump(){
        System.out.println("猫跳");
    }
    public void catchFish(){
        System.out.println("猫抓鱼");
    }
}
  • 举例2:
public boolean equals(Object obj){}
  • 举例3:
class Account{

 }

 class CheckingAccount extends Account{}//信用卡账户

class SavingAccount extends Account{}//储蓄卡账户
 //...

class Customer{

     Account acct;

     public void setAccount(Account acct){ //Account acct = new SavingAccount();
          this.acct = acct;
    }
 
 }

2.2 向下转型

Person p4 = new Man();
//        p4.earnMoney();//编译不通过
//        System.out.println(p4.isSmoking);//编译不通过
        //先明确:创建的子类Man的实例,在内存中是存在其特有的属性和方法的。
        //那如何调用?需要使用强转符:()
        Man m2 = (Man)p4;
        System.out.println(m2.isSmoking);
        m2.earnMoney();
        /*
        进行强转时,可能出现ClassCastException异常。
        建议在强转前,判断是否可以是指定的子类的类型。使用instanceof实现
         */
//        Woman w1 = (Woman)p4;
//        w1.goShopping();
        /*
        * 格式: a instanceof A :判断对象a是否是类A的实例
        * 如果是,则返回true;如果不是,返回false。
        *
        * 推论:如果a instanceof A返回true,则 a instanceof SuperA也返回true。其中SuperA是类A的父类
        *
        * */
        if(p4 instanceof Woman){
            Woman w1 = (Woman)p4;
            w1.goShopping();
        }else{
            System.out.println("不好意思,认错了!");
        }

        if(p4 instanceof Man){
            System.out.println("我是一个男人");
        }

        if(p4 instanceof Person){
            System.out.println("我是一个人");
        }

        if(p4 instanceof Object){
            System.out.println("我是一个Object");
        }
  • 小结
    在这里插入图片描述

2.3 练习

  • 练习1
/**
 *
 * 建立InstanceTest 类,在类中定义方法method(Person e);
     * 在method中:
     * (1)根据e的类型调用相应类的getInfo()方法。
     * (2)根据e的类型执行:
     * 如果e为Person类的对象,输出:
     * “a person”;
     * 如果e为Student类的对象,输出:
     * “a student”
     * “a person ”
     * 如果e为Graduate类的对象,输出:
     * “a graduated student”
     * “a student”
     * “a person”
 * 
 */
public class InstanceTest {

    public static void main(String[] args) {
        InstanceTest test = new InstanceTest();
        test.method(new Student());
        System.out.println();
        test.method(new Person());
    }

    public void method(Person e){

        System.out.println(e.getInfo());
        if(e instanceof Graduate){
            System.out.println("a graduated student");
        }
        if(e instanceof Student){
            System.out.println("a student");
        }
        if(e instanceof  Person){
            System.out.println("a person");
        }
    }
}

class Person {
    protected String name = "person";
    protected int age = 50;

    public String getInfo() {
        return "Name: " + name + "\n" + "age: " + age;
    }
}

class Student extends Person {
    protected String school = "pku";

    public String getInfo() {
        return "Name: " + name + "\nage: " + age
                + "\nschool: " + school;
    }
}

class Graduate extends Student {
    public String major = "IT";

    public String getInfo() {
        return "Name: " + name + "\nage: " + age
                + "\nschool: " + school + "\nmajor:" + major;
    }
}
  • 练习2
/**
 * 几何图形类
 *
 */
public class GeometricObject {

    protected String color;//颜色
    protected double weight;//权重

//    protected GeometricObject(){}

    protected 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;
    }
}
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;
    }

    public double findArea(){
        return 3.14 * 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.width = width;
        this.height = height;
    }

    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;
    }
    public double findArea(){
        return width * height;
    }

}
/**
 * 定义一个测试类GeometricObjectTest,
 * 编写equalsArea方法测试两个对象的面积是否相等(注意方法的参数类型,利用动态绑定技术),
 * 编写displayGeometricObject方法显示对象的面积(注意方法的参数类型,利用动态绑定技术)。
 *
 */
public class GeometricObjectTest {
    public static void main(String[] args) {
        GeometricObjectTest test = new GeometricObjectTest();

        Circle circle = new Circle(2.3, "red", 1.0);
        test.displayGeometricObject(circle);

        MyRectangle myRectangle = new MyRectangle(3.4, 2.3, "blue", 2.0);
        test.displayGeometricObject(myRectangle);

        test.equalsArea(circle,myRectangle);
    }

    public void equalsArea(GeometricObject o1,GeometricObject o2){
        boolean isEqual = o1.findArea() == o2.findArea();
        if(isEqual){
            System.out.println("面积相等");
        }else{
            System.out.println("面积不相等");
        }
    }

    public void displayGeometricObject(GeometricObject o ){
        System.out.println("几何图形的面积为:" + o.findArea());
    }
}

3. Object类及内部的常用方法

3.1 Object的认识

 * 1. Object类是所有Java类的根父类
 * 2. 如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类
 * 3. 重点讲解equals()和toString()
 *  * 面试题: 区分 finalize \ final \ finally

3.2 equals()的使用

  • 基本内容
 * 1. == 的使用
 *  ① 使用范围:基本数据类型、引用数据类型
 *  ② 使用在基本数据类型上,判断两个变量存储的数据值是否相等
 *    使用在引用数据类型上,判断两个引用的地址值是否相等。(判断两个引用是否指向内存中的同一个对象)
 *  *   对比:equals()只能使用在引用数据类型的变量上。
 *  * 2. equals()的使用
 * 2.1 java.lang.Object类中equals()的定义:
 *    public boolean equals(Object obj) {
 *         return (this == obj);
 *     }
 *  2.2 当自定义类没有重写equals()时,调用的就是Object类中定义的equals(),比较两个引用的地址值是否相等
 *  *  2.3 像String\日期类 Date \ File\包装类等已经重写了Object类中定义的equals(),用于判断两个对象
 *      的“实体内容”是否相等。
 *  * 2.4 开发中,对应自定义类,常常也需要重写equals(),用于判断两个对象的“实体内容”是否相等。
 *  *  * 面试题: 区分 == 和 equals()
  • 如何重写equals()
public class User {
    String name;
    int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public User() {
    }

    //手写的:
//    @Override
//    public boolean equals(Object obj) {
//        if(this == obj){
//            return true;
//        }
//        if(obj instanceof User){
//            User u = (User)obj;
//            //比较两个对象的属性是否都相等
            if(this.age == u.age && this.name.equals(u.name)){
                return true;
            }
            return false;
//
//            //简化为:
//            return this.age == u.age && this.name.equals(u.name);
//        }
//
//        return false;
//    }


    //自动生成:
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof User)) return false;

        User user = (User) o;

        if (age != user.age) return false;
        return name != null ? name.equals(user.name) : user.name == null;
    }
}

3.3 toString()的使用

  • 基本知识
* 0. 当我们print(对象名)时,实际上与print(对象名.toString())是一样的。
*
* 1. Object类中toString()的定义:
*    public String toString() {
*         return getClass().getName() + "@" + Integer.toHexString(hashCode());
*     }
* 2. 自定义类在没有重写toString()时,就是默认调用Object类中的toString(),返回当前对象的类型和内存中的地址值。
*
* 3.像String\日期类 Date \ File\包装类等已经重写了Object类中定义的toString(),返回当前对象中
*  实体内容的信息
*
* 4. 对于自定义类,如果希望调用toString()时,显示对象的实体内容的信息,则可以考虑重写toString()
  • 重写toString()
public class User {
    String name;
    int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public User() {
    }


//    @Override
//    public String toString() {
//        return "User{ name : " + name + ",age : " + age +"}";
//    }


    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
  • 测试
public class ToStringTest {
    public static void main(String[] args) {
        User u1 = new User("Tom",12);
        System.out.println(u1.toString());//com.atguigu.java2.User@1540e19d --> User{ name : Tom,age : 12}
        System.out.println(u1);//com.atguigu.java2.User@1540e19d --> User{ name : Tom,age : 12}

        String str1 = new String("hello");
        String str2 = "abc";
        System.out.println(str1.toString());
        System.out.println(str2);

    }
}

4. 课后练习

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值