继承的由来
我们用代码来引出继承的由来。
定义一个猫(Cat)类,有name和color两个属性,有eat一个行为;
class Cat {
String name;//名字
String color;//颜色
public void eat(){
System.out.println("吃东西");
}
}
然后定义一个狗(Dog)类,也有name和color两个属性,有eat一个行为;
class Dog {
String name;//名字
String color;//颜色
public void eat(){
System.out.println("吃东西");
}
}
如上代码,我们很容易看出这么一个问题,cat和dog都有相同的name,color属性,也同样具有eat行为。同样的代码我们却要写两次,那么有没有一个方法,只声明一次name,color属性,和eat行为呢。首先,猫和狗都属于动物,都有name和color属性,那么我们是否可以创建一个Animal类,让它包含猫和狗吗。继承的出现,为我们解决了这个问题。
class Demo_Extends {
public static void main(String[] args) {
Cat c = new Cat();
c.color = "橘色";
c.name = "二喜";
c.eat();
System.out.println(c.name + "..." + c.color);
//运行结果为
//吃东西
//二喜...橘色
}
}
//定义一个Animal类
class Animal {
String color; //动物的颜色
String name; //动物的名字
public void eat() { //吃东西的功能
System.out.println("吃东西");
}
}
class Cat extends Animal {
}
class Dog extends Animal {
}
/*
extends是继承的意思
Animal是父类
Cat和Dog都是子类
*/
综上代码我们发现,我们定义了一个Animal类,含有color和name两个属性,一个eat行为。然后分别定义一个Cat和Dog类,并且集成自Animal类。我们在构造函数中直接new一个Cat对象,然后直接给它的name和color属性赋值,并调用eat行为,发现时可行的。这样,我们就不用分别再为Cat和Dog声明属性和定义行为了。
继承的好处和弊端
A:继承的好处
a:提高了代码的复用性(从上述例子可以看出)
b:提高了代码的维护性(比如为Cat和Dog添加一个leg属性,只需要在Animal中添加即可)
c:让类与类之间产生了关系,是多态的前提
B:继承的弊端
类的耦合性增强了。(类与类之间的关联太紧密,父类改变,子类也会相应的做出改变)
开发的原则:高内聚,低耦合。
耦合:类与类的关系
内聚:就是自己完成某件事情的能力
Java中类的继承特点
Java只支持单继承,不支持多继承。(一个儿子只能有一个爹)
//一个类只能有一个父类,不可以有多个父类。
class SubDemo extends Demo{} //ok
class SubDemo extends Demo1,Demo2...//error
有些语言是支持多继承,格式:extends 类1,类2,...
Java支持多层继承(继承体系)
class A{}
class B extends A{}
class C extends B{}
如果想用这个体系的所有功能用最底层的类创建对象看下面代码示例
如果想看这个体系的共性功能,看最顶层的类 看下面代码示例
class Demo_Extends {
public static void main(String[] args) {
//如果想用这个体系的所有功能用最底层的类创建对象
C c = new C();
c.age=11;
c.name="二喜";
c.leg=4;
c.color="橘色";
c.eat();
c.sleep();
c.run();
/*
c对象就包含了age,name,leg,color属性,以及eat,sleep,run的行为
*/
//如果想看这个体系的共性功能,看最顶层的类
A a =new A();
a.age=2;
a.name="三毛";
a.eat();
/*
此时的a对象只包含age和name两个属性,以及eat一个行为。
*/
}
}
class A{
int age;
String name;
public void eat(){
System.out.printlb("吃东西");
}
}
class B extends A{
int leg;
public void sleep(){
System.out.printlb("睡觉");
}
}
class C extends B{
String color;
public void run(){
System.out.printlb("快跑");
}
}
继承的注意事项
a:子类只能继承父类所有非私有的成员(成员方法和成员变量)
class Demo_Extends {
public static void main(String[] args) {
Son son =new Son();//声明一个son对象
son.age=11;//这样用是正确的
son.wife="王婆";//这样用是错误的,因为wife是Father的私有变量
son.eat();//son具有eat的行为
son.sleep();//son不能访问父类Father的私有方法sleep;这样用是错误的
}
}
class Father {
int age;
private wife;
public void eat(){
System.out.println("我要吃饭");
}
private void sleep(){
System.out.print("我要去睡觉");
}
}
class Son entends Father {
}
b:子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法。查看下方this和super关键字的使用
c:不要为了部分功能而去继承
项目经理含有 姓名 工号 工资 奖金属性;程序员 含有姓名 工号 工资,不要用为了相同的属性去让程序员集成项目经理,或者项目经理集成程序员。
什么时候使用继承
继承其实体现的是一种关系:"is a"。(包含关系)
Person
Student
Teacher
水果
苹果
香蕉
橘子
采用假设法。
如果有两个类A,B。只有他们符合A是B的一种,或者B是A的一种,就可以考虑使用继承。
继承中成员变量的关系
子类中的成员变量和父类中的成员变量名称不一样,这个太简单
子类中的成员变量和父类中的成员变量名称一样,这个怎么玩呢?
在子类方法中访问一个变量的查找顺序
a:在子类方法的局部范围找,有就使用
b:在子类的成员范围找,有就使用
c:在父类的成员范围找,有就使用
d:如果还没找到,就报错
class Demo4_Extends {
public static void main(String[] args) {
Son s = new Son();
s.print();
}
}
/*
* A:案例演示
* a:不同名的变量
* b:同名的变量
子父类出现同名的变量只是在讲课中举例子有,在开发中是不会出现这种情况的
子类继承父类就是为了使用父类的成员,那么如果定义了同名的成员变量没有意义了
*/
class Father {
int num1 = 10;
int num2 = 30;
}
class Son extends Father {
int num2 = 20;
public void print() {
System.out.println(this.num1); //this既可以调用本类的,也可以调用父类的(本类没有的情况下)
System.out.println(this.num2); //就近原则,子类有就不用父类的了
System.out.println(super.num2);
}
}
[注意]实际开发中不会遇到同名变量,自己在今后的开发过程中也不要给对象声明相同名称的变量
继承中成员方法的关系
子类和父类的方法名不同,这个就无所谓了
子类中的方法和父类方法名不同
通过子类调用方法
1.先找子类中,看有没有这个方法,有就使用
2.再看父类中有没有这个方法,有就使用
3.如果都没有,俺么就报错
this和super的区别和应用
A:this和super都代表什么
this:代表当前对象的引用,谁来调用我,我就代表谁
super:代表当前对象父类的引用
B:this和super的使用区别
a:调用成员变量
this.成员变量 调用本类的成员变量,也可以调用父类的成员变量
super.成员变量 调用父类的成员变量
b:调用构造方法
this(...) 调用本类的构造方法
super(...) 调用父类的构造方法
c:调用成员方法
this.成员方法 调用本类的成员方法,也可以调用父类的方法
super.成员方法 调用父类的成员方法
继承中构造方法的关系
子类中所有的构造方法默认都会访问父类中空参数的构造方法
因为子类会继承父类中的数据,可能还会使用父类的数据。
,子类初始化之前,一定要先完成父类数据的初始化。
每一个构造方法的第一条语句默认都是:super() Object类最顶层的父类。
class Demo5_Extends {
public static void main(String[] args) {
Son s = new Son();
}
}
/*
*
* 子类中所有的构造方法默认都会访问父类中空参数的构造方法
* 因为子类会继承父类中的数据,可能还会使用父类的数据。
* 所以,子类初始化之前,一定要先完成父类数据的初始化。
* 每一个构造方法的第一条语句默认都是:super() Object类最顶层的父类。
*/
class Father extends Object {
public Father() {
super();
System.out.println("Father 的构造方法");
}
}
class Son extends Father {
public Son() {
super(); //这是一条语句,如果不写,系统会默认加上,用来访问父类中的空参构造
System.out.println("Son 的构造方法");
}
}
继承中构造方法的注意事项
父类没有无参构造方法,子类怎么办?
super解决
this解决
super(…)或者this(….)必须出现在构造方法的第一条语句上
class Demo6_Extends {
public static void main(String[] args) {
Son s1 = new Son();
System.out.println(s1.getName() + "..." + s1.getAge());
System.out.println("--------------------");
Son s2 = new Son("张三",23);
System.out.println(s2.getName() + "..." + s2.getAge());
}
}
class Father {
private String name; //姓名
private int age; //年龄
public Father() { //空参构造
System.out.println("Father 空参构造");
}
public Father(String name,int age) { //有参构造
this.name = name;
this.age = age;
System.out.println("Father 有参构造");
}
public void setName(String name) { //设置姓名
this.name = name;
}
public String getName() { //获取姓名
return name;
}
public void setAge(int age) { //设置年龄
this.age = age;
}
public int getAge() { //获取年龄
return age;
}
}
class Son extends Father {
public Son() { //空参构造
this("王五",25); //本类中的构造方法
//super("李四",24); //调用父类中的构造方法
System.out.println("Son 空参构造");
}
public Son(String name,int age) { //有参构造
super(name,age);
System.out.println("Son 有参构造");
}
}