JAVA学习笔记

来源:互联网 发布:数码宝贝网络侦探必练 编辑:程序博客网 时间:2024/06/05 15:29

第四章、面向对象的概念和JAVA实现(II

一、学习目标

理论:

掌握JAVA中的三在特性:继承、封装、多态

 

技术:

 多态的应用。

 staticfinal的应用

 

二、本章内容

1、理解继承、封装、多态

2、实现继承、多态

3、理解接口、抽象类

4、掌握访问修饰符

 

 

三、授课思路

(一)、继承、封装、多态

面向对象编程有三个特性,就是继承、封装、多态

 

1、  解释概念

封装:隐藏属性、方法或实现的详细信息的处理方式(我们可以通过后面要学习的访问修饰符来实现封装)(P.53)

 

继承:通过一个实例来理解继承。(遗产继承示例)

 

多态:是指“多种形式”,例如:水,会有糖水,会有盐水,这两种都是水,只是以两种不同的形式存在而以。(JAVA中是通过对方法的重写和重载来实现多态)

 

 

补:什么是抽象???

将实体的相关属性和操作根据特定的应用程序进行标识和分组的过程就是数据抽象。(p55页)

 

 

 

2、  理解继承

A、              为什么要继承???

       例如:有一个矩形类,在这个类中有一个求矩形面积的方法。现在我们要写一个正方形的类,并且这个正方形类中也要有求正方形面积的方法。 那么大家都知道,正方形是矩形类中的一种,如果我们不让正方形去继承矩形类的话,那么,我们就要在这个正方形类中自已写一个求正方形面积的方法。为了能够不做这种重复的事情,所以,我们会让正方形类去继承矩形类,此时,正方形类中也就有了这个求面积的方法。从而就达到重用求面积的方法的作用。(我们可以称矩形类为父类或超类,正方形类为子类)

 

从上面的例子我们可以知道继承的目的就是为了“实现代码的重用。”

 

现在有一个问题,是不是在任何情况下,任何类都可以继承呢???

 

答:并不是的。继承也是有条件的。必需父类和子类之间有相关的联系,才可能进行继承,才有继承的必要。例如:青蛙类可以继承水生动物类也可以继承陆地动物类,因为青蛙既是水生动物也是陆地动物;狗类就只能继承陆地动物,因为狗只具备陆地动物的特点,不具备水生动物的特点,所以,我们不让狗类去继承水生动物类。

 

 

 

 

B、              继承所产生的两种结果:

上面的那矩形例子我们不难发现这么一个问题,如果我想要用求面积的方法,我们不用继承也可以完成呀,就是在正方形类中去实例化矩形这个类,然后能过矩形类的对象去调用这个面积方法,不就可以了吗???为什么还要去继承呢???

 

 

这也就是我们接下来要给大家讲的继承所产生的两种结果。

第一种:完全继承:子类完全继承父类

       就如同我们前面说的那个矩形例子。

第二种:差异继承:子类继承父类后,重写父类中的方法或添加自己的方法

例如:还是那个矩形例子,当正方形继承矩形类后,就会有求面积的方法,同时正方形还可以写自己的求周长的方法。

(演示一个创建窗体的例子)

 

3、  JAVA中实现继承

A、              继承的条件

       有一个父类,有一个子类

       class ClsJX  //矩形类

       {

              public void mj()

              {

                     System.out.println("面积");

              }

       }

       class ClsZFX   //正方形类

       {

             

       }

B、              继承的关键字

       extends

 

       class  ClsZFX  extends  ClsJX   //正方形子类

       {

             

       }

C、              继承的要点

(1)   子类继承父类,可以将父类中的方法进行重写

       class ClsXZ

       {

              public void mj()

              {

                     System.out.println("面积的公式为:长*");

              }

       }

       class ClsYX extends ClsXZ

       {

              public void mj()

              {

                     System.out.println("面积的公式为:3.14*半径*半径");

              }

       }

这种形式一般用于,子类需要父类的方法,但不需要父类方法中的细节,

 

例如:热水器有加热水的功能,我们制造热水器时,需要的是热水器加热水的功能,但我们在制造过程中,使用电来加热还中煤气加热还是太阳加热这就由我们自己决定了。

 

问题:ClsXZ  xz=new ClsYX( );

       xz.mj( );

调用的是父类的还是子类的?????

父类的引用指向子类对象

 

 

(2)   子类继承父类,子类可以有自己的方法。

       class ClsXZ

       {

              public void mj()

              {

                     System.out.println("面积的公式为:长*");

              }

       }

       class ClsJX extends ClsXZ

       {

              public void zc()

              {

                     System.out.println("周长的公式为:(长+宽)*2");

              }

       }

这种形式一般用于,子类继承父类后,想扩充自己的功能。

 

例如:U盘只有用来存储信息的功能,MP3就继承了U盘的特点,并且还扩展了功能,还有听歌的功能。

 

3)子类继承父类时,是不能继承类的构造方法的。

       class ClsXZ  //父类

       {

              ClsXZ()

              {

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

              }

       }

       class ClsJX extends ClsXZ  //子类继承父类

       {

              ClsJX()

              {

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

              }

       }

       class ClsTest

       {

              public static void main(String args[])

              {            

                     ClsJX yx=new ClsJX();         

              }

       }

