Java面向对象笔记(四)继承和多态
文章目录
一、面向对象的特征之二:继承性
一、继承性的好处
- 减少了代码的冗余
- 便于功能的扩展
- 为之后多态性的使用,提供了前提
为什么要有继承? 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
二、继承性的格式:class A extends B{ }
A:子类、派生类、subclass
B:父类、超累、基类、superclass
-
体现:一旦子类A继承父类B以后,子类A中就获取了父类B中声明的所有的属性和方法
特别的:父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中的结构。
只是因为封装性的影响,使得子类不能直接调用父类的结构而已。 -
子类继承父类以后,还可以声明自己特有的属性或方法:实现功能的拓展子类和父类的关系,不同于子集和集合的关系。
三、Java中关于继承性的规定:
-
一个类可以被多个子类继承
-
Java中类的单继承性:一个类只能有一个父类
-
子父类是相对的概念
-
子类直接继承的父类,称为:直接父类。间接继承的父类称为:间接父类
-
子类继承父类以后,就获取了直接父类以及所有间接父类中声明的属性和方法
- 四、对java.lang.Object类的继承
-
如果我们没有显式的声明一个类的父类的话,则此类继承于java.lang.Object类
-
所有的java类(除java.lang.Object类之外)都直接或间接的继承于java.lang.object类
-
意味着,所有的java类具有java.lang.Object类声明的功能
继承性实例
Person.java 父类,将属性私有化,继承的时候无法直接调用属性,则提供公有的get()、set()方法来调用
public class Person {
String name;
//将属性私有化,继承的时候无法直接调用属性,则提供公有的get()、set()方法来调用
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void eat() {
System.out.println("吃饭");
}
public void sleep() {
System.out.println("睡觉");
}
}
Students.java 子类继承父类所有的属性和方法
public class Student extends Person{
// String name;
// int age;
String major;
public Student() {
}
public Student(String name,int age,String major) {
this.name = name;
// this.age = age;
this.major = major;
}
// public void eat() {
// System.out.println("吃饭");
// }
//
// public void sleep() {
// System.out.println("睡觉");
// }
public void study() {
System.out.println("学习");
}
}
ExtendsTest.java 继承性测试类
public class ExtendsTest {
public static void main(String[] args) {
Person p1 = new Person();
// p1.age = 1;
p1.eat();
System.out.println("*******************************");
//体现继承性,通过Students对象去调Person类中的方法和属性
Student s1 = new Student();
s1.eat();
s1.sleep();
s1.name = "Tom";
s1.setAge(10);
System.out.println(s1.getAge());
}
}
二、方法的重写(override / overwrite)
-
重写:
子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作 -
应用:
重写以后,当创建子类对象以后,通过子类对象调用子父类中同名同参数的方法时,实际上执行的是子类重写父类的方法。 -
重写的规定:
方法的声明:
权限修饰符 返回值类型 方法名(形参列表){
//方法体
}
子类中的叫重写方法,父类中的叫被重写方法
-
1、子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参列表相同
-
2、子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符
特殊情况:子类不能重写父类中声明为private权限的方法 -
3、返回值类型:
- 父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void
- 父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类
- 父类被重写的方法的返回值类型是基本数据类型,则子类重写的方法的返回值类型必须是相同的基本数据类型
-
4、子类重写的方法抛出异常类型不大于父类被重写的方法抛出的异常类型(具体见异常处理)
注:子类和父类中同名同参的方法要么都声明为非static的(考虑重写),要么都声明为static的(不能重写)
方法重写的实例:
父类 Person.java
public class Person {
String name;
int age;
public Person() {
}
public Person(String name,int age) {
this.name = name;
this.age = age;
}
public void eat() {
System.out.println("吃饭");
}
public void walk(int distance) {
System.out.println("走路,走的距离是:" + distance + "公里");
}
//返回值是一个类
public Object info() {
return null;
}
//返回值是基本数据类型
public double info1() {
return 0.0;
}
}
子类 Student.java
public class Student extends Person{
String major;
public Student() {
}
public Student(String major) {
this.major = major;
}
public void study() {
System.out.println("学习。专业是:" + major);
}
//重写父类中的eat()方法
public void eat() {
System.out.println("学生应该多吃有营养的食物");
}
//重写返回值为一个类的方法时,返回值可以是这个类或这个类的子类
public String info() {
return null;
}
//重写返回值为基本数据类型的方法时,返回值也必须是同一基本数据类型
public double info1() {
return 1.0;
}
}
测试类 PersonTest.java
public class PersonTest {
public static void main(String[] args) {
Student student = new Student("计算机科学与技术");
student.eat();//重写前“吃饭”。 重写后“学生应该多吃有营养的食物”
student.walk(10);
student.study();
}
}
三、super关键字的使用
-
super理解为:父类的
-
super可以用来调用:属性、方法、构造器
-
super的使用:调用属性和方法
-
我们可以在子类的方法或构造器中。通过使用"super.属性"或"super.方法"的方式,显式的调用父类中声明的属性或方法。但是,通常情况下,我们习惯省略"super."
-
特殊情况:当子类和父类中定义了同名的属性(或同名同参数的方法)时,我们想要在子类中调用父类的属性(或父类被重写的方法),则必须显式的使用"super.属性"(或"super.方法")的方式,表明调用的是父类中的属性(被重写的方法)。
-
-
super调用构造器
-
我们可以在子类的构造器中显式的使用"==super(形参列表)"的方式,调用父类中声明的指定的构造器
-
"super(形参列表)"的使用,必须声明在子类构造器的首行
-
我们在类的构造器中,针对"this(形参列表)"或"super(形参列表)"只能二选一
-
在构造器的首行,没有显示的声明"this(形参列表)“或"super(形参列表)”,则默认调用的是父类中空参的构造器:super()
-
在类的多个构造器中,至少有一个类的构造器中使用了"super(形参列表)",调用父类中的构造器
-
super关键字实例
父类 Person.java
public class Person {
String name;
int age;
int id = 1001;//身份证号
public Person() {
}
public Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
子类 Student.java
public class Student extends Person{
String major;
int id = 1002;//学号,跟父类中同名的属性
public Student() {
}
public Student(String major) {
this.major =major;
}
//super()在构造器内的使用
public Student(String name,int age,String major) {
// this.name = name;
// this.age = age;
super(name,age);//调用父类中指定构造器
this.major = major;
}
//子类和父类出现同名属性时,默认调用子类的属性,要想调用父类的属性,需要加上super关键字
public void show() {
System.out.println("name = " + name + ", age = " + age);
System.out.println("id = " + this.id);//调用的是子类的id,1002,this先在子类中找,子类中没有则去父类中找
System.err.println("id = " + super.id);//调用的是父类的id 1001,super跳过子类,直接去父类中找
}
}
四、面向对象特征之三:多态性
-
理解多态性:可以理解为一个事物的多种形态
-
何为多态性:
对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用) -
多态的使用:虚拟方法调用
有了对象的多态性以后,编译期调用的是父类中这个方法,运行期执行的是子类重写的方法,故使用多态无法调用子类独有的方法
总结:编译,看左边;运行,看右边Person p1 = new Man();//创建父类对象时,new的是父类的子类,就是new的对象可以是多种形态 p1.eat();
-
多态性的使用前提: ① 类的继承关系 ② 方法的重写
-
对象的多态性,只适用于方法,不适用于属性。(编译和运行都看左边)
基本数据类型和类的转型
五、instanceof关键字的使用
如何才能调用子类特有的属性和方法
向下转型:使用强制类型转换符
Person p2 = new Man();
Man m1 = (Man)p2;
m1.earnMoney();
m1.isSmoking = true;
-
a instanceof A:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false
-
使用情镜:为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,
先进行instanceof的判断,返回true,就进行向下转型。返回false,不进行向下转型。 -
如果a instanceof A返回true,则 a instanceof B也返回true
其中,类B是类A的父类