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