1. 为什么需要使用继承?
①.提高代码的重用性
比如说你想要建立学生类和老师类,这两个类都属于人类,即人类的属性和方法这两个类都有,通过继承我们只需将这些类定义一遍,提高了重用性。
②.提高程序的扩展性
如果你想将一个类详细化,那么能且只能将其往一个方面详细化,比如你想将人类详细化,那么你只能往同学类或老师类,不能同时往这两个方面详细化,不然得到的类既不是同学类又不是老师类,而是师生类。因此通过继承可以提高类的扩展性,将一个类扩展到无数个类。
2.Java继承的语法格式
Java继承的关键字:extends
继承的语法格式:
public class 类名(子类/派生类/超类) extends 类名(父类/基类) {
}
注意:Java中类的继承是单继承,正如一个儿子只能有一个亲生父亲。
3.子类能继承到父类的那些内容?
子类能继承到父类中所有的属性和方法。
访问修饰符是用来限定属性和方法在什么情况下能被调用:
访问修饰符 | 同类中 | 同包中 | 不同包中 | 不同包但是有继承关系的子类中 |
private | 可以 | 不可以 | 不可以 | 不可以 |
空 | 可以 | 可以 | 不可以 | 不可以 |
protected | 可以 | 可以 | 不可以 | 可以 |
public | 可以 | 可以 | 可以 | 可以 |
由此可见四种访问修饰符的大小顺序为:
public>protected>空>private
比如有4个java文件内容如下:
A.java:(同类中)
package class1;
public class A{
public String name;
int number;
protected String sex;
private String location;
class B{
public void getinf(){
A a = new A();
System.out.println(a.name);//public√
System.out.println(a.number);//空√
System.out.println(a.sex);//protected√
System.out.println(a.location);//private√
}
}
}
C.java:(同包中)
package class1;
public class C {
public void getinf() {
A a = new A();
System.out.println(a.name);// public√
System.out.println(a.number);// 空√
System.out.println(a.sex);// protected√
System.out.println(a.location);// private×
}
}
D.java:(不同包中也没有继承关系)
package class2;
import class1.A;
public class D {
public void getinf() {
A a = new A();
System.out.println(a.name);// public√
System.out.println(a.number);// 空×
System.out.println(a.sex);// protected×
System.out.println(a.location);// private×
}
}
E.java:(不同包中但有继承关系)
package class2;
import class1.A;
public class E extends A{
public void getinf() {
E e = new E();
System.out.println(e.name);// public√
System.out.println(e.number);// 空×
System.out.println(e.sex);// protected√
System.out.println(e.location);// private×
}
}
4.理解继承
○问:子类是否可以定义父类中没有的属性和方法呢?
◎答:可以的。
★理解:子类继承父类就好像儿子继承父亲一样,首先父亲能被检查出来的基因会遗传给儿子,即父类中能访问到的属性和方法会继承给子类,让子类也有这些属性和方法;其次儿子可能会拥有一些父亲所没有的基因,有可能是后天的也有可能是突变了,即子类可以定义父类所没有的属性和方法。
○问:父母有一个学习的方法,子女也有一个学习的方法,那么两者的学习方法是否完成一致呢?
◎答:有可能会一致,但是也有不同的。
○问:如果不同怎么处理呢?
◎答:需要使用方法重写来解决这个问题。
★理解:就好像所谓的代沟,同样做某件事,有时儿子会学父亲怎么做怎么做,就所谓子类继承了父类的方法;但有时儿子会觉得父亲做的不对或者有更好的方法,就会产生不一样的做法,即不一样的方法体,但方法本身没发生改变,即还是要去做这件事。那么不改变方法,只改变方法体的这种行为便是重写。
实现方法重写必须要满足如下条件:
①.必须存在继承关系。
②.子类在重写父类方法时:子类方法的访问修饰符可以大于或者等于父类方法的访问修饰符。大小顺序在前面的表格下已给出。
③.子类在重写父类方法时:子类方法的返回值类型,方法名,参数都必须要和父类的完全一致。
④.方法中的代码要不同。
○问:方法重写后如何调用?
◎答:根据new关键字后的类名来决定,如果类名是子类的,那么会优先调用子类的方法,如果子类没有才会调用父类中的方法。
★理解:如父类class A有两个方法work()和play(),其子类class B继承class A,并且重写了方法work(),那么在方法中实例化:B b = new B();此时如果调用b.work(),调用的会是B中重写的方法work(),而不是A中的方法work();而调用b.play(),调用的则会是A中的方法play(),这个方法是通过继承使B也拥有的。
5.类的多态性
1.方法重载
一个方法名,参数不同,这叫方法重载。(Overload)
如在一个类中,可以有两个方法:foo(Stringstr)和foo(int number),他们的方法名相同,参数不同(包括参数类型和个数,只要不是完全一样就是不同),访问性可以不同,这样在调用时虽然是同一个方法名,系统会根据不同的参数而进不同的方法体。
2.方法重写
父类与子类有同样的方法名和参数,这叫方法重写。(Override)
方法重写的理解与格式之前已经解释了。
3.类的多态性
父类引用指向子类对象,调用方法时会调用子类的实现,而不是父类的实现,这叫多态。
如子类Child类继承父类Parent类:
Parentinstance = new Child();
instance.foo();//==> Child foo()
此时父类的实例化对象由于指向的是子类,所以调用的方法是子类的方法。
6.场景示例:
张老师现在教的是大学生的英语;那么这位老师是否可以教高中生英语?初中生?小学生?如果有10种类型的学生?100种?
答案是可以的。下面仅以教普通学生和大学生为例:
以下代码共5个文件5个类,包含一个课程类,一个老师类,一个学生类,一个大学生类和一个主类。我已经标上注释以便理解:
课程类Subject.java:
package classroom;
public class Subject {
public String name;// 姓名属性
public int time;// 课时属性
public int score;// 学分属性
}
老师类Teacher.java:
package classroom;
public class Teacher {
public String name;
public void teach(Student stu, Subject sub) {
System.out.println(name + "正在教" + stu.getName() + "学习" + sub.name);
stu.study(sub);
}
}
学生类Student.java:
package classroom;
public class Student {
private String name;// 姓名属性
int age;// 年龄属性
protected char sex;// 性别属性
public int score;// 学分属性
public int time = -1;// 剩余的课时时间,定义为负数方便初始化
// 定义设置姓名属性值的方法
public void setName(String n) {
name = n;
}
// 定义获取姓名属性值的方法
public String getName() {
return name;
}
// 定义学习课程对象的方法
public void study(Subject sub) {
// 减少课程的课时
if (time < 0)
time = sub.time;
if (time > 0) {
time--;
System.out.println(name + "正在学习" + sub.name + "课程,剩余的课时是" + time);
// 判断课程的课时是否被学完了
if (time <= 0) {
score += sub.score;// 学生的学分要加上课程的学分。
System.out.println(name + "已经学完了" + sub.name + "课程," + name
+ "现在的学分是" + score);
time = 0;
}
}
}
}
大学生类UNStudent.java:
package classroom;
public class UNStudent extends Student {
public String number;// 学号属性
// 玩的方法
public void play() {
System.out.println(getName() + "学完了,正在玩游戏!");
}
// 重写父类中的学习课程对象的方法
public void study(Subject sub) {
if (time < 0)
time = sub.time;
if (time > 0) {
time -= 2;
System.out.println(getName() + "正在学习" + sub.name + "课程,剩余的课时是"
+ time);
// 判断课程的课时是否被学完了
if (time <= 0) {
score += sub.score;// 学生的学分要加上课程的学分。
System.out.println(getName() + "已经学完了" + sub.name + "课程,"
+ getName() + "现在的学分是" + score);
time = 0;
}
} else {
play();
}
}
}
主类Manager.java:
package classroom;
public class Manager {
public static void wait(int i) {// 等待i秒
try {
Thread.sleep(i * 1000);// 1000代表1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Subject sub = new Subject();
sub.name = "英语";
sub.score = 3;
sub.time = 6;
// 实例化UNStudent类的对象
UNStudent un = new UNStudent();// 大学生张三
un.age = 20;
un.score = 15;
un.sex = '男';
un.setName("张三");
un.number = "2016090001";
Student stu = new Student();// 普通学生李四
stu.age = 20;
stu.score = 10;
stu.sex = '男';
stu.setName("李四");
Teacher t = new Teacher();
t.name = "张老师";
int temp = sub.time;
while (temp > 0) {
un.study(sub);// 大学生开始自学
wait(2);
t.teach(un, sub);// 老师教大学生学
t.teach(stu, sub);// 老师教普通学生学
wait(2);
temp--;
}
}
}
运行后得到的结果为:
以上,便是我对类的继承相关知识与概念的理解和概括。欢迎大家在评论里讨论!