动力节点——继承(十二)

来源:互联网 发布:php游戏开发教程 编辑:程序博客网 时间:2024/04/20 03:06

一,继承前序

1,在真正编码中,体现类和类之间的关系(对象和对象之间的关系)

最常用的不是继承,而是包含和使用。

使用:形式参数

包含:属性

2,学习继承的目的

因为继承是面向对象思想的特征之一,又因为java语言实现了面向对象思想;

所以java语言才必须支持继承,学习继承是为了以后学习多态打基础。

综合上述,如果在一个类中想使用另一个类的属性和行为,第一个想到的不是

继承,而是使用和包含。


二,继承的引入

1,继承的语法

在以下的实例中;

猫类和狗类一般在继承体系中叫做子类

公共类    动物类一般在继承体系中叫做父类或者超类

/*

从两个猫和狗的动物类中,看到很多重复的代码,可以把重复的代码定义到一个类中,

使用extends关键字让猫和狗类继承这个写好的公共类。那么公共类中的代码就可以被

猫和狗类的对象所使用,这个就是java语言中的实现继承的方式。

*/

class  Animal{

        String  color;

        int  age;

        public  void  sleep(){}

}

//编写一个猫类

class  Cat  extends  Animal{

        /*

        String  color;

        int  age;

        public  void  sleep(){}

        */

        public  void  catchMouse(){

                System.out.println("猫抓老鼠");

        }

}

class  Dog  extends  Animal{

        /*

        String  color;

        int  age;

        public  void  sleep(){}

        */

        public  void  careRoom(){

                System.out.println("狗看家");

        }

}

public  class  ExtendsDemo{

        public  static  void  main(String[]  args){

                //创建一个猫类对象

                Cat  cc=new  Cat();

                System.out.println(cc.color);//这里猫类的对象可以访问公共类中属性,证明继承关系成立。

        }

}


三,继承特点

1,子类可以直接继承父类的成员

2,子类不可以继承父类的私有成员;子类不可以使用父类的私有成员。

3,封装性是指把一个类的所有成员属性都定义为private,但是这样,就所有属性都不能被子类继承;

如果想让子类继承父类的成员,那么这个成员就绝对不能使用private修饰符,也就是说使用继承会打破封装性。


通过以上的描述,我们可以看出继承在体现提取公共代码、提升编码效率上的目的是错误的;

继承只是体现了实际生活中的两个事物之间的继承关系;

如果生活中两个事物不是继承关系,而只是在代码中为了代码复用,使用继承关系是错误的。

4,父类的构造方法是不能被子类继承的

5,在子类创建之前必须先创建父类对象

6,在子类构造方法执行之前必须先执行父类的构造方法;

默认是调用父类的无参的构造方法(实际上默认使用super()  调用的),

无论子类在创建对象时是调用无参的还是有参的构造方法,则都是默认调用父类的无参构造方法;

可以在子类的构造方法中,手动使用super(参数值);来指定调用父类的哪个构造方法。

7,在java语言中,类和类之间是不能多继承的,一个类不能同时继承多个类的。

如果在考题中描述为,在java语言中,是不能多继承的 。这样说也是对的

8,java语言中,继承是可以有继承体系的(多层继承)

class  Fu{

        int  a=10;

        //private  int  c=30;

        public  Fu(){

                System.out.println("这是父类无参的构造方法")

        }

        public  Fu(int  a){

                System.out.println("这是父类带参的构造方法");

                this.a=a;

        }

        public  void  test(){

                System.out.println("这是父类的普通成员方法test");

        }

}

class  Zi  extends  Fu{

        int  b=20;

        public  Zi(){

                System.out.println("这是子类的无参构造方法");

        }

        public  Zi(int  b){

                super(b);//指定调用父类带参的构造方法

                System.out.println("这是子类带参构造方法");

                this.b=b;

        }

        public  void  privt2(){

                System.out.println("这是子类的privt2方法");

        }

        

}

public  class  ExtendsDemo1{

        public  static  void  main(String[]  args){

                //创建子类对象

                Zi  zz=new  Zi();

                //体现继承关系

                //子类可以使用父类的成员

                System.out.println(zz.a);

                zz.test();

                //System.out.println(zz.c);//父类的私有成员,子类不能使用


                //调用子类带参的对象

                Zi  zz=new  Zi(10);

        }

}


四,继承对成员变量的影响:

1,继承关系中查找成员变量的次序;

先从自身查找,如果没有再查找父类,父类没有再查找祖先类的;

在哪个步骤先找到就停止,如果都找不到就报错误。

2,如果子类和父类有相同名称的成员变量,则执行自身的。

3,子类中的静态成员变量在执行也是符合第二条的原则。

class  Fu{

        int  a=10;

        static  int  a=10;

        public  void  test1(){

                

        }

}

class  Zi  extends  Fu{

        int  a=20;

        static  int  a=20;

        public  void  tets2(){}

}

public  class  ExtendsDemo2{

