方法重写和多态

目录

1. 类类型的属性

2. 数组类型的属性

3. 重写toString

4. 重写equals方法

5. 重写hashcode方法

7. 多态

7.1 向上转型

7.2 向下转型


1. 类类型的属性

自定义的类型,可以作为属性类型,属于引用数据类型,跟String性质相同

2. 数组类型的属性

我们自定义的类型,也可以作为数组的类型,依然属于引用数据类型,数组中每个元素为我们自定义的数据类型

public class Person {
    private  String name;
    private int age;
    private Address address;
    private Hobby[] hobbies;

    public void setHobbies(Hobby [] hobbies){
        this.hobbies = hobbies;
    }
    public Hobby[] getHobbies(){
        return hobbies;
    }
    public void setAddress(Address address){
        this.address =address;
    }
    public Address getAddress(){
        return address;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
public class Address {
    private String province;
    private String city;
    private String area;
    private String street;
    private String zipCode;

    public String getProvince() {
        return province;
    }
    public void setProvince(String province) {
        this.province = province;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
    public String getArea() {
        return area;
    }
    public void setArea(String area) {
        this.area = area;
    }
    public String getStreet() {
        return street;
    }
    public void setStreet(String street) {
        this.street = street;
    }
    public String getZipCode() {
        return zipCode;
    }
    public void setZipCode(String zipCode) {
        this.zipCode = zipCode;
    }
}
public class Hobby {
    private String hobbyType;
    private String hobbyName;

    public String getHobbyType() {
        return hobbyType;
    }
    public void setHobbyType(String hobbyType) {
        this.hobbyType = hobbyType;
    }
    public String getHobbyName() {
        return hobbyName;
    }
    public void setHobbyName(String hobbyName) {
        this.hobbyName = hobbyName;
    }
}
public class TestPerson {
    public static void main(String[] args) {
        Person p1 = new Person();
        p1.setName("赵四");
        p1.setAge(20);

        Address add1 = new Address();
        add1.setProvince("广东省");
        add1.setCity("东莞市");
        add1.setArea("大朗区");
        add1.setStreet("文化路");
        add1.setZipCode("234578");

        p1.setAddress(add1);

        System.out.println(p1.getName());
        System.out.println(p1.getAge());
        System.out.println(p1.getAddress());
        System.out.println(p1.getAddress().getProvince());
        System.out.println(p1.getAddress().getCity());
        System.out.println(p1.getAddress().getArea());
        System.out.println(p1.getAddress().getStreet());
        System.out.println(p1.getAddress().getZipCode());

        System.out.println("==========================================================");

        Hobby [] hobbies = new Hobby[2];

        hobbies[0] = new Hobby();
        hobbies[0].setHobbyType("文艺类");
        hobbies[0].setHobbyName("尬舞");

        Hobby hobby = new Hobby();
        hobby.setHobbyType("体育类");
        hobby.setHobbyName("篮球");
        hobbies[1] = hobby;

        System.out.println(Arrays.toString(hobbies));

        p1.setHobbies(hobbies);

        Hobby[] hobbies1 = p1.getHobbies();

        System.out.println("-------------------------------------------");

        for(int i = 0;i < hobbies1.length;i++){
            System.out.println(hobbies1[i]);
            System.out.println(hobbies1[i].getHobbyType());
            System.out.println(hobbies1[i].getHobbyName());
        }
    }
}

3. 重写toString

1.为什么我们自定义的类可以直接调用toString方法

    因为我们写的类默认继承自Object类,toString方法是从Object继承而来的方法

2.调用toString方法后返回给我们的是包名+类名+@+hash值

    因为Object类中toString方法就是这么实现的

3.直接输出一个对象相当于调用此对象的toString 方法  这是JDK设定的

4.重写的目的

    为提高开发的便捷性,使输出一个对象将可以直接查看此对象的属性值

    且更方便,无需单独调用各个属性的getter方法

public class Person{
    private  String name;
    private int age;
    private char sex;

    public char getSex() {
        return sex;
    }
    public void setSex(char sex) {
        this.sex = sex;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Person(String name, int age, char sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    public Person() {
    }
    public String toString() {

        return "Person{name = " + name + ",age =  " + age + ",sex = " + sex + " }";
    }
    public static void main(String[] args) {
        Person p1 = new Person("赵四",20,'男');

        System.out.println(p1.toString());
        System.out.println(p1);
    }
}

4. 重写equals方法

1. == 和 equals 的区别?

== 比较基本数据类型  比较的是值

== 比较引用数据类型  比较的是地址

equals方法本身也比较地址 但经过重写自定义了比较规则

2.只要是new出来的对象 其地址 任何时候都不会相同

3.重写equals方法的目的,使我们可以重写equals方法,改变比较规则

public class Person {
    private String name;
    private String idCard;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getIdCard() {
        return idCard;
    }

    public void setIdCard(String idCard) {
        this.idCard = idCard;
    }

    public Person(String name, String idCard) {
        this.name = name;
        this.idCard = idCard;
    }
    public Person() {
    }
    public boolean equals(Object obj){
        if(this == obj){
            return true;
        }
        Person person = (Person)obj;

        if( this.name.equals(person.name) && this.idCard.equals(person.idCard)){
            return true;
        }
        return false;
    }
    public static void main(String[] args) {
        Person p1 = new Person("赵四", "8945871452685623598541");
        Person p2 = new Person("赵四", "8945871452685623598541");

        System.out.println(p1 == p2); //  false
        System.out.println(p1.equals(p2)); // false

        System.out.println("-----------------------------------------------------------");

        String str1 = new String("abc");
        String str2 = new String("abc");

        System.out.println(str1 == str2);
        System.out.println(str1.equals(str2));
    }
}

5. 重写hashcode方法

1.hashCode方法的作用?

    返回当前对象的hashCode值  是一个十进制int类型的整数数值

2.什么是hash值?

    hash算法  杂凑算法  根据一些混乱的  复杂的条件  所计算出来的一个数值

    hash值就是使用杂凑算法  根据地址等信息所计算出来的一个十进制数值

3.为什么要重写hashCode方法呢?

    1.在实际开发中 重写equals必须要重写hashCode方法  这两个方法共进退

    2.默认情况下 equals 比较为 true 的两个对象 hashCode 也相同 

        分析:默认情况下 我们使用父类的 equals 方法  对两个对象的地址进行比较

        此时  只要结果为true  那么表示这两个对象地址相同  同时 hashCode 也相同

        目前我们对 equals 方法进行了重写  打破了这种规则  所以我们还需要继续重写         hashCode 方法,继续维持这个规则

4.重写hashCode方法最终要实现的效果

        两个对象equals 为true 保证hashCode也相同

        目前用equals方法对名字和身份证号的比较进行重写

        所以hashCode方法也应该使用名字和身份证号计算hash值

5.String类重写了 equals方法 将原本的比较地址重写为了比较地址且比较内容

        同时也重写了hashCode 不在根据地址计算hash值  而是根据字符串的内容计算hash值

        也就是,内容相同的字符串 hash值都相同

6.为什么计算hashCode要使用 31?

        使用任意数字计算hashCode都可以

        因为JDK中也使用 31 来计算hashCode

        因为 31 是一个特殊的质数  任何数乘以 31 等于这个数左移5位  减去这个数本身

        总之:使用31 计算hash值效率更高

public class Person {
    private String name;
    private String idCard;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getIdCard() {
        return idCard;
    }
    public void setIdCard(String idCard) {
        this.idCard = idCard;
    }
    public Person(String name, String idCard) {
        this.name = name;
        this.idCard = idCard;
    }
    public Person() {
    }
    public boolean equals(Object obj){
        if(this == obj){
            return true;
        }
        Person person = (Person)obj;

        if( this.name.equals(person.name) && this.idCard.equals(person.idCard)){
            return true;
        }
        return false;
    }
    public  int hashCode(){
        int prime = 678; // 权重 决定性因素之一
        int result = 1; // 用于最终返回的结果

        result = prime * result + (this.name == null ? 0 : this.name.hashCode());
        result = prime * result + (this.idCard == null ? 0 : this.idCard.hashCode());

        return result;
    }
    public static void main(String[] args) {
        Person p1 = new Person("赵四", "8945871452685623598541");
        Person p2 = new Person("赵四", "8945871452685623598541");

        System.out.println(p1 == p2);
        System.out.println(p1.equals(p2));

        System.out.println(p1.hashCode());
        System.out.println(p2.hashCode());

        System.out.println("-------------------------------------------------");

        System.out.println(p1.toString());

        String str1 = new String("abc hello world 666");
        String str2 = new String("abc hello world 666");

        System.out.println(str1.equals(str2));
        System.out.println(str1.hashCode());
        System.out.println(str2.hashCode());

        String str3 = new String("abc");
        String str4 = new String("acb");

        System.out.println(str3.hashCode());
        System.out.println(str4.hashCode());
    }
}
public class TestPrime {
    public static void main(String[] args) {
        int a = 20;
        System.out.println(20 * 31);
        System.out.println((20 << 5) - 20);
    }
}

7. 多态

7.1 向上转型

同一种事物,由于条件不同,产生的结果也不同

1.多态:父类引用 指向子类对象        同一个引用类型,使用不同的实例而执行不同的操作

        等号左边是引用   右边是对象,即实例

2.多态的前提:

        1.必须要有继承

        2.通常(99%)的需要方法重写

3.为什么要使用多态?

        提高程序灵活性

向上转型

多态:父类引用指向子类对象

向上转型,能够访问的是子类重写父类  或者  继承父类的方法,不能访问子类独有的方法

1.父类作为形参,子类作为实参

2.父类做为声明返回值 实际返回值为子类类型

3.父类类型的数组/集合/其元素为子类类型

public class Pet {
    private String name;
    private int health;
    private int love;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getHealth() {
        return health;
    }

    public void setHealth(int health) {
        this.health = health;
    }

    public int getLove() {
        return love;
    }

    public void setLove(int love) {
        this.love = love;
    }

    public void print(){
        System.out.println("宠物的名字是:" + name);
        System.out.println("宠物的健康值是:" + health);
        System.out.println("宠物的亲密值是:" + love);
    }

    public void cure(){
        System.out.println("宠物看病");
    }
}
public class Dog extends Pet {
    private String strain;

    public String getStrain() {
        return strain;
    }

    public void setStrain(String strain) {
        this.strain = strain;
    }

    @Override
    public void print(){
        super.print();
        System.out.println("狗狗的品种是:" + strain);
    }

    public void cure(){
        super.cure();
        System.out.println("狗狗看病,打针,吃骨头,健康值恢复了");
        this.setHealth(100);
    }
}
public class Penguin extends Pet {
    private String sex;  // alt + insert

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public void print(){
        super.print();
        System.out.println("企鹅的性别是:" + sex);
    }

    public void cure(){
        super.cure();
        System.out.println("企鹅看病,打针,疗养,吃小鱼,健康值");
        this.setHealth(100);
    }
}
public class Master {
    public void toHospitalWithDog(Dog dog){
        dog.cure();
    }

    public void toHospitalWithPenguin(Penguin penguin){
        penguin.cure();
    }

    // 分析:以上通过编写两个方法实现了给两种宠物看病 这种方式可以解决问题 但是不太合理
    // 因为 如果后续有更多的宠物子类 则需要继续编写更多的方法来实现 这样不符合软件开发的:开闭原则
    // 开 程序需要对扩展开放
    // 闭 程序需要对修改源代码关闭
    // 我们应该编写一个方法用于实现给所有的宠物看病

    public void toHospitalWithPet(Pet pet){ // = new Dog() ; = new Penguin()
        pet.cure();

    }

    public Pet givePet(String str){//声明父类返回值
        if(str.equals("一等奖")){
            return new Penguin();  //实际返回值为子类类型
        }else if(str.equals("二等奖")){
            return new Dog();
        }
        return new Cat();
    }
}
public class TestMaster {
    public static void main(String[] args) {
        Master zs = new Master();
        Dog dog = new Dog();
        dog.setHealth(66);
        zs.toHospitalWithDog(dog);

        System.out.println(dog.getHealth());


        Penguin penguin = new Penguin();
        penguin.setHealth(20);
        zs.toHospitalWithPenguin(penguin);
        System.out.println(penguin.getHealth());

        System.out.println("------------------------------------------------");

        // 回顾继承的一句话:子类是父类 子类与父类是is-a的关系

        Dog dog1 = new Dog();
        dog1.setHealth(20);

        Penguin penguin1 = new Penguin();
        penguin1.setHealth(20);


        zs.toHospitalWithPet(dog1);

        System.out.println("------------------------------------------------");
        zs.toHospitalWithPet(penguin1);


        Cat cat = new Cat();
        cat.setHealth(20);

//        zs.toHospitalWithDog(cat);
//        zs.toHospitalWithPenguin(cat);
        zs.toHospitalWithPet(cat);

        System.out.println("------------------------------------------------");

        Pet p = zs.givePet("一等奖");

        System.out.println("------------------------------------------------");

        Pet [] pets = new Pet[3];

        pets[0] = new Dog();//方式1 

        Penguin p1 = new Penguin();//方法2
        pets[1] = p1;
    }
}

7.2 向下转型

多态:父类引用指向子类对象    向上转型

   

向上转型:可以访问的是子类重写父类的属性、方法  或者  继承父类的方法

                不能访问子类独有的方法  如需访问  必须向下转型

必须先向上转型  才能向下转型

向下转型:是指将一个指向子类对象的父类类型  向下强制转换为子类类型

                不可以将一个指向父类对象的父类类型  强制转换为子类类型

向上转型是为了灵活性  向下转型是为了实用性

关于String 类  以及  我们自定义类重写equals方法的问题

1.为什么我们需要类型判断以及向下转型

因为我们重写的是父类Object类中的方法 而父类中equals方法的形参类型是为Object类型 而重写要求参数列表要完全一致 ,所以 我们也必须写为Object类型,但是在实际使用的过程中 我们如果需要使用到String 或者自定义类的属性 ,方法就必须向下转型

1.多态其实就是父类引用指向子类对象  属于向上转型  能够提高程序的灵活性

2.后续我们学习的抽象类 和接口 不能直接new对象  必须通过new 子类的方式创建对象

public class Person {
    private String name;
    private String idCard;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getIdCard() {
        return idCard;
    }

    public void setIdCard(String idCard) {
        this.idCard = idCard;
    }

    public Person(String name, String idCard) {
        this.name = name;
        this.idCard = idCard;
    }

    public Person() {
    }

    public boolean equals(Object obj){
        if(this == obj){
            return true;
        }
        if(obj instanceof  Person){
            Person person = (Person)obj;

            if( this.name.equals(person.name) && this.idCard.equals(person.idCard)){
                return true;
            }
        }
        return false;
    }
    public static void main(String[] args) {
        Person p1 = new Person("赵四", "8945871452685623598541");
        Person p2 = new Person("赵四", "8945871452685623598541");
     
        System.out.println(p1.equals("abc"));
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值