Java 继承 抽象类 接口

JAVA继承 抽象类 接口
作者: 嗯呢
一.类的继承
      通过继承可以实现代码的复用,被继承的类称为父类或超类(superclass),由继承而得到的类称为子类(subclass)。一个父类可以拥有多个子类,但一个类只能有一个直接父类,这是因为JAVA语言中不支多重继承。

      子类继承父类的成员变量和成员方法,同时可以修改父类的成员变量或重写父类的方法,还可以添加新的成员变量或成员方法。

      JAVA语言中有一个名为java.lang.Object的特殊类,所有的类都是直接或间接地继承该类而得到的。

      1.子类的创建
           类的继承是通过extends关键字来实现的,在定义类时若使用ectends关键字指出新定义类的父类,就是在两个类之间建立了继承关系。新定义的类称为子类,它可以从父类那里继承所有非private的成员作为自己的成员。

   子类的创建:

 * 格式:  class SubClass extends SuperClass   //SubClass为子类,SuperClass为父类

 *      {

 *         .

 *         .

 *         .

 *       }

     2.调用父类中特定的构造方法
         在没有明确地指定构造方法时,子类还是会先调用父类中没有参数的构造方法,以便进行初始化的操作。在子类的构造方法中可以通过super()来调用父类特定的构造方法。

 

例://以Person作为父类,创建学生子类Student,并在子类中调用父类里某指定的构造方法。

class Person2

{

       private String name;

       private int age;

       publicPerson2()//定义Person2类的无参构造方法

       {

              System.out.println("调用了Person2类的无参构造方法");

       }

       publicPerson2(String name,int age)//定义Person2类的有参构造方法

       {

              System.out.println("调用了Person2类的有参构造方法");

              this.name=name;

              this.age=age;

       }

       publicvoid show()

       {

              System.out.println("姓名:"+name+"  年龄:"+age);

       }

}

class Student2extends Person2//定义继承自Person2类的子类Student2

{

       privateString department;

       publicStudent2()//定义Student2类的无参构造方法

       {

              System.out.println("调用了学生类的无参构造方法Student2()");

       }

       publicStudent2(String name,int age,String dep)//定义Student2类的有参构造方法

       {

              super(name,age);//调用父类的无参构造方法

              department=dep;

              System.out.println("我是"+department+"学生");

              System.out.println("调用了学生类的有参构造方法Student2(Stringname,int age,String dep)");

       }

}

public class App8_2 {

       publicstatic void main(String[] args)

       {

              Student2stu1=new Student2();//创建对象,并调用无参构造方法

              Student2stu2=new Student2("李小四",23,"信息系");//创建对象并调用有参构造方法

              stu1.show();

              stu2.show();

       }

}

 