运行结果:

父类的构造方法

子类的构造方法

 

当实例化子类的时候,首先加载的是父类的构造方法,再加载子类的构造方法。

 

4)、子类继承父类时,可以使用super关键字来调用父类的方法和属性

class Calyx

{

       int c=1;

       int k=1;

       ClsXZ()

       {

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

       }

       public void mj()

       {

              System.out.println("面积的公式为:长*");

       }

}

class ClsJX extends ClsXZ

{

       ClsJX()

       {

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

       }

       public void zc()

       {

              System.out.println("周长的公式为:(长+宽)*2");

       }

       public void printXZ()

       {

              System.out.println(super.c);

              System.out.println(super.k);

              super.mj();

       }

}

class ClsTest

{

       public static void main(String args[])

       {            

              ClsJX yx=new ClsJX();

              yx.printXZ();             

       }

}

 

对于上面的例子进行思考:

问题一:如果在子类中,将父类中的mj( )方法重写了,那么,这个时候,使用super.mj( )调用的是子类的还是父类的???

问题二:可不可以使用super去调用父类的构造方法???

 

5)、当父类中有方法是被final修饰的话,可以被继承,但是这个方法不能被重写

6)、当父类中有方法是被static修饰的话,则这个方法被子类重写时也要加上static

7)、当一个类被声明为final类,则这个类不能被继承,并且,这个类中所有的属性和方法都是final的。

 

 

class ClsFLJX  //父类

{

      

       public ClsFLJX(int a)

       {

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

       }

}

class ClsZLZFX extends ClsFLJX  //子类继随父类

{

       public ClsZLZFX()

       {

              super(3);  //使用super关键字显示的调用父类的带参数的构造方法,这一句只能写在子类构造方法的第一行

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

       }     

}

class ClsTest

{

       public static void main(String args[])

       {

             

              ClsZLZFX zfx=new ClsZLZFX();

             

       }

}

 

 

 

4、  多态

多态主要表现在方法上,以两种形式表示出来,一种是方法重写,一种是方法重载

 

A、重写

方法的重写,我们在讲前面的继承时就使用过了。我们可能会提出一个问题,既然我们使用继承就是为了达到代码的重用,那为什么要使用重写???这不就违背了代码重用吗???那么,我们子类重写父类中的方法,要遵循一个原则,就是当父类中的某一个方法是不适合子类使用的。那么,我们就要在子类中将父类的这个方法进行重写;(出现在子类中,)

 

例如:有一个形状类,在这个类中,我们有两个方法,一个是求形状面积的方法(公式:长*宽),一个是求形状体积的方法。现在有一个三角形类继承了,这个形状类,然后继承后发现形状类中的求面积的方法,并不适合三角形类使用,那么,我就会有两种解决方案,

 

第一种,把父类中的求面积方法进行重写;

第二种,在三角形类中,我们去自已写一个适合三角形面积的方法。

 

 

我们现在来分析一下,上面的两种解决方案,第一种方法,对于使用三角形这个类的使用者来说,就会很容易的去使用这个求面积的方法,因为在他看来,三角形类中只有一个求面积的方法。而对于第二种方法来说,使用者会产生一个疑惑,因为在三角形类中会有两个求面积的方法,一个是从父类继承下来的,一个是三角形类自己的,那么,到底使用者要使用那一个才是正确的呢???

 

 

所以最后我们为了能让使用者一眼就能清楚的知道要使用那一个求面积的方法,我们就会在三角形类中重写求面积的方法,因此最后我们会选择第一种解决方案。

 

 

B、重载

我们在第三章学习构造方法时,就接触了方法的重载,只是我们不知道那就是方法的重载。

 

