[零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04)

时间:2023-02-15 14:14:09
上季内容回顾: 1、final关键字
・ 修饰类不能被继承
・ 修饰方法不能被覆写
・ 修饰的变量就是一个常量,全局常量(public static final)
2、抽象类和接口
・ 抽象类:只包含一个抽象方法的类,抽象方法只需声明而不需要实现,必须有子类
・ 接口:只包含抽象方法和全局常量的类――接口,也是必须有子类
在实际中一个类很少会去继承一个已经完全实现好的类,基本上都是继承抽象类和实现接口。 本季主要知识点: 1、对象的多态性
2、instanceof关键字
3、Object类
对象的多态性 [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) 注意点:
为了清楚的阐述出概念,现在先使用普通类的继承关系。
向上转型: class A    
{    
        public void fun1()    
        {    
                System.out.println("A类===>public void fun1()");    
        }    
        public void fun2()    
        {    
                //fun2方法调用的是fun1方法    
                this.fun1();    
        }    
}    
class B extends A    
{    
        //覆写A类中的fun1()方法    
        public void fun1()    
        {    
                System.out.println("B类===>public void fun1()");    
        }    
        public void fun3()    
        {    
                System.out.println("B类===>public void fun3()");    
        }    
}    
public class Demo01    
{    
        public static void main(String args[])    
        {    
                B b = new B();    
                A a = new A();    
                b.fun1();    
                a.fun2();    
                b.fun3();    
        }    
}
[零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) 对象多态性体现在对象相互转型上面哈~ class A    
{    
        public void fun1()    
        {    
                System.out.println("A类===>public void fun1()");    
        }    
        public void fun2()    
        {    
                //fun2方法调用的是fun1方法    
                this.fun1();    
        }    
}    
class B extends A    
{    
        //覆写A类中的fun1()方法    
        public void fun1()    
        {    
                System.out.println("B类===>public void fun1()");    
        }    
        public void fun3()    
        {    
                System.out.println("B类===>public void fun3()");    
        }    
}    
public class Demo02    
{    
        public static void main(String args[])    
        {    
                //声明一个父类对象    
                A a = null;    
                //new B()是子类对象向父类对象转换    
                a = new B();    
                a.fun1();    
        }    
}