/*在子类中访问你类的构造方法,其格式为super(参数列表)。

 * super()可以重载,也就是说,super()会根据参数的个数与类型,执行父类相应的构造方法。

 * 调用父类构造方法的super()语句必须写在子类构造方法的第一行。

 *super()与this()的功能相似,但super()是从子类的构造方法调用父类的构造方法, 而this()则是在同一个类内调用其他的构造方法。

 *super()与this()均必须放在构造方法内的第一行,也就是这个原因,super()与this()无法同时存在同一个构造方法内。

 * 与this关键字一样,super指的也是对象,所以super同样不能在static环境中使用,包括静态方法和静态初始化器(static语句块)。

 

      3.在子类中访问父类的成员
         例://在学生子类Student中访问父类Person的成员。用protected修饰符和super关键字访问父类的成员

class Person3

{

       protectedString name;//用protected(保护成员)修饰符修饰

       protectedint age;

       publicPerson3()//定义Person3类的“不做事”的无参构造方法

       {

             

       }

       publicPerson3(String name,int age)//定义Person3类的有参构造方法

       {

              this.name=name;

              this.age=age;

       }

       protectedvoid show()

       {

              System.out.println("姓名:"+name+"   年龄:"+age);

       }

}

class Student3 extends Person3//定义子类Student3,其父类为Person3

{

       privateString department;

       intage=20;//新添加了一个与父类的成员变量age同名的成员变量


       publicStudent3(String xm,String dep)//定义Student3类的有参构造方法

       {

              name=xm;   //在子类里直接访问父类的protected成员name

              department=dep;

              super.age=25;   //利用super关键字将父类的成员变量age赋值为25

              System.out.println("子类Student3中的成员变量age="+age);

              super.show();       //去掉super而只写show()亦可,这是调用父类中的成员方法

              System.out.println("系别:"+department);

       }

}

public class App8_3 {

       publicstatic void main(String[] args)

       {

              @SuppressWarnings("unused")

              Student3stu=new Student3("李小四","信息系");

       }

}

 

/*在子类中访问父类的成员:

 * 在子类中使用super不但可以访问父类的构造方法,还可以访问父类成员就是和成员方法,

 * 但super不能访问在子类中添加的成员。子类中访问父类成员的格式如下:

 * 1.  super.变量名;     2.super.方法名;

 * 用protected修饰的成员可以被三种类所引用:该类自身、与它在同一个包中的其他类、在其他包中该的子类。

 * 将成员声明为protected的最大好处是可以同时兼顾到成员的安全性和便利性。

     4.覆盖
       重载是指在同一个类内定义名称相同,但参数个数或类型不同的方法。

       覆盖(overriding):是指在子类中,定义名称,参数个数与类型均与父类完全相同的方法,用于重写父类里同名方法的功能。

       

例://以个人类Person为父类,创建学生子类Student,并用子类中的方法覆盖父类的方法。

class Person4

{

       protectedString name;

       protectedint age;

       publicPerson4(String name,int age)

       {

              this.name= name;

              this.age= age;

       }

       protectedvoid show()

       {

              System.out.println("姓名:"+name+"  年龄:"+age);

       }

}

class Student4 extendsPerson4

{

       privateString department;

       publicStudent4(String name,int age,String dep)

       {

              super(name,age);

              department= dep;

       }

       protectedvoid show()//覆盖父类Person4中的同名方法

       {

              System.out.println("系别:"+department);

       }

}

public class App8_4

{

       publicstatic void main(String[] args)

       {

              Student4stu = new Student4("王永涛",24,"电子");

              stu.show();

       }

}

 

 *覆盖父类的方法:子类在重新定义父类已有的方法时,应保持与父类完全相同的方法声明,即应与父类有完全相同的方法名、返回值类型和参数列表,否则就不是方法的覆盖,而是子类定义自己的与父类无关的方法,父类的方法末被覆盖,所以仍然存在。

 *注意: 子类中不能覆盖父类中声明为final或static的方法。   在子类中覆盖父类的方法时,可以扩大父类中方法权限,但不可以缩小父类方法的权限。

     5.用父类的对象访问子类的成员
例://利用父类Person5的对象调用子类Student5中的成员。与不可被继承的成员与最终类

class Person5

{

       protected String name;//如果声明为静态最终变量,则不能被覆盖。

       protected int age;

       publicPerson5(String name, int age)

       {

              this.name= name;

              this.age= age;

       }

       protectedvoid show()

       {

              System.out.println("姓名:"+name+"  年龄:"+age);

       }

}

class Student5extends Person5

{

       privateString department;

       publicStudent5(String name,int age, String dep)

       {

              super(name,age);

              department= dep;

       }

       protectedvoid show()

       {

              System.out.println("系别:"+department);

       }

}

public class App8_5

{

       publicstatic void main(String[] args)

       {

              Person5per = new Student5("王永涛",24,"电子");//声明父类变量per指向子类对象

              per.show();    //利用父类对象per调用show()方法

       }

}

 

通过父类的对象访问子类的成员,只限于“覆盖”的情况发生时。

    6.不可被继承的成员与最终类
 * 如果父类的成员不希望被子类的成员所覆盖,可以将它们声明为final。

 *

 * 如果就final来修饰成员变量,则说明该成员变量是最终变量,即常量,程序中的其他部分可以访问,但不能修改。

 * 如果用final修饰成员方法,则该成员方法不能被子类所覆盖,即该方法是最终方法。

 *

 * 所以已被private修饰符限定为私有的方法,以及所有包含在final类中的方法,都被默认是final的。

 *

 *final成员变量与final局部变量的区别:final成员变量和定义在方法中的final局部变量,它们一旦给定,就不能更改。

 * 大体上说,final成员变量和final局部变量都是只读量,它们能且只能被赋值一次,而不能赋值多次。

 *

 * 一个成员变量若被staticfinal两个修饰符所限定时,它实际的含义,就是常量,所以在程序中通常用static和final一起来指定一个常量。

 *

 * 定义一个成员变量时,若只用final修饰而不用static修饰,则必须且只能赋值一次,不能缺省。这种成员变量的赋值方式有两种:

 * 一种是在定义变量时赋初值;另一种是在某个构造方法中进行赋值。

二.Object类
      1.equals()方法
  equals()方法:判断两个对象是否相等。

 equals()方法与==运算符比较方式的一同:“==”运算符用于比较两个变量本身的值,即两个对象在内存中的首地址,而equals()方法则是比较两个字符串中所包含的内容是否相同;而对于非字符串类型的变量来说,“==”运算符和equals()方法都用来比较其所指对象在堆内存中的首地址。换句话说,“==运算符和equals()方法都是用来比较两个类类型的变量是否指向同一个对象。”

     2.toString()方法与getClass()方法
       toString()方法:toString()方法的功能是将调用该方法的对象的内容转换成字符串,并返回其内容,但返回的是一些没有意义且看不懂的字符串。

 * 因此,如果要用toString()方法返回对象的内容,可以重新定义该方法用于覆盖父类中的同名方法以满足需要。

 *

 *getClass()方法:该方法的功能是返回运行该方法的对象所属的类。getClass()方法返回值是Class类型。

      3.对象运算符instanceof
    对象运算符instanceof:判断一个指定对象是否是指定类或它的子类的实例,若是,则返回true,否则返回false。

 getName()方法返回一个类的名称,返回值是String类型。

 getSuperclass()方法获得父类。

 

 例://运算符instanceof及getName()、getSuperclass()方法的使用。

 public class Person8

{

       staticint count = 0;

       protectedString name;

       protectedint age;

       @SuppressWarnings("static-access")

       publicPerson8(String n1,int a1)

       {

              name= n1;

              age= a1;

              this.count++;

       }

       publicString toString()

       {

              returnthis.name+" , "+this.age;

       }

       @SuppressWarnings("static-access")

       publicvoid display()

       {

              System.out.println("本类名="+this.getClass().getName()+";");

              System.out.println("父类名="+this.getClass().getSuperclass().getName());

              System.out.println("Person.count="+this.count+"");

              System.out.println("Student.count="+Student8.count+"");

              Objectobj=this;

              if(objinstanceof Student8)

                     System.out.println(obj.toString()+"是Student类对象。");

              else

                     if(objinstanceof Person8)

                            System.out.println(obj.toString()+"是Person类对象");

       }

}

class Student8 extends Person8

{

       staticint count = 0;

       protectedString dept;

       @SuppressWarnings("static-access")

       protectedStudent8(String n1,int a1,String d1)

       {

              super(n1,a1);

              dept= d1;

              this.count++;

       }

       publicString toString()

       {

              returnsuper.toString()+","+dept;

       }

       @SuppressWarnings("static-access")

       publicvoid display()

       {

              super.display();

              System.out.print("super.count="+super.count);

              System.out.println(";this.count="+this.count);

       }

       publicstatic void main(String[] args)

       {

              Person8per = new Person8("王永涛",23);

              per.display();

              Student8stu = new Student8("张小三",22,"计算机系");

              stu.display();

       }

}

 

三.抽象类
     1.抽象类与抽象方法
    抽象类是以修饰符abstract修饰的类,定义抽象类的语法格式如下:

    abstract class 类名

   {

      声名成员变量;

      返回值的数据类型方法名(参数表)  ——————一般方法

      {

         ……

      }

       abstract 返回值的数据类型方法名(参数表); ——————抽象方法

   }

 

 注意:

       1.由于抽象类是需要被继承的,所以abstract类不能用final来修饰。也就说,一个类不能既是最终类,又是抽象类,即关键字abstract与final不能合用。

       2.abstract不能与private、stastic、final或native并列修饰同一方法。

       3.抽象类的子类必须实现父类中的所有方法,或者将自己也声明为抽象的。

       4.抽象类中不一定包含抽象方法,但包含抽象方法的类一定要声明为抽象类。

       5.抽象类可以有构造方法,且构造方法可以被子类的构造方法所调用,但构造方法不能被声明为抽象的。

       6.一个类被定义为抽象类,则该类就不能用new运算符创建具体实例对象,而必须通过覆盖的方式来实现抽象类中的方法。

       7.抽象方法在抽象方法里,不能定义方法体。

 

例://抽象类的应用举例。定义一个形状抽象类Shape,以该形状抽象类为父类派生出圆形子类Cricle和矩形子类Pectangle。

abstract class Shape9//定形状抽象类Shape

{

       protected String name;

       publicShape9(String xm)   //抽象类中一般方法,本方法是构造方法

       {

              name= xm;

              System.out.print("名称:"+name);

       }

       abstractpublic double getArea();//声明抽象方法,没有方法体

       abstractpublic double getLength();//声明抽象方法

}

class Cricle9extends Shape9//定义继承自Shape9的圆形子类Cricle9

{

       privatedouble pi=3.14;

       privatedouble radius;

       publicCricle9(String shapeName,double r)

       {

              super(shapeName);

              radius=r;

       }

       public double getArea()      //实现抽象类中的getArea()方法

       {

              returnpi*radius*radius;

       }

       publicdouble getLength()   //实现抽象类中的getLength()方法

       {

              return2*pi*radius;

       }

}

class Rectangle9 extends Shape9   //定义继承自Shape9的圆形子类Rectangle9

{

       privatedouble width;

       privatedouble height;

       publicRectangle9(String shapeName,double width,double height)

       {

              super(shapeName);

              this.width=width;

              this.height=height;

       }

       publicdouble getArea()

       {

              returnwidth*height;

       }

       publicdouble getLangth()

       {

              return2*(width+height);

       }

       @Override

       publicdouble getLength() {

              //TODO 自动生成方法存根

              return0;

       }

}

public class App8_9

{

       publicstatic void main(String[] args)

       {

              Shape9 rect=new Rectangle9("长方形",6.5,10.3);//声明父类对象指向子类

              System.out.print(";面积="+rect.getArea());      对象

              System.out.println(";周长="+rect.getLength());

              Shape9 circle=new Cricle9("圆",10.2);

              System.out.print(";面积="+circle.getArea());

              System.out.println(";周长="+circle.getLength());   

       }

}

四.接口
     1.接口的定义、实现与引用
接口与抽象类的不同:

 1.接口的数据成员必须初始化。

 2.接口中的方法必须全部都声明为abstract,也就是,接口不能像抽象类一样拥有一般的方法,而必须全部是抽象方法。

 * 接口定义的语法格式如下:

 *[public] interface 接口名称 [extends 父接口名列表]

 * {

 *    [public] [static] [final] 数据类型 成员变量名=常量;

 *     ……

 *    [public] [abstract] 返回值的数据类型 方法名(参数名);

 *     ……

 * }

 * 其中interface前的public修饰符可以省略。若省略,接口使用默认的访问控制,即接口只能被与它处在同一包中的成员访问。

一。 接口里的“抽象”方法只需要做声明,不用定义其处理数据的方法体。

二。 成员就是必须赋初值。

 * 接口的实现与引用:

 * 接口的实现是在声明一个类的同时用关键字implements来实现一个接口。  接口实现的语法格式为:

 *class 类名称 implements接口名表

 * {

 *    ……

 * }

  一个类要实现一个接口时,注意以下问题:

  1.如果实现某接口的类不是abstract的抽象类,则在类的定义部分必须实现指定接口的所有抽象方法。

   2.一个类在实现某接口的抽象方法时,必须使用完全相同的方法头。否则,只是在定义一个新方法,而不是实现已有的抽象方法。

   3.接口中抽象方法的访问控制修饰符都已指定为public,所以类在实现方法时,必须显示地使用public修饰符,否则将被系统警告为缩小了接口中定义的方法的访问控制范围。

     2.接口的继承与多重继承
与类相似,接口也有继承性。定义一个接口时可通过extends关键字声明该新接口是某个已存在的父接口的子接口,它将继承父接口的所有变量与方法。与类的继承不同是,一个接口可以有多个父接口,它们之间用逗号分隔,形成父接口列表。如果有子接口中有与父接口同名的常量或相同的方法,则父接口中常量被隐藏方法被覆盖。

 

例://接口继承

interface Face1

{

      double pi=3.14;

      abstractdouble area();

}

interface Face2

{

      abstractvoid setColor(String c);    //可以有参数但不能方法体

}

interface Face3 extendsFace1,Face2  //接口的多重继承,也是使用关键字

{                                extends,不同于类,一个接口可以有

      abstractvoid volume();             多个父接口,逗号分隔。

}

public class Cylinder11 implements Face3

{

      private double radius;

      private int height;

      protected String color;

      public Cylinder11(double r,int h)

      {

             radius=r;

             height=h;

      }

      public double area()    //返回值类型相同,方法名相同

      {

             returnpi*radius*radius;

      }

      public voidsetColor(String c)

      {

             color=c;

             System.out.println("黑色:"+color);

      }

      public void volume()   //返回值类型相同,方法名相同

      {

             System.out.println("圆柱体体积="+area()*height);

      }

      public static voidmain(String[] args)

      {

             Cylinder11volu=new Cylinder11(3.0,2);

             volu.setColor("红色");

             volu.volume();

      }

}

 

五.内部类与匿名类
      1.内部类
    内部类:内部类(inner class)也称“嵌套类”是定义在类中的类,内部类的主要作用是将逻辑上相关的类放到一起。包含内部类称为“外部类”,内部类与一般类相同。

注意:

    1.内部类不能与外部类同名。

    2.在外部引用内部类时,则必须在内部类名前冠以其属外部类的名字才能使用。

    3.在用new运算符创建内部类时,也要在new前面冠以对象变量。

 

说明:

    1.在文件管理方面,内部类在编译完成之后,所产生的文件名称为“外部类名$内部名类名.class”。

    2.内部类可以被声明为private或protected。因些外部类与内部类的访问原则是:在外部类中,通过一个内部类的对象引用内部类中的成员;反之,在内部类中可以直接引用它的外部类的成员,包括静态成员、实例成员及私有成员。内部类也可以通过创建对象从外部类之外被调用,但必须将内部类声明为public的。

 

 内部类具有如下特性:

1.内部类的前面用final修饰,则表明该内部类不能被继承。

2.内部类可以定义为abstract,但需要被其他的内部类继承或实现。

3.内部类不能与包含它的外部类名相同。

4.内部类也可以是一个接口,该接口必须由另一个内部类来实现。

5.内部类不但可以在类里定义,也可以在程序块之内定义内部类。

6.内部类如果被声明为static,则静态内部类将自动转化为“顶层类”(top level class),即它没有父类,而且不能引用外部类成员或其他内部类中的成员。非静态内部类不能声明静态成员,只有静态内部类才能声明静态成员。

 

例://内部类与外部类的访问规则

public class Group13

{

      private int age;//声明外部类的私有成员变量

      publicclass Student13  //声明内部类               ———————      {

             Stringname;//声明内部类的成员变量

             publicStudent13(String n,int a)//定义内部类的构造方法        内

             {

                    name=n;//访问内部类的成员变量name                  部               

                    age=a;//访问外部类的成员变量age

             }                                                      类

             publicvoid output()//内部类的成员方法 

             {

                    System.out.println("姓名:"+name+"  年龄:"+age);

             }

      }    //                                          ———————

      public void output()//定义外部类的成员方法

      {

             Student13 stu=newStudent13("刘 洋",24);     //创建内部类对象stu

             stu.output();

      }

      public static voidmain(String[] args)

      {

             Group13 g=newGroup13();               //用g调用外部类的方法

             g.output();

      }

}

 

      2.匿名内部类
匿名类(anonymousclass): 匿名类是一种特殊的内部类,它没有类名,在定义类的同时,就生成该类的一个实例,由于不会在其他地方用到该类,所以不用取名字,因而又被称为匿名内部类。

这种类不取名字,而是直接用其父类的名字或者它所实现的接口名字,而且匿名内部类的定义与创建该类的一个实例同时进行,即类的定义前面一个new运算符,而不是使用关键字class,同时带上圆括号“()”表示创建对象。

 

格式如下:

 (  //创建匿名内部类,并执行所定义的方法

    new 类名()  //括号"()"内不允许有参数

    {

      方法名(参数,,参数2,···,参数n)

      {

          方法体语句;

       }

     }

  ).方法名(参数1,参数2,···,参数n)

 

说明: 匿名内部类名前不能有修饰符,也不能定义构造方法,因为它没有名字,也正是这个原因,在创建对象时也不能带参数,因为默认构造方法不能带参数

 

例://匿名内部类的使用方法

public class App8_14

{

      public static voidmain(String[] args)

      {

             (          

               new Inner()//创建匿名内部类Inner的对象

               {

                    voidsetName(String n)

                    {

                           name=n;

                           System.out.println("姓名:"+name);//以上三句是为弥补内部

                    }                           //类Inner里没有定义到的方法

                }                    //  创建匿名内部类Inner的对象

              ).setName("张  华");     //执行匿名内部类里所定义的方法

      }

    static class Inner//定义内部类

    {

         String name;

    }

}

你可能感兴趣的:(Java 继承 抽象类 接口)