上季内容回顾:
1、final关键字 
· 修饰类不能被继承 
· 修饰方法不能被覆写 
· 修饰的变量就是一个常量,全局常量(public static final) 
2、抽象类和接口 
· 抽象类:只包含一个抽象方法的类,抽象方法只需声明而不需要实现,必须有子类 
· 接口:只包含抽象方法和全局常量的类——接口,也是必须有子类
在实际中一个类很少会去继承一个已经完全实现好的类,基本上都是继承抽象类和实现接口。
本季主要知识点:
1、对象的多态性 
2、instanceof关键字 
3、Object类
对象的多态性
image
注意点: 
为了清楚的阐述出概念,现在先使用普通类的继承关系。
向上转型:
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();    
        }    
}
image
对象多态性体现在对象相互转型上面哈~
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()调用的是哪个类的方法哈~
image
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();    
        }    
}
子类对象向父类对象转型之后,所调用的方法一定是被覆写过的方法,这就是对象的向上转型哈~
image
向下转型:
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()哈~
image
程序提示找不到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();    
        }    
}
验证下效果:
image
这就是对象向下转型哈~
观察以下一种代码,检查下有没问题哈~:
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()方法了哈~
image
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()方法
image
如果现在我们要调用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错误了哈~
image
在程序开发中有两大错误是比较常见的: 
·  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();    
        }
    
}
image
如果按此做法,就会面临一个很严重的问题: 
· 如果现在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()方法哈~~~这就是对象多态性带来的好处,谁被其实例化就具备这样的功能哈~如果父类设计的非常的完善,则方法中会非常的好写。
image
要求: 
如果传入的是B类的对象,则要求再调用fun3()方法,如果传入的是C类的对象,则要求再调用fun4() 
方法。
问题: 
如何去判断一个对象是否是某个类的实例呢?这就需要instanceof关键字支持哈。
instanceof关键字
image
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类的实例哈~
image
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类的实例哈~
image
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类的实例吗?验证显示不是哈~说明不能向子类转换哈~
image
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关键字的作用哈~
image
Instanceof的使用时机: 
一般情况下都是在转型之前进行一下判断,这样就可以进行比较安全的转型操作。
Object类
image
在Java中用户所编写的一切类都是一个类的子类,称为Object类。
image
实际上此类默认继承了Object类,以上代码等价于以下代码:
image
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));    
        }    
}
现在我们看下效果哈~
image
现在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()之前的效果一样哈~
image
加和不加都是一样滴,那我们下面就覆写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”了哈~
image
我们查下System的JDK文档,找到out.print()方法哈~
image
实际上out.print()方法是调用的这个方法哈~
image
所以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));    
        }    
}
现在输出信息了哈~
image
还有一个equals()方法哈~
image
现在我们来判断两个对象是否相等哈~
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));    
        }    
}
image
以上的对象比较代码有严重问题: 
· 因为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错误
image
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,现在看下程序能否正常执行哈~
image
这就是Object类的对象比较,所以在进行转型之前一定要加入验证代码哈~这一点很重要哈~
总结 
1、对象的多态性 
· 向上自动转型 
· 向下强制转型 
2、instanceof关键字 
3、Object类
注意: 
在开发中很少去继承一个已经实现好的类,一般都会去继承一个抽象类或实现一个接口。
ps:下季我们将使用多态性来理解抽象类和接口的应用,敬请期待~~~O(^_^)O
################################################