现在我们来看下a.fun1()调用的是哪个类的方法哈~ [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) class A    
{    
        public void fun1()    
        {    
                System.out.println("A类===>public void fun1()");    
        }    
        public void fun2()    
        {    
                //fun2方法调用的是fun1方法    
                this.fun1();    
        }    
}    
class B extends A    
{    
        //覆写A类中的fun1()方法    
        public void fun1()    
        {    
                System.out.println("B类===>public void fun1()");    
        }    
        public void fun3()    
        {    
                System.out.println("B类===>public void fun3()");    
        }    
}    
public class Demo02    
{    
        public static void main(String args[])    
        {    
                //声明一个父类对象    
                A a = null;    
                //new B()是子类对象向父类对象转换    
                //子类对象向父类对象转型之后,所调用的方法一定是被覆写过的方法    
                a = new B();    
                a.fun1();    
                a.fun2();    
        }    
}
子类对象向父类对象转型之后,所调用的方法一定是被覆写过的方法,这就是对象的向上转型哈~ [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) 向下转型: class A    
{    
        public void fun1()    
        {    
                System.out.println("A类===>public void fun1()");    
        }    
        public void fun2()    
        {    
                //fun2方法调用的是fun1方法    
                this.fun1();    
        }    
}    
class B extends A    
{    
        //覆写A类中的fun1()方法    
        public void fun1()    
        {    
                System.out.println("B类===>public void fun1()");    
        }    
        public void fun3()    
        {    
                System.out.println("B类===>public void fun3()");    
        }    
}    
public class Demo03    
{    
        public static void main(String args[])    
        {    
                //声明一个父类对象    
                A a = null;    
                //new B()是子类对象向父类对象转换    
                //子类对象向父类对象转型之后,所调用的方法一定是被覆写过的方法    
                a = new B();    
                a.fun1();    
                a.fun2();    
                a.fun3();    
        }    
}
现在我们来看下能否调用a.fun3()哈~ [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) 程序提示找不到fun3()方法,A类中没有fun3()方法哈,如果我们一定要调用的话,我们就要使用向下转型哈~ class A    
{    
        public void fun1()    
        {    
                System.out.println("A类===>public void fun1()");    
        }    
        public void fun2()    
        {    
                //fun2方法调用的是fun1方法    
                this.fun1();    
        }    
}    
class B extends A    
{    
        //覆写A类中的fun1()方法    
        public void fun1()    
        {    
                System.out.println("B类===>public void fun1()");    
        }    
        public void fun3()    
        {    
                System.out.println("B类===>public void fun3()");    
        }    
}    
public class Demo03    
{    
        public static void main(String args[])    
        {    
                //声明一个父类对象    
                A a = null;    
                //new B()是子类对象向父类对象转换    
                //子类对象向父类对象转型之后,所调用的方法一定是被覆写过的方法    
                a = new B();    
                //可以进行向下转型,需要使用强制性手段哈~    
                B b = (B)a;    
                b.fun3();    
        }    
}
验证下效果: [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) 这就是对象向下转型哈~ 观察以下一种代码,检查下有没问题哈~: class A    
{    
        public void fun1()    
        {    
                System.out.println("A类===>public void fun1()");    
        }    
        public void fun2()    
        {    
                //fun2方法调用的是fun1方法    
                this.fun1();    
        }    
}    
class B extends A    
{    
        //现在我们不覆写A类中的fun1()方法    
        public void funX()    
        {    
                System.out.println("B类===>public void fun1()");    
        }    
        public void fun3()    
        {    
                System.out.println("B类===>public void fun3()");    
        }    
}    
public class Demo04    
{    
        public static void main(String args[])    
        {    
                A a = new B();    
                a.fun1();    
        }    
}
程序找不到B类中被覆写的fun1()方法,所以去查找父类A中的fun1()方法了哈~ [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) class A    
{    
        public void fun1()    
        {    
                System.out.println("A类===>public void fun1()");    
        }    
        public void fun2()    
        {    
                //fun2方法调用的是fun1方法    
                this.fun1();    
        }    
}    
class B extends A    
{    
        //覆写A类中的fun1()方法    
        public void fun1()    
        {    
                System.out.println("B类===>public void fun1()");    
        }    
        public void fun3()    
        {    
                System.out.println("B类===>public void fun3()");    
        }    
}    
public class Demo04    
{    
        public static void main(String args[])    
        {    
                A a = new A();    
                a.fun1();    
        }    
}
现在对象实例化时没有子类哈,所以a.fun1()调用的是父类A中本身的fun1()方法 [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) 如果现在我们要调用fun3()方法呢?现在使用向下转型可以吗? class A    
{    
        public void fun1()    
        {    
                System.out.println("A类===>public void fun1()");    
        }    
        public void fun2()    
        {    
                //fun2方法调用的是fun1方法    
                this.fun1();    
        }    
}    
class B extends A    
{    
        //覆写A类中的fun1()方法    
        public void fun1()    
        {    
                System.out.println("B类===>public void fun1()");    
        }    
        public void fun3()    
        {    
                System.out.println("B类===>public void fun3()");    
        }    
}    
public class Demo04    
{    
        public static void main(String args[])    
        {    
                A a = new A();    
                //如果我们要调用fun3()方法呢?现在使用向下转型可以吗?    
                B b = (B)a;    
                b.fun3();    
        }    
}
这样修改的话,我们看下有没问题哈,验证一下,发现编译时没有错误,但执行时却出现ClassCastException错误了哈~ [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) 在程序开发中有两大错误是比较常见的:
NullPointerException:表示空指向异常,如果没有开辟堆内存空间,则出现此异常
ClassCastException:表示类转换异常,两个不相关的类的对象进行向下转型操作。
上面一个解释比较难理解哈,我们光看A类的话,我们不能知道A类有什么子类哈,但是如果我们光看B类的话,我们可以看出B类是继承A类的话,所以得出了下面一个结论。 结论:
在进行向下转型之前,两个对象必然先发生向上转型关系,这样好建立起关系,否则两个没有关系的对象是不能相互转型的。
对象多态性到底有那些用处呢? 如果不知道多态性的时候应该使用以下的方式编写代码,利用方法的重载完成。 class A    
{    
        public void fun1()    
        {    
                System.out.println("A类===>public void fun1()");    
        }    
        public void fun2()    
        {    
                //fun2方法调用的是fun1方法    
                this.fun1();    
        }    
}    
class B extends A    
{    
        //覆写A类中的fun1()方法    
        public void fun1()    
        {    
                System.out.println("B类===>public void fun1()");    
        }    
        public void fun3()    
        {    
                System.out.println("B类===>public void fun3()");    
        }    
}    
class C extends A    
{    
        //覆写A类中的fun1()方法    
        public void fun1()    
        {    
                System.out.println("C类===>public void fun1()");    
        }    
        public void fun4()    
        {    
                System.out.println("C类===>public void fun4()");    
        }    
}    
public class Demo05    
{    
        public static void main(String args[])    
        {    
                fun(new B());    
                fun(new C());    
        }    
        //现在要求定义几个方法,可以接收父类A的子类对象    
        //如果不知道多态性的时候应该使用以下的方式编写代码    
        public static void fun(B b)    
        {    
                b.fun2();    
        }    
        public static void fun(C c)    
        {    
                c.fun2();    
        }
    
}
[零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) 如果按此做法,就会面临一个很严重的问题:
・ 如果现在A类有30个子类,则方法要重写30遍。
所以此时就可以利用对象的多态性完成,因为所有的子类对象都可以向父类对象转换。
class A    
{    
        public void fun1()    
        {    
                System.out.println("A类===>public void fun1()");    
        }    
        public void fun2()    
        {    
                //fun2方法调用的是fun1方法    
                this.fun1();    
        }    
}    
class B extends A    
{    
        //覆写A类中的fun1()方法    
        public void fun1()    
        {    
                System.out.println("B类===>public void fun1()");    
        }    
        public void fun3()    
        {    
                System.out.println("B类===>public void fun3()");    
        }    
}    
class C extends A    
{    
        //覆写A类中的fun1()方法    
        public void fun1()    
        {    
                System.out.println("C类===>public void fun1()");    
        }    
        public void fun4()    
        {    
                System.out.println("C类===>public void fun4()");    
        }    
}    
public class Demo06    
{    
        public static void main(String args[])    
        {    
                fun(new B());    
                fun(new C());    
        }    
        //现在要求定义几个方法,可以接收父类A的子类对象    
        //现在使用多态性编写代码    
        public static void fun(A a)    
        {    
                a.fun2();    
        }    
}
现在我们就只留一个fun()方法,new B(),new C()都是A类的子类哈,所以现在不管调用时传什么子类,都调用所传子类被覆写的fun1()方法哈~~~这就是对象多态性带来的好处,谁被其实例化就具备这样的功能哈~如果父类设计的非常的完善,则方法中会非常的好写。 [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) 要求:
如果传入的是B类的对象,则要求再调用fun3()方法,如果传入的是C类的对象,则要求再调用fun4()
方法。
问题:
如何去判断一个对象是否是某个类的实例呢?这就需要instanceof关键字支持哈。
instanceof关键字 [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) class A    
{    
        public void fun1()    
        {    
                System.out.println("A类===>public void fun1()");    
        }    
        public void fun2()    
        {    
                //fun2方法调用的是fun1方法    
                this.fun1();    
        }    
}    
class B extends A    
{    
        //覆写A类中的fun1()方法    
        public void fun1()    
        {    
                System.out.println("B类===>public void fun1()");    
        }    
        public void fun3()    
        {    
                System.out.println("B类===>public void fun3()");    
        }    
}    
class C extends A    
{    
        //覆写A类中的fun1()方法    
        public void fun1()    
        {    
                System.out.println("C类===>public void fun1()");    
        }    
        public void fun4()    
        {    
                System.out.println("C类===>public void fun4()");    
        }    
}    
public class Demo07    
{    
        public static void main(String args[])    
        {    
                B b = new B();    
                System.out.println(b instanceof A);    
        }    
}
我们来判断下对象b是否是A类的实例哈,我们分析下哈,子类B可以直接向父类A转型哈,说明父类A可以接收子类B的实例,那两者必然有关系哈,我们验证一下,结果返回true哈,证明对象b是A类的实例哈~ [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) class A    
{    
        public void fun1()    
        {    
                System.out.println("A类===>public void fun1()");    
        }    
        public void fun2()    
        {    
                //fun2方法调用的是fun1方法    
                this.fun1();    
        }    
}    
class B extends A    
{    
        //覆写A类中的fun1()方法    
        public void fun1()    
        {    
                System.out.println("B类===>public void fun1()");    
        }    
        public void fun3()    
        {    
                System.out.println("B类===>public void fun3()");    
        }    
}    
class C extends A    
{    
        //覆写A类中的fun1()方法    
        public void fun1()    
        {    
                System.out.println("C类===>public void fun1()");    
        }    
        public void fun4()    
        {    
                System.out.println("C类===>public void fun4()");    
        }    
}    
public class Demo07    
{    
        public static void main(String args[])    
        {    
                B b = new B();    
                System.out.println(b instanceof A);    
                System.out.println(b instanceof B);    
        }    
}

