为什么需要继承?继承得优势/特点在哪里?
- 为什么需要继承?
- 在类创建者实现程序得过程中,会遇到虽然这个类能满足你的需求,但是你又想为他扩充功能得时候,此时就可以使用继承来解决这个问题。比如父类是person,拥有吃饭、睡觉得功能(方法),子类是programmer。我们可以知道程序员也是人,所以程序员也需要吃饭,但并不是任何人都可以编程,所以我们需要在programmer类中新增一个功能:programme()。
public class WhyDoYouNeedExtends {
/**父类*/
static class Person {
/**吃饭*/
public void eat() {}
/**睡觉*/
public void sleep() {}
}
/**子类*/
static class Programmer extends Person {
/**编程*/
public void programme() {}
}
public static void main(String[] args) {
Programmer programmer = new Programmer();
// 子类可以使用父类的共有方法
programmer.eat();
programmer.sleep();
// 父类不一定可以使用子类的方法,下面的代码会报错。那么如何在父类中调用子类的方法呢?下面会说到的
// person.programme();
}
}
- 继承的优势/特点在哪里?
- 特点一:继承能避免代码重写。
- 如果没有继承,那么在写programmer类时,为了保证类的正常使用,势必需要写吃饭、睡觉功能,这样会很多余。
- 特点二:一个父类可以有许多子类,但子类只允许有一个直接父类。
- 任何人都只有一个爸爸吧,但是你爸爸可以有很多儿子。
- 特点三:子类会继承父类的成员变量和成员方法,同时还可以修改父类的成员变量和重写父类的成员方法。
- 子类会继承父类的成员变量,但子类所继承的成员变量≠父类的成员变量
static class Person {
/**年龄*/
int age;
public Person() {
this.age = 10;
}
}
static class Programmer extends Person{
int age;
public Programmer() {
this.age = 1;
// 此处是继承的父类成员域,而并不是父类本身的成员域。也就是说super.age与父类的age在内存中存储的地址是不同的。
super.age = 100;
}
public void print() {
System.out.println("子类的age = " + age);
System.out.println("继承的age = " + super.age);
}
public static void main(String[] args) {
Person person = new Person();
System.out.println("父类本身的age1 = " + person.age);
Programmer programmer = new Programmer();
programmer.print();
// 此处是为了查看子类在构造方法中对继承的父类成员域进行修改后,父类中的成员域是否有变化。
System.out.println("父类本身的age2 = " + person.age);
}
}
输出结果为:
父类本身的age1 = 10
子类的age = 1
继承的age = 100
// 可以得知,子类对继承的成员变量域进行修改,不会影响到父类中本身的成员变量
父类本身的age2 = 10
- 那么我们如果想要修改父类中的成员变量该如何修改呢?我们先来看一段代码。
static class Person {
/**身高 单位:cm*/
public int stature;
public Person() {
this.stature = 170;
}
}
static class Programmer extends Person{
/**特点之二
* 那么我们如果想要修改父类中的成员变量该如何修改呢?
* - 如果该成员变量的修饰词是public,则子类可以直接进行修改
* 我们对person中的 stature 变量进行操作
* */
public static void main(String[] args) {
Person person = new Person();
System.out.println("父类本身身高 = " + person.stature);
Programmer programmer = new Programmer();
System.out.println("子类访问父类身高 = " + programmer.stature);
programmer.stature = 180;
System.out.println("继承的身高 = " + programmer.stature);
System.out.println("被子类修改后的父类身高 = " + person.stature);
}
}
输入结果:
父类本身身高 = 170
子类访问父类身高 = 170
继承的身高 = 180
被子类修改后的父类身高 = 170
- 通过上述代码我们可以得知,
- 子类在对父类成员变量修改的时候,其实是在对继承的值进行修改,比如 儿子继承了父亲给的100w,这笔钱怎么花都是儿子的事情了,和父亲是没有关系的
- 我们再来看一段代码
static class FatherClass {
public int value;
private int value;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public void info() {
value = 100;
System.out.println("FatherClass=" + value);
}
}
static class ChildClass extends FatherClass {
public void info() {
super.info();
}
public static void main(String[] args) {
ChildClass c = new ChildClass();
c.info();
System.out.println("子类继承的值 = " + c.getValue());
c.setValue(200);
System.out.println("子类修改过后,父类的值 = " + c.getValue());
}
}
FatherClass=100
子类继承的值 = 100
子类修改过后,父类的值 = 200
- 上述代码我们可以到父类的值是有被改动的,这和我们上面的结论是冲突的。其实也不冲突,具体原因是在于 Person person = new Person();
- 特点四:可以声明父类,创建子类(又称父类装载子类)
Person person = new Programmer();
- 需要注意的是
- (1) 声明什么样的类型,就只能调用什么类型的属性和方法
- (2) 创建什么样的类型,就真正运行的什么类型的方法
- (1)和(2)称为向上转型, 例如:Person p=new Teacher();那么p只能打点调用Person类中的方法和属性(看到的),但实际上却运行的是创建的Teacher类型的方法。
- (3) 创建什么样的类型,就可以强转为什么类型。
- 例如: Person p=new Teacher();
- Teacher t=(Teacher) p;
- 这种叫做向下转型,此时t调用的是创建的Teacher类型的相应属性和方法。