方法重载的特点是,方法名相同,只是传入的参数个数和传入参数类型不同而以。

 

方法的重载一般出现在以下情形,当一个类中有多个方法,并且这些方法所实现的功能相同,只是所传递参数个数和类型不同,我们就会要使用到方法的重载。

(重载是在一个类中)

 

 

例如:现在我们要写一个类,这个类中的方法只做一件事情,就是做加法运算,

class ClsAdd

{

       public int add(int a,int b)

       {

              int c=a+b;

              return c;

       }

}

上面的解决方案,我们只能解决整数的加法运算,如果我们是两个浮点型数据相加呢???

 

class ClsAdd

{

       public int add(int a,int b)

       {

              int c=a+b;

              return c;

       }

       public float addF(float a,float b)

       {

              float d=a+b;

              return d;

       }

       public double addD(double a,double b)

       {

              double e=a+b;

              return e;

       }

}

 

上面方案,为我们解决不同类型数据进行加法运算的问题。

但有一个问题,如果在这个类中有100个做加法过算的方法,那么我们是不是要记住100个方法名呢???这样对于使用都来说就很痛苦了,必需要记住这100个方法名。

 

 

class ClsAdd

{

       public int add(int a,int b)

       {

              int c=a+b;

              return c;

       }

       public float add(float a,float b)

       {

              float d=a+b;

              return d;

       }

       public double add(double a,double b)

       {

              double e=a+b;

              return e;

       }

}

 

上面的解决方案,就一次性把前面所出现的问题都解决掉了。

 

 

 

 

(二)、理解访问修饰符

1、同一个类中,所有的都可以访问

class accessing

{

       private   int   myPrivate=90;

       int  myDefault=80;

       protected  int   myProtected=70;

       public  int  myPublic=60;

       void show()

       {

              System.out.println(aes.myPrivate);

              System.out.println(aes.myDefault);

              System.out.println(aes.myProtected);

              System.out.println(aes.myPublic);

       }

       public static void main(String args[])

       {

              accessing aes=new accessing();

              aes.show();

       }     

}

 

2、同一个包类的,除private不可访问以外,其它都可以访问

class test

{

       private int myPrivate=90;

       int myDefault=80;

       protected int myProtected=70;

       public int myPublic=60;   

}

class accessing

{     

       void show()

       {

              test t=new test();

              System.out.println(t.myPrivate);

              System.out.println(t.myDefault);

              System.out.println(t.myProtected);

              System.out.println(t.myPublic);

       }

       public static void main(String args[])

       {

              accessing aes=new accessing();

              aes.show();

       }     

}

 

3、不同包内的子类:只有 protectedpublic可以访问

 

package myPackage;

public class test

{

       private int myPrivate=90;

       int myDefault=80;

       protected int myProtected=70;

       public int myPublic=60;   

}

 

import myPackage.*;

class accessing extends test

{     

       void show()

       {

              //System.out.println(myPrivate);

              //System.out.println(myDefault);

              System.out.println(myProtected);

              System.out.println(myPublic);      

       }

       public static void main(String args[])

       {

              accessing aes=new accessing();

              aes.show();

       }     

}

 

4、不同包并且不是子类:只有public可以访问

package myPackage;

public class test

{

       private int myPrivate=90;

       int myDefault=80;

       protected int myProtected=70;

       public int myPublic=60;   

}

 

import myPackage.*;

class accessing

{     

       void show()

       {

              test t=new test();

       //     System.out.println(t.myPrivate);

       //     System.out.println(t.myDefault);

       //     System.out.println(t.myProtected);

              System.out.println(t.myPublic);    

       }

       public static void main(String args[])

       {

              accessing aes=new accessing();

              aes.show();

       }     

}

 

 

(三)、理解抽象类和接口

1、抽象类

例如:现在有一个职员类的父类,

abstract class ClsEmploee

{

        String name;

        float jbgz;

        float jiangjin;

        int xiujia;

        double zgz;

       //用来初始化变量

       public ClsEmploee(String n,float jg,float j,int day)

       {

              name=n;

              jbgz=jg;

              jiangjin=j;

              xiujia=day;

       }

       //这是一个抽象方法,由子类去重写;用来计算职员的工资

       abstract void getGZ();

      

       //这是一个打印方法

       public void printGZ()

       {

              System.out.println(name+"总工资为:"+zgz);

       }

}

//教师继承职员类

class ClsJY extends ClsEmploee

{

       private float ksgz;

