目录
1、面向对象特征之二:继承性
-
为什么要有继承?
- 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
-
二、继承性的好处
- 减少了代码的冗余,提高了代码的复用性;
- 便于功能的扩展;
- 为之后多态性的使用,提供了前提。
-
继承性的格式
-
class A extends B{}
A:子类、派生类、subclass
B:父类、超类、基类、superclass
-
体现:一旦子类 A 继承父类以后,子类 A 中就获取了父类 B 中声明的结构:属性、方法。特别的,父类中声明为 private 的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构,只有因为封装性的影响,使得子类不能直接调用父类的结构而已。
-
子类继承父类以后,还可以声明自己特有的属性或方法,实现功能的拓展。
-
子类和父类的关系:不同于子集与集合的关系。
-
extends:延展、扩展
-
-
四、Java 中关于继承性的规定:
- 一个类可以被多个类继承
- Java 中类的单继承性:一个类只能有一个父类
- 子父类是相对的概念。
- 子类直接继承的父类,称为:直接父类。间接继承的父类,称为,间接父类。
- 子类继承父类后,就获取了直接父类以及所有间接父类中声明的属性和方法。
-
五、
- 如果我们没有显式的声明一个类的父类的话,则此类继承于 java.lang.Object 类
- 所有的 java 类(除 java.long.Object 类之外)都直接或间接地继承于 java.lang.Object 类;
- 意味着,所有的 java 类具有 java.lang.Object 类声明的功能。
2、方法的重写(override/overwrite)
-
重写:子类继承父类以后,可以对父类中的方法进行覆盖操作。
-
应用:重写以后,当创建子类对象以后,通过子类对象去调用子父类中同名同参数方法时,执行的是子类重写父类的方法。即在程序执行时,子类的方法将覆盖父类的方法。
-
3.重写的规定:
-
方法的声明:
//可以直接将父类的方法的第一行粘过来,直接写方法体 // public void walk(int distance){ // System.out.println("重写的方法"); // } //直接输入父类的方法名,Alt + /,选择即可生成 @Override public void walk(int distance) { System.out.println("自动生成"); }
-
约定俗称:子类中的叫重写的方法,父类中的叫被重写的方法。
-
-
注意事项
-
① 子类重写的方法的方法名和形参列表必须和父类被重写的方法的方法名、形参列表相同;
-
② 子类重写的方法使用的访问权限不能小于父类被重写的方法的访问权限(子类大于等于)
特殊情况: 子类不能重写父类中声明为private权限的方法;
-
③ 返回值类型:
- 父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void;
- 父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类;
- 父类被重写的方法的返回值类型如果是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的基本数据类型(必须是:double)。
-
子类方法抛出的异常不能大于父类被重写的方法抛出的异常;
注意:子类与父类中同名同参数的方法必须同时声明为非static的(即为重写),或者同时声明为static的(不是重写)。因为static方法是属于类的,子类无法覆盖父类的方法。
-
(1)方法的重写和重载是Java多态性的不同表现。重写是父类与子类之间多态性的一种表现,重载是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被"屏蔽"了。如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载。
(2)从编译和运行的角度看:重载,是指允许存在多个同名方法,而这些方法的参数不同。编译器根据方法不同的参数表,对同名方法的名称做修饰。对于编译器而言,这些同名方法就成了不同的方法。它们的调用地址在编译期就绑定了。Java的重载是可以包括父类和子类的,即子类可以重载父类的同名不同参数的方法。所以:对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法,这称为“早绑定”或“静态绑定”;
而对于多态,只有等到方法调用的那一刻,解释运行器才会确定所要调用的具体方法,这称为“晚绑定”或“动态绑定”。
引用一句Bruce Eckel的话:“不要犯傻,如果它不是晚绑定,它就不是多态。”
3、四种访问权限修饰符
Order类
package com.atguigu.java2;
/*
* 体会4种不同的权限修饰
*/
public class Order {
private int orderPrivate;
int orderDefault;
protected int orderProtected;
public int orderPublic;
private void methodPrivate(){
orderPrivate = 1;
orderDefault = 2;
orderProtected = 3;
orderPublic = 4;
}
void methodDefault(){
orderPrivate = 1;
orderDefault = 2;
orderProtected = 3;
orderPublic = 4;
}
protected void methodProtected(){
orderPrivate = 1;
orderDefault = 2;
orderProtected = 3;
orderPublic = 4;
}
public void methodPublic(){
orderPrivate = 1;
orderDefault = 2;
orderProtected = 3;
orderPublic = 4;
}
}
Ordertest类
package com.atguigu.java2;
public class OrderTest {
public static void main(String[] args) {
Order order = new Order();
order.orderDefault = 1;
order.orderProtected = 2;
order.orderPublic = 3;
order.methodDefault();
order.methodProtected();
order.methodPublic();
//同一个包中的其他类,不可以调用Order类中私有的属性、方法
// order.orderPrivate = 4;
// order.methodPrivate();
}
}
SubOrder类
package com.atguigu.java3;
import com.atguigu.java2.Order;
public class SubOrder extends Order {
public void method(){
orderProtected = 1;
orderPublic = 2;
methodProtected();
methodPublic();
//在不同包的子类中,不能调用Order类中声明为private和缺省权限的属性、方法
// orderDefault = 3;
// orderPrivate = 4;
//
// methodDefault();
// methodPrivate();
}
}
OrderTest类
package com.atguigu.java3;
import com.atguigu.java2.Order;
public class OrderTest {
public static void main(String[] args) {
Order order = new Order();
order.orderPublic = 1;
order.methodPublic();
//不同包下的普通类(非子类)要使用Order类,不可以调用声明为private、缺省、protected权限的属性、方法
// order.orderPrivate = 2;
// order.orderDefault = 3;
// order.orderProtected = 4;
//
// order.methodPrivate();
// order.methodDefault();
// order.methodProtected();
}
}
4、super关键字
- 1.super理解为:父类的
- 2.super可以用来调用:属性、方法、构造器
- 3.super的使用
- 3.1 我们可以在子类的方法或构造器中,通过"super.属性"或"super.方法"的方式,显式的调用父类中声明的属性或方法。但是,通常情况下,我们习惯去省略这个"super."
- 3.2 特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的使用"super.属性"的方式,表明调用的是父类中声明的属性。
- 3.3 特殊情况:当子类重写了父类中的方法后,我们想在子类的方法中调用父类中被重写的方法时,必须显式的使用"super.方法"的方式,表明调用的是父类中被重写的方法。
- 4.super调用构造器
- 4.1 我们可以在子类的构造器中显式的使用"super(形参列表)"的方式,调用父类中声明的指定的构造
- 4.2 "super(形参列表)"的使用,必须声明在子类构造器的首行!
- 4.3 我们在类的构造器中,针对于"this(形参列表)"或"super(形参列表)"只能二选一,不能同时出现。
- 4.4 在构造器的首行,既没有显式的声明"this(形参列表)“或"super(形参列表)”,则默认的调用的是父类中的空参构造器。super()
- 4.5 在类的多个构造器中,至少有一个类的构造器使用了"super(形参列表)",调用父类中的构造器。
Person类
public class Person {
String name;
int age;
int id = 1001; //身份证号
public Person(){
System.out.println("我无处不在");
}
public Person(String name){
this.name = name;
}
public Person(String name,int age){
this(name);
this.age = age;
}
public void eat(){
System.out.println("人,吃饭");
}
public void walk(){
System.out.println("人,走路");
}
}
Student类
public class Student extends Person{
String major;
int id = 1002; //学号
public Student(){
}
public Student(String name,int age,String major){
// this.age = age;
// this.name = name;
super(name,age);//调用父类的指定的构造器
this.major = major;
}
public Student(String major){
this.major = major;
}
public void eat(){
System.out.println("学生多吃有营养的食物");
}
public void Study(){
System.out.println("学生,学习知识。");
this.eat();
//如果,想调用父类中被重写的,不想调用子类中的方法,可以:
super.eat();
super.walk();//子父类中未重写的方法,用"this."或"super."调用都可以
}
public void show(){
System.out.println("name = " + this.name + ",age = " + super.age);
System.out.println("id = " + this.id);
System.out.println("id = " + super.id);
}
}
测试类
public class SuperTest {
public static void main(String[] args) {
Student s = new Student();
s.show();
s.Study();
Student s1 = new Student("Ton",21,"IT" );
s1.show();
System.out.println("***********************");
Student s2 = new Student();
}
}
5、子类对象实例化过程
- 1.从结果上看:
- 子类继承父类以后,就获取了父类中声明的属性或方法。
- 创建子类的对象中,在堆空间中,就会加载所有父类中声明的属性。
- 2.从过程上看:
- 当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类构造器,直到调用了java.lang.Object类中空参的构造器为止。正因为加载过所有的父类结构,所以才可以看到内存中有父类中的结构,子类对象可以考虑进行调用。
明确:虽然创建子类对象时,调用了父类的构造器,但自始至终就创建过一个对象,即为new的子类对象。