        public  static  void  main(String[]  args){

                //创建子类对象

                Zi  zz=new  Zi();

                System.out.println(z.a);//10

                System.out.println(z.b);//20

        }

}


五,继承对成员方法的影响:

1,子类的构造方法执行之前必须先执行父类的构造方法。

2,子类的构造方法默认是调用父类的无参的构造方法

3,可以在子类的构造方法中使用super(参数值);来指定调用父类的哪个构造方法。

class  Fu1{

        public  Fu1(){

                System.out.println("Fu1类的无参构造方法");

        }

}

class  Zi1  extends  Fu1{

        int  a=10;

        public  Zi1(){

                System.out.println("Zi1类的无参构造方法");

        }

        public  Zi1(int  a){

                this();

                System.out.println("Zi1类的带参构造方法");

                this.a=a;

        }

}

public  class  ExtendsDemo3{

        public  static  void  main(String[]  args){

                Zi1  zz=new  Zi1(20);

        }

}


六,继承对成员方法的影响:

1,从继承体系中查找待调用方法;

先从自身查找,再查找父类,其后依次查找所有祖先类,哪一个找到了,则就不再查找。

2,父子类中出现同名称的普通成员方法(重点)。

会直接执行子类的成员方法。

3,父子类中出现同名称的静态成员方法。

会直接执行子类的成员方法。

class  Fu2{

        public  void  test1(){

                System.out.println("这是父类的普通成员方法test1");

        }

        public  static  void  test3(){

                System.out.println("这是父类的静态成员方法test3");

        }

}

class  Zi2  extends  Fu2{

        public  void  test1(){

                System.out.println("这是子类的普通成员方法test1");

        }

        public  void  test2(){

                System.out.println("这是子类的普通成员方法test2");

        }

        public  static  void  test4(){

                System.out.println("这是子类的普通成员方法test4");

        }

}

public  class  ExtendsDemo4{

        public  static  void  main(String[]  args){

                //创建一个子类对象

                Zi2  zz=new  Zi2();

                //zz.test2();

                zz.test1();

                zz.test3();

        }

}


七,继承中的方法重写

1,方法重写只发生在继承体系中。

2,方法重写就是子类中有和父类相同的方法;

则执行时是执行子类的而不是父类;

因为子类会继承父类的方法,而自己还有相同的方法;

所以在执行时执行的是自己的,就好像把父类的方法重写了。

3,方法重写和方法重载总结:

方法重载(overload)

        方法重载必须发生在一个类内部

        方法重载和修饰符没有关系

        方法重载和返回值类型没有关系

        方法重载必须和方法名称一样

        方法重载必须形式参数不同

                个数不同   or

                对应的数据类型不同

        方法重载和方法抛出异常类型没有关系

        方法重载和返回值没有关系

        方法重载和方法体没有关系


方法重写(override)

        方法重写必须发生继承体系中

        方法重写和修饰符有关系

                子类方法放的修饰符必须大于等于父类的修饰符(这里一般是指权限修饰符)

        方法重写和返回值类型有关系

                必须一样

        方法重写必须和方法名称一样

        方法重写必须形式参数相同

        方法重写和方法抛出异常类型有关系

                子类的方法抛出异常类型必须小于等于父类的方法抛出异常类型

        方法重写和返回值有关系

                必须一样

        方法重写和方法体没有关系


八,super关键字

1,它是用在子类对象指向父类对象数据

2,super关键字只能在子类内部

3,super的使用方式:

在子类对象中使用super . 成员变量名称访问父类对象的成员变量。

在子类对象中使用super . 成员方法名称(参数值);调用父类对象的成员方法。

在子类对象中,在某个构造方法中可以使用super(参数值);指明在创建子类对

象时需要调用父类的哪个构造方法(重点)

这个super(参数值);代码必须写在第一行。

如果子类的构造方法中使用super(参数值)调用了父类的构造方法,则就不能再使

用this(参数值)调用本类其它构造方法。

如果子类的构造方法中使用this(参数值)调用了子类的其它构造方法,则就不能再

使用super(参数值)调用父类的构造方法。

class  Fu3{

        int  a=10;//父类成员变量

        public  Fu3(){

                System.out.println("父类的无参构造方法");

        }

        public  Fu3(int  a){

                System.out.println("父类的带参构造方法");

        }

        public  void  test1(){

                System.out.println("父类的成员方法test1");

        }

}

class  Zi3  extends  Fu3{

        int  a=20;//本类成员变量

        public  Zi3(){

                System.out.println("子类的无参构造方法");

        }

        public  Zi3(int  a){

                super(a);//使用super指明在创建对象时使用父类哪个构造方法

                System.out.println("子类的带参构造方法");

                this.a=a;

        }

        public  void  test2(){

                int  a=30;//局部变量

                System.out.println("子类的成员方法test2");

                System.out.println("1  a="+a);//  30

                System.out.println("2  a="+this . a); //20

                //使用super指明说明此代码需要输出父类对象的成员变量的值

                System.out.println("3  a="+super . a);

        }

