继承
-
概念:
Java继承继承是面向对象最显著的一个特性。继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。Java继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。这种技术使得复用以前的代码非常容易,能够大大缩短开发周期,降低开发费用。
继承(inheritance)
还原客观世界中的 is a关系
(一) is a 关系
- 即是什么是一种什么, 例如:
柠檬 是一种 水果(苹果 is a 水果)
山竹 是一种 水果(山竹 is a 水果)
狗 是一种 动物 (狗 is a 动物)
机械键盘 是一种 键盘(机械键盘 is a 键盘) - is a 关系的特点: 前者一定具备后者的特征与行为,可以简单的理解,子类可以看作是对父类的拓展
(二) 计算机中的is a关系
-
特点:
1. 计算机中的is a 关系称之为继承关系,是一种类与类之间的关系。 2. 前者称为父类、基类或超类,后者称为子类或派生类。 3. 当继承关系建立时,子类也能“拥有”父类中的特征(属性)与行为(方法)。
-
继承的语法
class 类名 extends 父类名{ }
(三) 继承效果
-
子类可以继承到父类中的非私有属性和方法
例:
class Animal{ String name; int age; public void sleep(){} public void eat(){} } class Dog extends Animal{//Dog继承了Animal 可以使用Animal中定义的属性或方法 }
-
Dog类继承了Animal类,则Dog类会获得Animal类中的非私有属性与方法
例:创建Dog对象,访问Animal中定义sleep,eat方法
public static void main(String[]args){ Dog d = new Dog(); d.sleep();//虽然Dog类中没有定义sleep方法,但是Dog继承了Animal所以Dog也能调用Animal中的方法 d.eat(); }
-
继承关系在内存中的表现
父类对象会成为子类对象的一部分,因此可以通过子类对象,使用父类对象中的属性或者方法
-
继承的传递性
父类还可以有父类,父类的父类的父类还可以再有父类...以此类推,属性与方法一直会向下传递
例:
public class TestIntan{
public static void main(String[]args){
MyClassD mc = new MyClassD();
System.out.println(mc.a);//访问太爷类中的a属性
System.out.println(mc.b);//访问爷爷类中的b属性
System.out.println(mc.c);//访问父类中的c属性
System.out.println(mc.d);//访问本类中的d属性
}
}
class MyClassA{
int a;
}
class MyClassB extends MyClassA{
int b;
}
class MyClassC extends MyClassB{
int c;
}
class MyClassD extends MyClassC{
int d;
}
注意: Java中继承关系为单继承,一个类只能有一个直接父类,可以间接继承。
(四) 访问权限控制符
- 作用:控制组件可见(可用,可访问)的范围
修饰符 | 本类 | 同包 | 其他包中的子类 | 不同包中的其他类 |
---|---|---|---|---|
private | √ | |||
default(不写权限控制) | √ | √ | ||
protected | √ | √ | √(在其他包中,通过子类对象进行访问) | |
public | √ | √ | √ | √ |
注意: 当组件前没有访问权限修饰符时,默认为(default)修饰
(五) 方法的覆盖(Override) (重点概念)
- 使用场景:
当父类的方法不再适用于子类或无法满足子类需求时,可以覆盖掉父类的方法
再对其进行调用时,会调用覆盖后的方法
语法:
返回值类型、方法名、参数表相同,修饰符相同或更宽
例:
public class TestOverride{
public static void main(String[]args){
Sub sub = new Sub();
sub.m1();//调用子类覆盖后的m1方法 打印 m1 in sub
}
}
class Super{
public void m1(){
}
}
class Sub extends Super{
//覆盖:访问权限修饰符相同或更宽 返回值类型、方法名、参数表相同
public void m1(){
System.out.println("m1 in sub");
}
}
- 方法覆盖与方法重载的区别
1. 方法覆盖发生在父子类之间,语法要求:访问权限修饰符相同或更宽 返回值类型、方法名、参数表相同。
2. 方法重载可以在本类中,也可以在父子类间进行重载,语法要求:方法名相同、参数表不同,其他无要求。
例:
public class TestOverride2{
public static void main(String[]args){
Sub sub = new Sub();
sub.m1();//调用父类中的m1()方法
sub.m1(10);//调用子类中的m1(int)方法
}
}
class Super{
public void m1(){
System.out.println("m1 in super");
}
}
class Sub extends Super{
//与父类的方法构成重载
public void m1(int n){
}
}
(六) 对象创建的过程
1. 分配空间(父类+子类)
2. 初始化父类属性
3. 调用父类构造方法
4. 初始化子类属性
5. 调用子类构造方法
注意:遵循先父后子的顺序,如果父类还有父类,那么就要先初始化父类的父类以此类推...
class Super{
public Super(){//父类构造方法
System.out.println("Super()");
}
}
class Sub extends Super{
public Sub(){//子类构造方法
System.out.println("Sub()");
}
}
注意:自动创建父类对象时,由于默认调用父类的无参构造方法,如果父类没有无参构造方法,则会产生编译错误
(七) super关键字
-
含义: super表示父类对象的引用
- 使用super. 访问父类中的属性或方法 使用时机:当父类的方法或属性被子类覆盖时,可以使用super. 访问父类的方法或属性
例:访问父类的属性
class Super{ int a=10;//父类属性 } class Sub extends Super{ int a=20;//子类属性 public void m1(){ int a = 30;//局部变量 System.out.println( a ); //打印局部变量a System.out.println( this.a ); //打印本类属性a System.out.println( super.a ); //打印父类属性a } }
例:访问父类被覆盖的方法
class Super{ public void m1(){ System.out.println("m1 in super"); } } class Sub extends Super{ public void m1(){//覆盖父类的方法 super.m1();//调用父类中的m2方法 System.out.println("m1 in sub"); } }
2.使用super() 明确自动创建父类对象时,所使用的构造方法,默认使用父类的无参构造方法 使用时机:使用父类构造方法初始化父类属性(非必要操作)
例:
class Animal{
String name;
int age;
public Animal(){}
public Animal(String name, int age){
this.name = name;
this.age = age;
}
}
class Dog(){
public Dog(String name,int age){
//使用父类有参构造为属性赋值
super(name,age);
}
}
注意:
- super()只能定义在构造方法的第一行
- 每个构造方法第一行代码隐式包含super() 表示创建对象时默认使用父类的无参构造方法
- 定义类时通常会为该类添加两个构造方法,有参构造方法为属性赋值,无参构造方法用于子类创建对象时使用,这是一种约定俗成的编程习惯