对象b也肯定是B类的实例哈~ [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) class A    
{    
        public void fun1()    
        {    
                System.out.println("A类===>public void fun1()");    
        }    
        public void fun2()    
        {    
                //fun2方法调用的是fun1方法    
                this.fun1();    
        }    
}    
class B extends A    
{    
        //覆写A类中的fun1()方法    
        public void fun1()    
        {    
                System.out.println("B类===>public void fun1()");    
        }    
        public void fun3()    
        {    
                System.out.println("B类===>public void fun3()");    
        }    
}    
class C extends A    
{    
        //覆写A类中的fun1()方法    
        public void fun1()    
        {    
                System.out.println("C类===>public void fun1()");    
        }    
        public void fun4()    
        {    
                System.out.println("C类===>public void fun4()");    
        }    
}    
public class Demo07    
{    
        public static void main(String args[])    
        {    
                A a = new A();    
                System.out.println(a instanceof A);    
                System.out.println(a instanceof B);    
        }    
}
那相反对象a是B类的实例吗?验证显示不是哈~说明不能向子类转换哈~ [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) class A    
{    
        public void fun1()    
        {    
                System.out.println("A类===>public void fun1()");    
        }    
        public void fun2()    
        {    
                //fun2方法调用的是fun1方法    
                this.fun1();    
        }    
}    
class B extends A    
{    
        //覆写A类中的fun1()方法    
        public void fun1()    
        {    
                System.out.println("B类===>public void fun1()");    
        }    
        public void fun3()    
        {    
                System.out.println("B类===>public void fun3()");    
        }    
}    
class C extends A    
{    
        //覆写A类中的fun1()方法    
        public void fun1()    
        {    
                System.out.println("C类===>public void fun1()");    
        }    
        public void fun4()    
        {    
                System.out.println("C类===>public void fun4()");    
        }    
}    
public class Demo08    
{    
        public static void main(String args[])    
        {    
                fun(new B());    
                System.out.println("#########################");    
                fun(new C());    
        }    
        public static void fun(A a)    
        {    
                a.fun2();    
                if (a instanceof B)    
                {    
                        B b = (B)a;    
                        b.fun3();    
                }    
                if (a instanceof C)    
                {    
                        C c = (C)a;    
                        c.fun4();    
                }    
        }    
}
这就是instanceof关键字的作用哈~ [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) Instanceof的使用时机:
一般情况下都是在转型之前进行一下判断,这样就可以进行比较安全的转型操作。
Object类 [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) 在Java中用户所编写的一切类都是一个类的子类,称为Object类。 [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) 实际上此类默认继承了Object类,以上代码等价于以下代码: [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) Object类的作用:
・ 如果一个好的类需要覆写Object类中的三个方法:
|- public String toString():对象输出时的操作
|- public boolean equals(Object obj):对象比较时的操作
|- public int hashCode(): 返回该对象的哈希码值。
class Student //extends Object    
{    
        private String name;    
        private int age;    
        public Student(String name,int age)    
        {    
                this.name = name;    
                this.age = age;    
        }    
}    
public class Demo09    
{    
        public static void main(String args[])    
        {    
                System.out.println(new Student("王乾",27));    
        }    
}
现在我们看下效果哈~ [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) 现在Student类是Object类的子类哈,那我们加上toString()看下效果 class Student //extends Object    
{    
        private String name;    
        private int age;    
        public Student(String name,int age)    
        {    
                this.name = name;    
                this.age = age;    
        }    
}    
public class Demo09    
{    
        public static void main(String args[])    
        {    
                System.out.println(new Student("王乾",27).toString());    
        }    
}
我们发现和没加toString()之前的效果一样哈~ [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) 加和不加都是一样滴,那我们下面就覆写Object类的toString()方法哈~ class Student //extends Object    
{    
        private String name;    
        private int age;    
        public Student(String name,int age)    
        {    
                this.name = name;    
                this.age = age;    
        }    
        public String toString()    
        {    
                return "Michael";    
        }    
}    
public class Demo09    
{    
        public static void main(String args[])    
        {    
                System.out.println(new Student("王乾",27));    
        }    
}