        public  void  test3(){

                System.out.println("子类的成员方法test3");

                //子类Zi3继承了父类Fu3,则Fu3的非私有成员就可以认为是属于子类对象的

                //一下三句代码都是等价的

                test1();

                this . test1();

                super . test1(); 

        }

}

public  class  ExtendsDemo5{

        public  static  void  main(String[]  args){

                Zi3  zz=new  Zi3();

                zz.test2();

        }

}


九,继承的内存图解

class  Fu4{

        int  a=10;

        public  void  test1(){}

}

class  Zi4  extends  Fu4{

        int  b=20;

        public  void  test1(){}

}

public  class  ExtendsDemo6{

        public  static  void  main(String[]  args){

                Zi4  zz=new  Zi4();

        }

}


注:先加载父类的描述信息,再加入子类描述信息。对象开辟空间首先开辟父类对象空间并默认初始化,

再显示初始化。然后开辟this指向父类空间。

之后才开辟子类对象空间并默认初始化,再显示初始化。然后开辟this指向本类对象空间,super指向父类对象空间。


十,继承体系中代码块的综合练习

class  Fu5{

        int  a=10;

        {

                System.out.println("父类静态代码块1");

        }

        {

                System.out.println("父类构造代码块1");

        }

        public  Fu5(){

                System.out.println("父类的无参构造方法");

        }

        public  Fu5(int  a){

                this();

                System.out.println("父类的带参构造方法");

        }

        {

                System.out.println("父类的静态代码块2");

        }

        {

                System.out.println("父类构造代码块2");

        }

        public  static  void  test1(){

                System.out.println("父类的静态成员方法Test1");

        }

}

class  Zi5  extends  Fu5{

        int  b=20;

        {

                System.out.println("子类静态代码块1");

        }

        {

                 System.out.println("子类构造代码块1");

        }

        public  Zi5(){

                System.out.println("子类的无参构造方法");

        }

        public  Zi5(int  b){

                super(b);

                System.out.println("子类的带参构造方法");

        }

        {

                System.out.println("子类静态代码块2");

        }

        {

                System.out.println("子类构造代码块2");

        }

        public  static  void  test1(){

                System.out.println("子类的静态成员方法test1");

        }

}

public  class  ExtendsDemo7{

        public  static  void  main(String[]  args){

                Zi5  zz=new  Zi5(10);

                Zi5 . test1();

                //执行顺序是什么?

                /*

                        加载阶段

                                父类的静态代码块1

                                父类的静态代码块2

                                子类的静态代码块1

                                子类的静态代码块2

                        父类对象创建阶段

                                父类的构造代码块1

                                父类的构造代码块2

                                父类的无参构造方法

                                父类的带参构造方法

                        子类对象创建阶段

                                子类的构造代码块1

                                子类的构造代码块2

                                子类带参的构造方法

                        Zi5 . test1()的输出

                                子类的静态成员方法test1

                */

        }

}  


十一,一个对象创建过程的步骤:

加载

        把class文件加载入内存

                先把父类的加载入内存(继承迭代关系)

                再把子类的加载入内存

        为父类的静态成员变量开辟空间并默认初始化

        为父类的静态成员显示初始化

        为父类的静态成员方法开辟空间

        为父类的成员方法开辟空间

        执行父类的静态代码块

        为子类的静态成员变量开辟空间并默认初始化

        为子类的静态成员变量显示初始化

        为子类的静态成员方法开辟空间

        为子类的成员方法开辟空间

        执行子类的静态代码块

创建

        为父类对象开辟空间

        为父类的普通成员变量开辟空间并默认初始化

        为父类的普遍成员变量显示初始化

        为父类的this    super指针开辟空间

        执行父类的构造代码块

        执行父类的构造方法(会出现构造方法嵌套使用)

        为子类对象开辟空间

        为子类的普通成员变量开辟空间并默认初始化

        为子类的普通成员变量显示初始化

        为子类的this    super指针开辟空间

        执行子类的构造代码块

        执行子类的构造方法(会出现构造方法嵌套调用)

使用


十二,final关键字

1,定义:

final的含义是最终的(就是最后,不能改变变量)

2,final使用方式:

A,final修饰类,被final修饰的类不能被继承

B,final修饰成员方法,被final修饰的成员方法不能再子类中被重写

C,final修饰成员变量,被final修饰的成员变量是常量。(自定义常量)

3,final修饰局部变量:(重点)

A,final修饰的基本数据类型的局部变量,就是常量,其值不可改变。

B,final修饰引用数据类型的局部变量,是这个局部变量指向的地址不能被改变。

class  E{

        int  a=10;

}

public  class  FinalDemo{

        public  static  void  main(String[]  args){

                //final修饰的基本数据类型的局部变量

                final  int  a=10;

                //a=20;//a被final修饰,其值不能再发生改变

                

                //final修饰引用数据类型的局部变量

                final  E  ee=new  E();

                //ee.a=20;

                E  ee2=new  E();

                //ee=ee2;//ee被final修饰,其值即指向的地址值不能被改变

        }

}


0 0