一、面向对象三大特性之继承
继承最重要的作用就是实现代码的复用,不但可以使用已有基类所有的功能,而且派生类可以在不改变原有基类的情况下对这些功能进行扩展。
1、继承的实现:
在 java 中,继承使用 extends 关键字来实现,定义的语法如下:
class [子类] extends [父类]
2、继承的限制:
1)java不允许多重继承,但是允许多层继承
一个子类只能继承一个父类,因为java不允许多重继承,但是可以通过多层继承的方式,使C同时继承A和B的方法。
class A{
public void functionA(){}
}
class B extends A{
public void functionB(){}
}
class C extends B{
public void functionC(){}
}
2)子类对象在实例化之前,一定会首先实例化父类。
实际上在子类的构造方法之中,相当于隐含一个 super()语句,在父类提供无参构造的时候可以不写,但如果父类定义多个构造方法,则必须使用super()语句指明所要调用的构造方法。
class Person{
public Person(){
System.out.println("父类A实例化");
}
}
class Student extends Person{
public Student(){
//super(); 父类提供无参构造的时候可以不写
System.out.println("子类B实例化");
}
}
public class Demo{
public static void main(String[] args) {
Student student=new Student();
}
}
运行结果如下:
3)子类会继承父类的所有属性和方法,其中非私有部分属于显示继承,子类可以直接调用;而父类中使用private修饰的私有部分,属于隐式继承,子类无法直接使用,需通过其他方式调用(例如setter和getter)。
3、super关键字:
上面我们说到如果父类定义多个构造方法,则子类在构造时必须使用super()语句指明所要调用的构造方法。
此外,使用super还可以在子类中调用父类的非私有方法和属性。
那么,super和this的区别有哪些:
1)super从子类中调用父类的非私有方法和属性,不查找子类而直接调用父类定义,。
2)this优先调用本类中的方法和属性,先查找本类,如果本类没有才调用父类。
因此,两者最大的区别在于,super调用的一定是父类的方法,而this却不一定。
4、覆写(override)
所谓覆写,指的是子类在继承父类时,又重新定义了与父类相同的方法或者属性。那么为什么要覆写,简单来讲就是继承来的属性和方法不能满足子类的需求,从而重新改造以满足需求。
1)属性的覆写(了解概念即可)
子类定义了与父类属性名称完全相同的属性,就是属性的覆写。
这种操作本身没有意义,因为属性一般都使用private封装,子类不知道父类有什么属性,那么也就不存在属性覆写的问题。
2)方法的覆写(重要)
子类定义了与父类方法名、参数类型及个数完全相同的方法,就是方法的覆写。
需要注意的是,子类覆写的方法不能拥有比父类更严格的访问权限。
(访问权限:public > protected > default > private,如果父类的访问权限是public,那么子类只能使用public,如果父类的访问权限是default,那么子类可以使用的权限有public 、protected以及default )
class Person{
public void function(){
System.out.println("父类的方法");
}
}
class Student extends Person{
public void function(){
System.out.println("子类的方法");
}
}
public class Demo{
public static void main(String[] args) {
Student student=new Student();
student.function(); //此时打印的是“子类的方法”
}
}
5、总结一下重载和重写(覆写)的区别:
重载:一个类中有两个及以上方法名相同的方法,但参数类型、参数个数、参数顺序不同,则称为方法的重载。特别注意返回值类型不同不能重载。
重写:发生在父类和子类之间,子类在继承父类时,又重新定义了与父类方法名相同、参数列表相同,返回值类型相同(协变类型)的方法。需要注意重新定义的方法访问修饰符的限制不能比父类更加严格。
总之,重载和覆写是Java多态性的不同表现。前者是在一个类中多态性的表现,后者是在父类和子类两个类之间多态性的表现。
6、final关键字: 在Java中final被称为终结器。
1)使用final可以修饰类、方法、属性
修饰类 -->成为密封类,不允许被继承
修饰变量 -->变量变为常量,在声明时必须初始化,不能再次赋值
修饰常量 -->常量名命名全部使用大写字母,多个单词之间用下划线_隔开
修饰方法 -->成为密封方法,不能重写
2)final成员变量必须在声明的时候初始化或者在构造器中初始化,否则就会报编译错误。
3)使用final定义的类不能有子类(String类便是使用final定义)
4)final一旦修饰一个类之后,该类的所有方法默认都会加上final修饰(不包含成员变量)
二、面向对象三大特性之多态
Java中的多态,核心表现主要有以下两点:
1、方法的多态性:
1)方法的重载:调用同一方法名,可以根据参数列表的不同,实现不同的功能。
2)方法的重写:同一父类的方法,不同的实例化子类有不同的实现。
2、对象的多态性:(前提是方法覆写)
1)对象的向上转型(自动):父类 父类对象 = 子类实例
观察向上转型:我们依然使用上面的例子
class Person{
public void function(){
System.out.println("父类实例");
}
}
class Student extends Person{
public void function(){
System.out.println("子类实例");
}
}
public class Demo{
public static void main(String[] args) {
Person person=new Student();
person.function(); //打印的是“子类实例”
}
}
可以发现,如果子类覆写了父类的方法,那么就调用子类覆写后的方法,如果子类没有覆写,那么就会调用父类的方法。核心本质在于使用的是哪个子类(new在哪里),以及调用的方法是否被子类覆写。
那么为什么要使用向上转型:主要作用是可以实现接收参数的统一
class Person{
public void function(){
System.out.println("我是人类");
}
}
class Student extends Person{
public void function(){
System.out.println("我是学生");
}
}
class Teacher extends Person{
public void function(){
System.out.println("我是老师");
}
}
public class Demo{
public static void main(String[] args) {
//实现接收参数的统一
whoYouAre(new Student());
whoYouAre(new Teacher());
}
public static void whoYouAre(Person pre){
pre.function();
}
}
2)对象的向下转型(强制):子类 子类对象 = (子类)父类实例
对象的向下转型,是强制将父类对象变为子类对象,我们为什么要这样做:就是为了使用子类扩充的操作。
class Person{
public void function(){
System.out.println("父类方法");
}
}
class Student extends Person{
public void function(){
System.out.println("子类方法");
}
public void print(){
System.out.println("子类独有的打印方法");
}
}
public class Demo{
public static void main(String[] args) {
Person person=new Student();
person.function();
//此时只能使用父类定义好的方法,不能使用Student类中的printf方法
Student student = (Student)person; //强制向下转型
student.print(); //现在可以访问子类独有的打印方法
}
}
需要注意的是,并不是所有的父类对象都可以向下转型 :如果想要向下转型,首先一定要发生向上转型,否则在转型时会出现 ClassCastException,因此向下转型存在安全隐患。
为安全起见,在向下转型之前需要判断是否已经发生了向上转型,此时可以使用instanceof关键字判断。
Person person = new Student();
if (person instanceof Student) { //避免ClassCastException
Student student = (Student) person ;
student.print();
}
多态总结:
1)对象的多态性的前提是方法覆写。
2)通过对象的向上转型可以实现接收参数的统一。
3)通过向下转型可以实现对子类扩充方法的调用(有安全隐患一般不用)。
4)两个没有关系的类对象不能转型,否则会出现ClassCastException。