Java面向对象(五)

Java面向对象(五)

十六、面向对象特征之三: 多态性

16.1 多态性的定义:

  • 对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)。

    可以直接应用在抽象类和接口上

  • Java 引用变量有两个类型:编译时类型和运行时类型。

    编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定

    简称:编译时,看左边;运行时,看右边。

  • 若编译时类型和运行时类型不一致,就出现了对象的多态性。

public class Person {
	......
}

public class Man extends Person{
	......
}

public class Weman extends Person{
	......
}

public class PersonTest {
	
	public static void main(String[] args) {
		
		Person p1 = new Person();
		Man man = new Man();
		
		//对象的多态性:父类的引用指向子类的对象
        //编译时声明了一个Person类型的变量p2,运行时实际引用的是Man类型的实例对象
        //所以,当调用子父类同名同参数的方法时,实际执行的是子类重写父类的方法 ---虚拟方法调用
		Person p2 = new Man();
		Person p3 = new Woman();
		
	}
}

16.2 多态性的使用:

  1. 虚拟方法调用(Virtual Method Invocation):

    • 正常方法调用:

      Person e = new Person();
      e.getInfo();
      Student e = new Student();
      e.getInfo();
      
    • 虚拟方法调用(多态情况下):

      子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法确定的。

      Person e = new Student();
      e.getInfo(); //调用Student类的getInfo()方法
      
      /*
      编译时e为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类的getInfo()方法。——动态绑定
      */
      
  2. 多态性的使用前提:① 类的继承关系 ② 方法的重写

  3. 对象的多态性,只适用于方法,不适用于属性(属性值编译和运行都看左边)。

  4. 多态性使用举例:

    import java.sql.Connection;
    
    //多态性的使用举例一:
    public class AnimalTest {
    	
    	public static void main(String[] args) {
    		
    		AnimalTest test = new AnimalTest();
    		test.func(new Dog());		//输出:狗进食 狗叫
    		
    		test.func(new Cat());		//输出:猫进食 猫叫
    	}
    	
    	public void func(Animal animal){	//Animal animal = new Dog();
    		animal.eat();
    		animal.shout();
    
    	}
    }
    
    
    class Animal{
    	
    	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("狗叫");
    	}
    	
    	public void watchDoor(){
    		System.out.println("狗看门");
    	}
    }
    class Cat extends Animal{
    	public void eat(){
    		System.out.println("猫进食");
    	}
    	
    	public void shout(){
    		System.out.println("猫叫");
    	}
    }
    
    //举例二:
    
    class Order{
    	
    	public void method(Object obj){
    		
    	}
    }
    
    //举例三:数据库连接
    class Driver{
    	
    	public void doData(Connection conn){//conn = new MySQlConnection(); / conn = new OracleConnection();
    		//规范的步骤去操作数据
    //		conn.method1();
    //		conn.method2();
    //		conn.method3();
    		
    	}
    }
    
    

16.3 多态典型例题

public class InterviewTest1 {

    public static void main(String[] args) {
        Base1 base = new Sub1();
        base.add(1, 2, 3);			//输出:sub_1

        Sub1 s = (Sub1)base;
        s.add(1,2,3);				//输出:sub_2
    }
}

class Base1 {
    public void add(int a, int... arr) {
        System.out.println("base1");
    }
}

class Sub1 extends Base1 {

    public void add(int a, int[] arr) {
        System.out.println("sub_1");
    }

    public void add(int a, int b, int c) {
        System.out.println("sub_2");
    }

}

//	public void add(int a, int... arr) 和 public void add(int a, int[] arr) 是方法重写。

十七、instanceof 关键字

17.1 instanceof 的引入:

  • 有了对象的多态性以后,该对象实例在内存中不仅加载了父类的属性和方法,实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。

  • 如何才能调用子类特有的属性和方法?
    向下转型:使用强制类型转换符。

Person p2 = new Man();
//p2变量声明为 Person 类型,不能调用子类 Man 类特有的方法
//p2.earnMoney();
//p2.isSmoking = true;

//向下转型
Man m1 = (Man)p;
m1.earnMoney();
m1.isSmoking = true;

//使用强转时,可能出现ClassCastException的异常。
//		Woman w1 = (Woman)p2;	编译通过,运行报错。
//		p2变量是一个Person类型的变量,但定义时new的是Man型,实际上指向Man型的对象
//		w1.goShopping();
  • 为了避免在向下转型时出现 ClassCastException 的异常,我们在向下转型之前,先进行 instanceof 的判断,一旦返回 true,就进行向下转型。如果返回 false,不进行向下转型。
		//问题一:编译时通过,运行时不通过
		//举例一:
//		Person p3 = new Woman();
//		Man m3 = (Man)p3;
		//举例二:
//		Person p4 = new Person();
//		Man m4 = (Man)p4;

		
		//问题二:编译通过,运行时也通过
//		Object obj = new Woman();
//		Person p = (Person)obj;
		
		//问题三:编译不通过
//		Man m5 = new Woman();
		
//		String str = new Date();
		
