当我们在定义若干个类的时候,发现某一些类中具有相同的属性和行为。那么,我们就可以将这些相同的部分进行抽取,独立生成另外一个类,那么这个生成出来的类我们称之为是父类,其他的被抽取内容的类称之为子类,子类与父类之间就是所谓的继承关系 用 extends来表示。
举例:
工人类的行为有睡觉,吃饭,工作。学生类的行为有吃饭,睡觉,学习。这两个类具有相同的部分——睡觉,吃饭,所以我们可以将相同的部分抽取出来生成另一个类,让学生类与工人类继承它。
工人类:
class Worker{
public void sleep(){
System.out.println("睡觉");
}
public void eat(){
System.out.println("吃饭");
}
public void work(){
System.out.println("工作");
}
}
学生类:
class Student{
public void sleep(){
System.out.println("睡觉");
}
public void eat(){
System.out.println("吃饭");
}
public void study(){
System.out.println("学习");
}
}
继承:
//新生成的类
class Person{
public void sleep(){
System.out.println("睡觉");
}
public void eat(){
System.out.println("吃饭");
}
}
class Worker extends Person{
public void work(){
System.out.println("工作");
}
}
class Student extends Person{
public void study(){
System.out.println("学习");
}
}
单继承的意思是一个子类只能有一个父类,但是一个父类可以有若干个子类。不代表Java当中就没有多继承的时候!如果是类与类之间 必须是单继承;如果是接口与接口之间,可以是多继承。C++的继承属于多继承,不太符合实际的社会问题,所以Java更加符合现实编程。
1.父子类没有静态变量时
如果只有子类有且非私有 那么就调用子类的
class Test2{
public static void main(String[] args){
Son son1=new Son();
System.out.println(son1.num1);//结果是10
}
}
class Father{
int num2=20;
}
class Son extends Father{
int num1=10;
}
如果只有父类有且非私有 那么就调用父类的
class Test2{
public static void main(String[] args){
Son son1=new Son();
System.out.println(son1.num2);//结果20
}
}
class Father{
int num2=20;
}
class Son extends Father{
int num1=10;
}
如果子父类都有且非私有 那么就调用子类的
class Test2{
public static void main(String[] args){
Son son1=new Son();
System.out.println(son1.num1);//结果10
}
}
class Father{
int num1=20;
}
class Son extends Father{
int num1=10;
}
2.父子类有静态变量时
查找顺序:子类对象成员->子类静态->父类成员->父类静态
class Test2{
public static void main(String[] args){
Son son1=new Son();
//先在子类对象成员中找--找到了
System.out.println(son1.num1);
//先在子类对象成员中找--没找到>>再去子类的静态区找--找到了
System.out.println(son1.num2);
//先在子类对象成员中找--没找到>>再去子类的静态区找--没找到>>再去父类对象成员中找--找到了
System.out.println(son1.num3);
//先在子类对象成员中找--没找到>>再去子类的静态区找--没找到>>再去父类对象成员中找--没找到>>再去父类静态区中找--找到了
System.out.println(son1.num4);
}
}
class Father{
int num3=20;
static int num4=40;
}
class Son extends Father{
int num1=10;
static int num2=20;
}
3.子类成员函数在内部调用变量时 :局部变量->子类对象成员->子类静态->父类成员->父类静态
如果只有子类有且非私有 那么就调用子类的
class Test4{
public static void main(String[] args){
Son son3=new Son();
son3.show();
}
}
class Father{
/*public void show(){
System.out.println("这是父类");
}*/
}
class Son extends Father{
public void show(){
System.out.println("这是子类");
}
}
//结果:这是子类
如果只有父类有且非私有 那么就调用父类的
class Test4{
public static void main(String[] args){
Son son3=new Son();
son3.show();
}
}
class Father{
public void show(){
System.out.println("这是父类");
}
}
class Son extends Father{
/*public void show(){
System.out.println("这是子类");
}*/
}
//结果:这是父类
如果子父类都有且非私有 那么就调用子类的(函数重写)
class Test4{
public static void main(String[] args){
Son son3=new Son();
son3.show();
}
}
class Father{
public void show(){
System.out.println("这是父类");
}
}
class Son extends Father{
//这里存在着函数的重写
@Override
public void show(){
System.out.println("这是子类");
}
}
//结果:这是子类
函数重写的意义:
1.保留父类的功能声明 子类可以进一步优化
2.保留父类的功能声明 子类可以重新定义函数重写是注意的细节:
1.函数重名 但是参数列表不同 不构成重写关系
2.函数重名 参数列表相同 构成重写关系 返回值类型也必须是一样的
3.子类重写父类函数时,权限>=父类权限
4.当然 如果父类函数权限为private 子类压根就继承不到 何谈重写
子类的构造函数在调用运行的时候 先执行父类的构造函数,因为在子类的构造函数当中,有一句默认的super()隐藏了。
对super的调用必须是构造器中的第一个。
class Test3{
public static void main(String[] args){
Son son2=new Son();
}
}
class Father{
Father(){
System.out.println("父类构造函数!");
}
}
class Son extends Father{
//super(); 此处省略了
Son(){
System.out.println("子类构造函数!");
}
}
//结果:
//父类构造函数!
//子类构造函数!
注意super(...) 如果父类没有默认无参构造函数 那么子类构造函数中super()失效了
所以在调用父类构造函数时,一定要注意父类构造函数的参数情况!适时修改super(...)
例如:
class Test3{
public static void main(String[] args){
Son son2=new Son();
}
}
class Father{
Father(int num){
System.out.println("父类构造函数!");
}
}
class Son extends Father{
Son(){
super();
System.out.println("子类构造函数!");
}
}
//报错:
/*
Test3.java:13: 错误: 无法将类 Father中的构造器 Father应用到给定类型;
super();
^
需要: int
找到: 没有参数
原因: 实际参数列表和形式参数列表长度不同
1 个错误
*/
解决方法:给super的参数列表添加对应的参数 或者 给Father类添加一个默认的构造函数。
1、this关键字值的是对当前对象的引用,super关键字值的是对当前对象的空间的引用
2、this(...)是当前类中 本类构造函数调用本类构造函数的方式。
super(...)是本类构造函数调用父类构造函数的方式
3、两者都必须在第一行(既然两者都必须在第一行,那么两者是否冲突 )
如果本类构造函数当中不存在调用关系 那么每一个本类构造函数第一句都是super(...)
如果本类构造函数当中存在调用关系,那么最后被调用的那个构造函数第一句绝对是super(...)
class Son extends Father{
int num1=20;
static int num2=30;
Son(){
//本构造函数调用了Son(int num1,int num2),因此存在调用关系,所以第一句是this()
this(0,0);
System.out.println("Son constructor1......");
}
Son(int num1){
//本构造函数调用了Son(int num1,int num2),因此存在调用关系,所以第一句是this()
this(0,0);
System.out.println("Son constructor2......");
}
Son(int num1,int num2){
//本构造函没有调用了其他构造函数,因此不存在调用关系,所以第一句是super()
super();
System.out.println("Son constructor3......");
}
}