学习目录
继承
继承的概念
继承是面向对象程序设计使代码可以复用(重复的使用)
的最重要的手段,它允许程序员在保持原有类特 性的基础上进行扩展,增加新功能,这样产生新的类,称子类(派生类)
,继承呈现了面向对象程序设计的层次结构, 体现了由简单到复杂的认知过程
继承主要解决的问题是:共性的抽取,实现代码复用
例如:狗和猫都是动物,那么我们就可以将共性的内容进行抽取,然后采用继承的思想来达到共用
继承的语法
在Java中如果要表示类之间的继承关系,需要借助extends
关键字
例如:
修饰符 class 子类 extends 父类 {
// ...
}
我们写一个例子来说明一下父类和子类
例如:
结果:
子类访问父类成员
访问父类成员有二种情况
子类和父类不存在同名成员变量
这种情况下可以直接正常的访问
例如:
父类
class Animal{
String name;
int age;
}
子类(Dog) 继承 父类(Animal)
class Dog extends Animal{
int yog = 1; 子类自己的成员变量
void bark(){
yog = 66; 访问子类自己的成员
name = "旺财"; 这是子类访问继承父类的成员
System.out.println(name + "在玩耍");
}
}
子类和父类成员变量同名
这种情况也分二种:
1 与父类中成员同名,且类型相同
2 与父类中成员同名,但类型不相同
父类
class Animal{
int a = 1;
int b = 2;
int c = 3;
}
class Dog{
int a; 1 与父类中成员同名,且类型相同
char b; 2 与父类中成员同名,但类型不相同
public void Add(){
a = 16;
b = 86;
c = 99;
}
这种情况下是优先访问子类自己的成员,没有在从父类找
}
结果: 16 86 99
- 如果访问的成员变量里,子类里有的优先访问自己成员变量,没有在到父类中找
如果都没有编译器就会报错,成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找
super关键字
super关键字:如果子类和父类中存在相同名称的成员,通过super .
就可以在子类中访问父类的成员
super
关键字有三种用法:
访问父类普通成员变量、访问父类普通成员方法、调用父类的构造方法
- 访问父类普通
成员变量
例如:在子类和父类成员变量名字类型都相同的情况下
//父类
class A {
String name = “大黑”;
int age;
}
//子类
class pen extends A{
String name = “小白”;
double age;
public void house(){
System.out.println(super.name + "正在看家");
}
super 是获取到子类对象中从基类继承下来的部分
结果:
- 子类访问父类的
成员方法
父类和子类中构成重载的方法,直接可以通过参数列表区分清访问父类还是子类方法
- super 只能在
非静态
的成员方法里使用 - 访问父类的方法或者成员,必须在子类的方法里
- 对于
父类的private成员变量
,子类会继承
该成员变量,但是不可以访问
! - java不支持
多继承
,即一个类只能继承一个父类
子类构造方法
如果子类里有构造方法,那么需要先调用父类构造方法
,然后执行子类的构造方法
子类构造方法有二种:
父类构造方法无参数
父类构造方法有指定参数
- 父类构造方法无参数
无参数的情况下,在你没有提供构造方法时,编译器会默认提供一个无参数的构造方法
class A {
public String name;
public int age;
//父类无参数的构造方法 如果没有写编译器会默认提供一个
public A() {
System.out.println("父类 A() 构造方法");
}
}
class B extends A{
int a = 0;
//子类无参数的构造方法 如果没有写编译器会默认提供一个
public B(){
System.out.println("子类 B() 构造方法");
}
}
结果:
- 父类构造方法有指定参数
如果父类构造方法是带有参数的
,此时需要自己给子类定义构造方法
,并且子类的参数必须和父类的相同
并且子类构造方法中必须先给父类
构造方法初始化,否则编译失败
总结:
- 如果父类构造方法是无参数的,编译器会默认给子类提供一个无参数构造方法
- 如果父类构造方法是有参数的,那么子类的构造方法必须自己定义,并且参数必须和父类的一样
- 子类对象中成员是有两部分组成的,
父类继承下来的以及子类新增加的部分
在程序执行过程中,会先在构造子类对象时候 ,先要调用父类
的构造方法,将从父类
继承下来的成员构造初始化
,然后再调用子类
自己的构造方法,将子类
自己新增加的成员初始化
完整 - 子类构造方法在先初始化父类的构造方法时,使用的
super( )
必须是在子类构造的第一行
super
只能在子类构造方法中出现一次,并且不能和this同时出现
super 和 this 的不同之处
super
和this
都可以在成员方法中用来访问:成员变量
和调用其他的成员函数
并且都要作为构造方法的第一条语句,那么它们之间的区别呢
- 相同之处
super
和this
都是Java 的关键字,并且只能在类的非静态方法
中使用,用来访问非静态成员方法
和字段
在构造方法中调用时,必须是构造方法中的第一条语句,但是它们不能同时存在
- 不同之处
this
是哪个对象调用它,引用的就是那个对象
super
是只引用子类继承父类的成员变量或者方法- . 在非静态成员方法中
this
用来访问本类的方法和属性
super
用来访问父类继承下来的方法和属性 - 在构造方法中:
this(...)
用于调用本类构造方法
super(...)
用于调用父类构造方法,并且两种调用不能同时在构造方法中出现 - 构造方法中一定会存在
super(...)
的调用,用户没有写编译器也会增加,但是this(...)
用户不写则没有
子类和父类在代码块的执行顺序
之前在没有继承的情况下代码块的执行顺序:静态代码块、实例代码块、构造方法
静态代码块是只执行一次的
实例代码块和构造方法是对象调用几次就使用几次
如果在父类和子类还有构造方法里写静态代码和实例代码,执行的顺序还会一样吗?
例如:
class A {
public String name;
public int age;
public A(String name,int age) {
System.out.println("父类A() 构造方法");
}
{
System.out.println("父类实例代码块");
}
static{
System.out.println("父类静态代码块");
}
}
class B extends A{
public B(String name,int age){
super(name,age);
System.out.println("子类 B() 构造方法");
}
{
System.out.println("子类实例代码块");
}
static{
System.out.println("子类静态代码块");
}
}
public class Test {
public static void main(String[] args) {
B a = new B("小明",20);
System.out.println("===========================");
B b = new B("小红",18);
}
结果:
总结:
- 父类静态代码块优先于子类静态代码块执行,且是最早执行
- 父类实例代码块和父类构造方法紧接着执行
- 子类的实例代码块和子类构造方法紧接着再执行
- 第二次引用实例化子类对象时,父类和子类的静态代码块都将不会再执行
protected 关键字
protected
作用:限定了类或者类中成员能否在类外或者其他包中被访问
protected
在同一包中相同的类使用:
protected
在同一包中不同类使用:
protected
在不同包中的子类中使用:
继承的方式
Java 继承的方式有三种:
例如:
- Java 不支持一个类继承二个类
- 一般继承不要超过三层
final 关键字
final
可以用类修饰变量、成员方法、类
- 使用
final
修饰变量:
final int a = 10;
变量在被 final 修饰后变成了常量,就不能在被修改了
a = 20; 编译出错
- 使用
final
修饰方法:
之后在补充
- 使用
final
修饰类:
被 final
修饰后被称为 密封类
被修饰后这个类就不能在被继承
final public class Animal {
...
}
Java 的组合
组合 和 继承 类似,也是一种表达类之间关系的方式, 也是能够达到代码复用的效果
组合是将一个类或多个类作为成员变量(属性)来使用
例如:
学生和老师是学校的一部分,可以组合到学校的类中
class Student{ // 学生
}
class Teacher{ //老师
}
class School{ // 学校
public Student[] stu;
public Teacher[] t;
}
总结
- 继承
继承可以使面向对象的代码进行复用,可以使一个类继承另一个类的成员变量(属性)和方法
继承可以分二种:父类
和子类
继承父类的成员变量(属性)和方法的被称为子类(派生类)
被继承的类叫父类(基类、超类)
继承是通过extends 关键字
进行
- 子类访问父类成员
子类访问
父类的成员或者方法
时必须在方法
里进行
如果子类和父类成员变量同名
的情况下,是优先访问子类的成员,没有在到父类中找
如果子类和父类成员变量同名且类型不同
的情况下,是通过类型来区分
super
关键字
super
作用:从子类中找继承父类的成员变量和方法,使用方法:super . 变量名
如果子类和父类成员变量同名
的情况下,在使用super
是优先访问父类的成员
如果父类和子类中构成重载的方法
,直接可以通过参数列表区分
清访问父类还是子类方法
super
只能在非静态
的成员方法里使用,而且必须在子类的方法里使用
- 子类构造方法
对象是通过构造方法进行实例化的,编译器会默认提供一个
如果父类的构造方法是无参数的,编译器会默认在子类提供一个构造方法
如果父类构造方法是有参数的,那么子类的构造方式必须自己写,而且子类构造的参数必须和父类的一样
在初始化时,必须先在子类的方法里初始化父类,在初始化子类自己的 在初始化父类构造方法时,
使用的super
必须是在方法的第一行,并且不能和this
同时出现
super
和this
的区别
super
是用来找子类继承父类的成员变量和方法的
this
是谁调用它,引用的对象就是谁
- 子类和父类在代码块的执行顺序
在子类和父类里定义静态代码块、实例代码块、构造方法时
执行的顺序:父类和子类静态代码
、父类的实例代码块和构造方法
、子类的实例代码块和构造方法
静态代码块
是优先执行
的,如果有多个静态代码块
,是按照从上到下按顺序执行
静态代码块
是只执行一次
的,其他是按照顺序进行执行,先调用那个执行那个