       public ClsJY(String n,float jg,float j,int day,float ks)

       {

              super(n,jg,j,day);

              ksgz=ks;

       }

       public void getGZ()

       {

              zgz=jbgz+jiangjin+ksgz-(jbgz/30)*xiujia;

       }

}

 

//测试类

class ClsTest

{

       public static void main(String args[])

       {

              ClsJY jy=new ClsJY("ABC",12f,21f,1,12);

              jy.getGZ();

              jy.printGZ();       

       }

}

 

从上面的例子我们可以看到,对于不同的职员,算工资的标准也就不一样,所以,我们会把父类中的计算工资的方法写成抽象的,让子类去重写这个方法。

由此我们也就得到了抽象类的目的:提供可由其子类共享的一般形式

 

注意:

a、一个类中有抽象方法,那么该类一定是一个抽象类;

b、一个抽象类中可以没有抽象方法;

c、一个抽象类中可以有抽象方法,也可以有非抽象方法;

d、一个抽象类中也可以有构造方法;

e、一个类去继承一个抽象类则应该要将抽象类中所有抽象方法进行重写

f、一个抽象类A继承了抽象类B,当类C继承抽象类A时,则应重写这

抽象类A和抽象类B中所有的抽象方法。

g、一个抽象类A继承了抽象类B,并且抽象类A重写了抽象类B中的抽象方法,那么当类C继承抽象类A时,则应重写这抽象类A中的抽象方法。

h、抽象类不能实例化

 

2、接口

我们在前面讲了这个青蛙的例子,我们现在把这个例子使用JAVA来完成,看看会有什么后果。

例如:青蛙类可以继承水生动物类也可以继承陆地动物类,因为青蛙既是水生动物也是陆地动物;狗类就只能继承陆地动物,因为狗只具备陆地动物的特点,不具备水生动物的特点,所以,我们不让狗类去继承水生动物类。

class ClsSSDW  //这是一个水生动物类

{

       public void myPrintSS(String nameSS)

       {

              System.out.println(name+"卵生");

       }

}

class ClsLDDW  //这是一个陆地动物类

{     

       public void myPrintLD(String nameLD)

       {

              System.out.println(nameLD+"有腿");

       }

}

 

现在问题来了,如果我写一个青蛙类,而这个青蛙类既是水生类动物,又是陆地动物,那么,如何能让一个类去继承两个类呢????

 

 

第一种解决方案:让陆地动物去继承水生动物类,再让青蛙去继承随陆地动物类。但是这样做的话,就违背了我们所说的达到继承,父类和子类要有关联。

继承只能是单一继承,那用我们前面学过的内容就没有办法让青蛙类去同时继承这两个父类。

所以JAVA提出了这么一个概念就是“接口”,它就可以解决单一继承的问题。

接口:就是某个事物对外提供的一些功能声明,

public interface ClsSSDW  //这是一个水生动物接口

{

       public void myPrintSS(String nameSS);     

}

public interface ClsLDDW  //这是一个陆地动物类接口

{     

       public void myPrintLD(String nameLD);

}

 

class ClsQW implements ClsSSDW,ClsLDDW  //一个类可以实现多个接口

{

       public void myPrintSS(String nameSS);

       {

              System.out.println(name+"卵生");

       }

       public void myPrintLD(String nameLD);

       {

              System.out.println(nameLD+"有腿");

       }

}

注意:

1、接口中只能有方法的声明,不能有方法的主体

2、当一个类去实现接口时,则方法前面必须加上public关键字

3、接口中定义的方法不管有没有public关键字,都是一个公开的方法,

4、当一个类实现多个接口时,接口名之间用“,”隔开,并且要实现所有接口中的方法

5、接口与接口也可以继承,使用extends关键字来继承

6、接口不能实例化

 

(四)、static关键字和final关键字

1static用于修饰方法、变量、块

 

A、              在类的方法和属性前加上static关键字,则不需要通过对象就可以访问到这些方法和属性,直接通过类名可以访问

B、              也可以用于一段不属于方法的代码块

C、              静态变量实质上就是全局变量,不管创建多少实例,共用一个static变量

D、              类的静态方法只能调用其他的静态成员。并且只能访问静态变量,并且,静态成员没有this关键字

 

2final用于修饰类,方法,变量

A final类不能被继承:只要类被声明为final的,那么这个类中所有的成员都是final

B、一个非final类的final方法可以被继承,但不能被覆盖

Cfinal变量:实质上就是一个常量

原创粉丝点击