//	总结:可以这么理解,子类在创建时会加载所有的父类,转型也只能在已加载的类之间相互转型。
//	否则,就算是编译不报错,运行也会报错!

17.2 instanceof 的使用:

  • a instanceof A:判断对象a是否是类A的实例。如果是,返回 true;如果不是,返回 false。

  • 当类B是类A的父类。

    如果 a instanceof A 返回 true,则 a instanceof B 也返回 true。

public class Person extends Object {…}
public class Student extends Person {…}
public class Graduate extends Person {…}

public void method1(Person e) {
       if (e instanceof Person)
// 处理Person类及其子类对象
       if (e instanceof Student)
//处理Student类及其子类对象
       if (e instanceof Graduate)
//处理Graduate类及其子类对象
}

17.3 向下转型和向上转型拓展

  1. 从子类到父类的类型转换可以自动进行。

  2. 从父类到子类的类型转换必须通过造型(强制类型转换)实现。

  3. 无继承关系的引用类型间的转换是非法的。(类型转换异常)

十八、Object 类的使用

18.1 Object 类介绍

  1. Object 类是所有 Java 类的根父类。

  2. 如果在类的声明中未使用 extends 关键字指明其父类,则默认父类为 java.lang.Object 类。

  3. Object 类中的功能(属性、方法)就具有通用性。

​ 属性:无

​ 方法:equals(),toString() ,getClass(),hashCode(),clone(),finalize(),wait(),notify(),notifyAll()。

  1. Object 类只声明了一个空参的构造器。

18.2 == 与 equals() 方法

18.2.1 == 运算符
  1. 可以使用在基本数据类型变量和引用数据类型变量中。

  2. 如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等。(不一定类型要相同)

    public class EqualsTest {
        public static void main(String[] args) {
            //基本数据类型
            int i = 10;
            int j = 10;
            double d = 10.0;
            System.out.println(i == j);//true
            System.out.println(i == d);//true
    		
            char c = 10;
    		System.out.println(i == c);//true
    		
    		char c1 = 'A';
    		char c2 = 65;
    		System.out.println(c1 == c2);//true
        }
    }
    

如果比较的是引用数据类型变量:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体。

补充: == 符号使用时,必须保证符号左右两边的变量类型一致。

18.2.2 equals() 方法的使用
1. 是一个方法,而非运算符。
2. 只能适用于引用数据类型。
3. Object类中equals()的定义:
public boolean equals(Object obj) {
        return (this == obj);
}

说明:Object类中定义的equals()和==的作用是相同的:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体。

  1. 像 String、Date、File、包装类等都重写了 Object 类中的 equals() 方法。

    重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的"实体内容"是否相同

public class EqualsTest {
    public static void main(String[] args) {
     //引用类型:
		Customer cust1 = new Customer("Tom",21);
		Customer cust2 = new Customer("Tom",21);
		System.out.println(cust1 == cust2);//false
		
		String str1 = new String("xiaozhao");
		String str2 = new String("xiaozhao");
		System.out.println(str1 == str2);			//false
		
		System.out.println(cust1.equals(cust2));	//false(调用Object类中的equals()方法)
		System.out.println(str1.equals(str2));		//true
		
		Date date1 = new Date(32432525324L);
		Date date2 = new Date(32432525324L);
		System.out.println(date1.equals(date2));	//true
    }
}

public class Customer {
    public String name;
    public int age;
}
18.2.3 重写 equals() 方法
  • 通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。

    那么,我们就需要对 Object 类中的 equals() 进行重写。

  • 重写的原则:比较两个对象的实体内容是否相同。

  • 一般情况下,使用 IDE 自动重写 equals() 方法。

18.3 toString() 方法

  1. 当我们输出一个对象的引用时,实际上就是调用当前对象的 toString() 方法。
  2. Object类中toString()的定义:
public String toString() {
   return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
  1. 像 String、Date、File、包装类等都重写了 Object 类中的 toString() 方法。使得在调用对象的 toString() 时,返回"实体内容"信息。

  2. 自定义类也可以重写 toString() 方法,当调用此方法时,返回对象的"实体内容"。

    可以手动重写和自动重写,一般使用自动重写。

public class ToStringTest {
	public static void main(String[] args) {
		
		Customer cust1 = new Customer("Tom",21);
		System.out.println(cust1.toString());	//javase.ex.Customer@1b6d3586
		System.out.println(cust1);				//javase.ex.Customer@1b6d3586
		
		String str = new String("xiaozhao");
		System.out.println(str);				//xiaozhao
		
		Date date = new Date(4534534534543L);
		System.out.println(date.toString());	//Mon Sep 11 08:55:34 CST 2113
		
	}
}

public class Customer {
    public String name;
    public int age;

    public Customer(String name, int age) {
        this.name = name;
        this.age = age;
    }
/*自动重写的 toString 方法
        @Override
    public String toString() {
        return "Customer{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
*/
}
posted @ 2022-07-13 23:06  小钊丶  阅读(69)  评论(0编辑  收藏  举报