面向对象三大特性:封装、继承、多态。
一、继承
1.1继承的理解
生活中的继承
当你放弃学习编程,只能失败地回去继承亿万家业了,这是生活中继承,但大部分人都只能回去继承一个锄头和几块田
程序中的继承
- 程序中的继承,是类与类之间特征和行为的一种赠与或获得。
- 两个类之间的继承关系,必须满足“is a”的关系。
继承是满足is-a形式的,一般来说,子类拥有父类的所有特征,若不同的就重写和添加,越是继承,越是精细。- 功能越精细,重合点越多,越接近直接父类。
- 功能越粗略,重合点越少,越接近Object类。(万物皆对象的概念)
例如:就行如果定义一个动物类,那么我定义为 “能运动的,由细胞组成”的为动物。
那么我创建一个猫猫类,猫是肯定是动物的,所以继承了动物类,但它身上又有很多特征,如爱吃鱼,喵喵叫等
这时候我有一只波斯猫,也肯定属于猫科的,有猫猫类的所有特征,但它的毛色是白色的,眼睛是蓝色的,叫声为“喵呜”(这个不同,需要重写)
这么一来,波斯猫是继承了猫猫类的几乎所有特征,同时也继承了动物类的特征,同时还添加了很多自己的特征
所以说这是越分越细,越分越大的一个过程(由小变大过程)。
1.2继承的属性和方法
在java里,extends为继承
//动物类
public class Animal {
boolean live = true;
String make = "cell";
public void move(){
System.out.println("动物能动");
}
}
public class Animal {
boolean live = true;
String make = "cell";
public void move(){
System.out.println("动物能动");
}
}
//猫猫类
public class Cat extends Animal {
增加了两个特征
public void eat(){
System.out.println("爱吃鱼");
}
public void say(){
System.out.println("喵喵叫");
}
}
//下面调用一下猫猫类
public class Demo01 {
public static void main(String[] args) {
Cat cat = new Cat();
System.out.println("活的:" + cat.live); //动物类的
System.out.println("组成:" + cat.make); //动物类的
cat.eat();
cat.say();
cat.move(); //动物类的
}
}
结果:
活的:true
组成:cell
爱吃鱼
喵喵叫
动物能动
可以看到,猫猫类没有定义live 和make 属性和move 方法(动物类定义了),但猫猫类继承了动物类,也能用它的属性和方法。
1.2.1继承的属性和方法修改
有人认为,猫不是细胞做的,是水做的,这我也不好反驳,有人说后面的move内容应该改为 “猫好动”,这我觉得非常合理
public class Cat extends Animal {
String make = "water"; //修改一
public void eat(){
System.out.println("爱吃鱼");
}
public void say(){
System.out.println("喵喵叫");
}
@Override
public void move() { //修改二
System.out.println("猫好动");
}
}
//实例化一下运行
public class Demo01 {
public static void main(String[] args) {
Cat cat = new Cat();
System.out.println("活的:" + cat.live); //这是修改过的
System.out.println("组成:" + cat.make);
cat.eat();
cat.say();
cat.move(); //这是修改过的
}
}
结果:
活的:true
组成:water
爱吃鱼
喵喵叫
猫好动
1.2.2 方法的重写(重点)
当父类的方法不适合于子类时候,就进行重写
move()方法被我修改过了,在java里这叫重写,重写只发生在继承里
读者也可以看到,重写的方法上面顶着一个“@Override”,这个标志着该方法是重写过的(有的编辑器会显示这个,有的不会)
重写的原则(重点)
//重写前
public void move(){
System.out.println("动物能动");
}
//重写后
public void move() { //修改二
System.out.println("猫好动");
}
重写只能改动访问修饰符和方法里面的内容
-
不能改动参数,和返回值类型,更不能改变方法名了
-
而改动访问类型,只能由小变大(public是最大了,不能改变,可以由private 改成public)一般比较少改动
-
如果改变了参数,那不叫重写了,叫重载了,和重载还是很有区别的
1.3继承的构造方法
1.3.1继承无参构造
原理上,构造方法是不算继承的,继承是指类的继承(没实例化前就继承好了),构造方法是实例化之后才有的
但是,但你在父类也写上了构造方法后,就会发现,构造方法也继承过去了
(下面的我把它整理到一起,方便读者阅读)
//动物类
public class Animal {
public Animal(){
System.out.println("我是动物");
}
}
//猫猫类
public class Cat extends Animal {
public Cat(){
System.out.println("我是猫,喵~");
}
}
//实现猫猫类
public class Demo01 {
public static void main(String[] args) {
Cat cat = new Cat();
}
}
结果:
我是动物
我是猫,喵~
可以看到,实现猫猫类后,他会自动先调取动物类构造方法
但是,构造方法不是在实例化才会执行,是实例化的标志吗,难道实现猫猫类的同时,也把动物类也实现呢?
对的!!你可以想成这样,猫猫类把动物类继承了,相当于把动物类融合在一起了,实例化猫猫类相当于把大家一起实例化了。
1.3.2继承有参构造
这时候可能不服了,其他的我可以和父类像,但构造方法我不想相同
如果无参构造会继承的话,那我值设定有参构造,我又不传参,看你怎么办
//动物类,改为有参构造
public class Animal {
public Animal(int age){
System.out.println("我还是动物");
}
}
//猫猫类
public Cat(){
System.out.println("我是猫,喵~"); //报错了
}
}
报错:There is no default constructor available in 'demo.Animal'
Animal类没有默认的构造方法可用
这时必须改成这样才行
public class Cat extends Animal {
public Cat(){
super(18); //18是随意传入参数,super()这个是调用父类的构造方法意思
System.out.println("我是猫,喵~");
}
}
总结
- 当父类只有无参构造时候,子类实例化会先调用父类的无参构造,再调用自己的构造方法
- 当父类只有有参构造时候,子类实例化必须要先实现父类的有参构造(可以试下,不实现会报错)
- 当父类既有无参构造,又有有参构造时,子类实例化会默认实现无参构造,若调用父类的有参构造需要自己手动进行了
也就是说,无论如何都要实现父类的构造方法,你是改变不了继承父类的血脉这个事实的。
二、this 和 super
上面涉及了super, super和this是相似的
- this -----代表当前类
this() -----代表调用当前类的构造方法
this.属性-----代表当前类属性
this.方法()-----代表当前类的方法- super -----代表当前类的父类
super() -----代表调用父类的构造方法
super.属性-----代表父类的属性
super.方法()-----代表父类的方法
在继承关系中,为什么会自动调用父类的无参构造呢,因为继承时候,有很多你看不见的super 在你的类里面,包括父类的无参构造super()
同时,super()和this()是不能同时出现在一个构造方法(包括其他普通成员方法)里的。
注意,无论有没有写构造方法,在我们创建一个类的时候,java都会自动帮我们建立一个空白的无参构造,直到我们创建了一个构造方法它才会消失
所以说,实例化必会实现该类的构造方法!!!!