为什么需要继承?继承得优势/特点在哪里?

  • 为什么需要继承?
  • 在类创建者实现程序得过程中,会遇到虽然这个类能满足你的需求,但是你又想为他扩充功能得时候,此时就可以使用继承来解决这个问题。比如父类是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类型的相应属性和方法。