现在我们再来执行下看下效果,现在程序输出打印字符串“Michael”了哈~ [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) 我们查下System的JDK文档,找到out.print()方法哈~ [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) 实际上out.print()方法是调用的这个方法哈~ [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) 所以System.out.println(new Student("王乾",27));这行代码会默认调用toString()方法,它会找到Student类中被子类覆写的toString()方法哈~Student子类向Object父类进行向上转型,只要方法被子类覆写了,则此时要调用被覆写过的方法哈~ class Student //extends Object    
{    
        private String name;    
        private int age;    
        public Student(String name,int age)    
        {    
                this.name = name;    
                this.age = age;    
        }    
        public String toString()    
        {    
                return "姓名:"+this.name+",年龄:"+this.age;    
        }    
}    
public class Demo09    
{    
        public static void main(String args[])    
        {    
                System.out.println(new Student("王乾",27));    
        }    
}
现在输出信息了哈~ [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) 还有一个equals()方法哈~ [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) 现在我们来判断两个对象是否相等哈~ class Student //extends Object    
{    
        private String name;    
        private int age;    
        public Student(String name,int age)    
        {    
                this.name = name;    
                this.age = age;    
        }    
        public boolean equals(Object obj)    
        {    
                if(this==obj)    
                {    
                        //内存地址的值相等,则肯定是同一个对象    
                        return true;    
                }    
                Student stu = (Student)obj;    
                if (stu.name.equals(this.name)&&stu.age==this.age)    
                {    
                        return true;    
                }    
                else    
                {    
                        return false;    
                }    
        }    
        public String toString()    
        {    
                return "姓名:"+this.name+",年龄:"+this.age;    
        }    
}    
public class Demo10    
{    
        public static void main(String args[])    
        {    
                Student stu1 = new Student("王乾",27);    
                Student stu2 = new Student("王乾",27);    
                System.out.println(stu1.equals(stu2));    
        }    
}
[零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) 以上的对象比较代码有严重问题:
・ 因为equals方法接收的是Object类型,所以肯定可以接收任意的对象。
class Student //extends Object    
{    
        private String name;    
        private int age;    
        public Student(String name,int age)    
        {    
                this.name = name;    
                this.age = age;    
        }    
        public boolean equals(Object obj)    
        {    
                if(this==obj)    
                {    
                        //内存地址的值相等,则肯定是同一个对象    
                        return true;    
                }    
                Student stu = (Student)obj;    
                if (stu.name.equals(this.name)&&stu.age==this.age)    
                {    
                        return true;    
                }    
                else    
                {    
                        return false;    
                }    
        }    
        public String toString()    
        {    
                return "姓名:"+this.name+",年龄:"+this.age;    
        }    
}    
public class Demo10    
{    
        public static void main(String args[])    
        {    
                Student stu1 = new Student("王乾",27);    
                Student stu2 = new Student("王乾",27);    
                System.out.println(stu1.equals("51cto"));    
        }    
}
比较时我们传入一个字符串“51cto”,发现提示转换异常ClassCastException错误 [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) class Student //extends Object    
{    
        private String name;    
        private int age;    
        public Student(String name,int age)    
        {    
                this.name = name;    
                this.age = age;    
        }    
        public boolean equals(Object obj)    
        {    
                if(this==obj)    
                {    
                        //内存地址的值相等,则肯定是同一个对象    
                        return true;    
                }    
                if (!(obj instanceof Student))    
                {    
                        return false;    
                } 
   
                Student stu = (Student)obj;    
                if (stu.name.equals(this.name)&&stu.age==this.age)    
                {    
                        return true;    
                }    
                else    
                {    
                        return false;    
                }    
        }    
        public String toString()    
        {    
                return "姓名:"+this.name+",年龄:"+this.age;    
        }    
}    
public class Demo10    
{    
        public static void main(String args[])    
        {    
                Student stu1 = new Student("王乾",27);    
                Student stu2 = new Student("王乾",27);    
                System.out.println(stu1.equals("51cto"));    
        }    
}
我们加入判断,如果对象obj不是Student类的实例的话,那就不要再进行比较了哈,直接返回false,现在看下程序能否正常执行哈~ [零基础学JAVA]Java SE面向对象部分-16.面向对象高级(04) 这就是Object类的对象比较,所以在进行转型之前一定要加入验证代码哈~这一点很重要哈~ 总结
1、对象的多态性
・ 向上自动转型
・ 向下强制转型
2、instanceof关键字
3、Object类
注意:
在开发中很少去继承一个已经实现好的类,一般都会去继承一个抽象类或实现一个接口。
ps:下季我们将使用多态性来理解抽象类和接口的应用,敬请期待~~~O(^_^)O ################################################

本文出自 “王乾De技术博客” 博客,谢绝转载!