Java面向对象程序设计——第五章继承与接口

1子类与父类{

(1)类可以有两种重要的成员:成员变量和方法

——1:子类中的成员变量或方法有一部分是自己声明的

——2:还有一部分是从他的父类继承过来的

(2)什么叫继承?

——1子类继承父类的成员变量就相当于从子类中直接声明过一样,可以被子类中自己定义过的任何实例方法操作。

——2子类继承父类中的方法,就相当于直接在子类中定义了一个方法。

(3)子类和父类在同一个包中的继承性

——1可以继承父类中不是private的成员变量作为自己的变量。

——2也可以继承父类中不是private的方法作为自己的方法。

(4)子类与父类不在不在一个包中的继承性

——1子类可以继承父类protected和public的成员变量作为子类的成员变量。

——2子类可以继承父类protected和public的方法作为子类的成员方法。

*即privated和友好型的成员变量和方法无法继承。

父类:

package england.people;
public class Father { 
    private int money;
    protected int height;
    int weight;
}
//父类的成员变量有money,height,weight.

子类

package american.people;
import england.people.Father;
public class Son extends Father { 
    public String hand;
    public String getHand() {
        return hand;
    } 
} 
//子类的成员变量:height(继承的),hand.
//子类的方法:getHand。

“孙子类“(为了方便理解):

package japan.people;
import american.people.Son;
public class Grandson extends Son {
    public String foot ;
}
//子类的成员变量:height(继承的),hand(继承),foot。
//子类的方法:getHand(继承)

主类:

package england.people;
import american.people.Son;
import japan.people.Grandson;
public class Example5_1 {
    public static void main(String args[]) {
        Son son=new Son();
        Grandson grandson=new Grandson();
        son.height = 180;
        son.hand = "一双大手"; 
        grandson.height = 155;
        grandson.hand = "一双小手";
        grandson.foot ="一双小脚";
        String str = son.getHand();
        System.out.printf("儿子:%s,%d\n",str,son.height);
        str = grandson.getHand();
        System.out.printf("孙子:%s,%s,%d\n",str,grandson.foot,grandson.height); 
    }
}

输出:

儿子:一双大手,180
孙子:一双小手,一双小脚,155

}

2子类对象的构造过程{

(1)构造过程:

用子类的构造方法创建一个子类的对象时,子类的构造方法总是先调用父类的某个构造方法,也就是说,如果子类的构造方法没有明显的指出使用父类哪个构造方法,子类就调用父类那个不带参数的构造方法(再super关键字中还会细讲,即不调用super时会自动默认的调用父类无参方法)

(2)子类对象的特点g

*在用子类去创建对象时,不仅将子类声明的成员变量分配了内存,还为父类中的成员变量都分配了内存(无论继没继承,都分配了内存),但只将子类继承的那部分分配给了子类对象的变量

*重点    子类中还有一部分的方法是从父类继承过来的,

              这部分的方法可以去操作那部分分配了内存但是没有继承的父类的成员变量。

public class A {
    private int x;
    public void setX(int x) {
       this.x=x;
    } 
    public int getX() {
       return x;
    }
}
public class B extends A {
     double y=12;
     public void setY(int y)
     {   //this.y=y+x; 非法,子类没有继承x
     }
     public double getY() {
        return y;
     }
}
public class Example5_2 {
  public static void main(String args[]) {
      B b=new B();
      b.setX(888);
      System.out.println("子类对象未继承的x的值是:"+b.getX());
      b.y=12.678;
      System.out.println("子类对象的实例变量y的值是:"+b.getY());
  }  
}

 附:用子类创建的对象虽然无法直接去访问未继承的的成员变量X,但是可以通过继承来的方法去访问X。

} 3.成员变量的隐藏和方法重写{

(1)成员变量的隐藏

——1对于子类可以从父类继承成员变量,只要子类声明的成员变量和父类中的成员变量同名时,

子类就隐藏了从父类继承的成员变量。也就是说子类对象以及子类自己声明的定义的方法操作再操作与父类同名的这个成员变量是指的子类重新定义的成员变量,而不是从父类继承过来的成员变量。

注意:子类对象可以调用从父类继承的成员方法来操作隐藏的成员变量。

class People {
    public double x;
    public void setX(double x) {
       this.x=x;
    }
    public double getDoubleX() {
       return x;
    }
}
class Student extends People {
    int x;
    public int getX() {
       return x;
    }
}
public class Example5_3 {
  public static void main(String args[]) {
      Student stu=new Student();
      stu.x=98; //合法,子类对象的x是int型
      System.out.println("对象stu的x的值是:"+stu.getX());
      //stu.x=98.98; //非法,因为子类对象的x已经不是int型
      stu.setX(98.98); //子类对象调用继承的方法操作隐藏的double型变量x
      double m=stu.getDoubleX();//子类对象调用继承的方法操作隐藏的double型变量x
      System.out.println("对象stu隐藏的x的值是:"+m);
  }  
}

(2)方法重写:
子类通过重写可以隐藏已经继承的实例方法(方法重写也叫作方法覆盖)

——1重写是指的:子类中定义一个方法,这个方法的类型和父类的方法类型一致或者是父类方法的类型的子类型;并且这个类型的名字,参数个数,参数的类型完全相同。(所谓的子类型指的是如果父类的方法是“类”,那么允许子类重写方法的类型是“子类”)。

子类这样定义的方法称为子类重写的方法(不属于新增的方法)

*重写的方法可以操作继承的成员变量也可以操作子类新声明的的成员变量(与新增的实例方法一样)

*重写父类的方法时不可以降低访问权限

class A {
    double f(float x,float y) {
       return x+y;
    }
    public int g(int x,int y) {
       return x+y;
    }
}
class B extends A {
    double f(float x,float y) {//父类方法类型是友好型,则重写类型必须要为public或者
       return x*y;            //provated或者一样为友好型,不能为private型
    }  
}
public class Example5_4 {
    public static void main(String args[]) {
      B b=new B();
      double result=b.f(5,6);        //b调用重写的方法
      System.out.println("调用重写方法得到的结果:"+result);   
      int m=b.g(3,5);        //b调用继承的方法
      System.out.println("调用继承方法得到的结果:"+m);  
    } 
}  

*这个方法的类型是父类方法的类型的子类型

public class People {
    public void speak(){
       System.out.println("我是People");
    }
}

public class Chinese extends People {
   public void speak(){
       System.out.println("我是中国人");
    }
}
class CreatPeople {
    public People creatPeople() { //方法的类型是People类
        People p=new People();
        return p;               
    }
}
class CreatChinese extends CreatPeople {
    public Chinese creatPeople() {     * //重写方法的类型是People类的子类:Chinese
        Chinese chinese=new Chinese();
        return chinese;               
    }
}
public class Example5_5 {
    public static void main(String args[]) {
      CreatChinese create=new CreatChinese();
      Chinese zhang=create.creatPeople();   //create调用重写的方法
      zhang.speak();   
    } 
}  

}

4:super关键字{

(1)使用super调用父类的构造方法

                *子类不继承父类的构造方法

                *子类如果想使用父类的构造方法,就必须要在子类的的构造方法中使用,并且使用关键字super来表示,而且super必须是子类构造方法中第一条语句,如果子类构造方法中省略了super,那么默认有super()去调用父类中没有参数的构造方法,父类中没有构造方法,则必须添加一个无参的构造方法在父类中否则会报错。(无法将类 Student中的构造器 Student应用到给定类型;)

public class Student {
    int number;
    String name;
    Student() {
    }
    Student(int number,String name) {
       this.number=number;
       this.name=name;
    }
    public int getNumber() {
       return number;
    }
    public String getName() {
       return name;
    }
 }
public class UniverStudent extends Student {
   boolean isMarriage; //子类新增的结婚属性
   UniverStudent(int number,String name,boolean b) {
      super(number,name);
   }
   public boolean getIsMarriage(){
      return isMarriage;
   }
}

public class Example5_6 {
   public static void main(String args[]) {
       UniverStudent zhang=new UniverStudent(20111,"张三",false);
       int number=zhang.getNumber();
       String name=zhang.getName();
       boolean marriage=zhang.getIsMarriage();
       System.out.println(name+"的学号是:"+number);
       if(marriage==true) {
         System.out.println(name+"已婚");
       }
       else{
         System.out.println(name+"未婚");
       }
   }
}

(2)使用super去操作被隐藏的成员变量和方法

子类中想使用被隐藏的成员变量或实例方法就可以使用关键字super。

比如super.x  ,super.play()  ,去访问和调用子类隐藏的实例变量和方法。

在用super调用隐藏的方法时该方法中出现的成员变量是指被隐藏的成员变量

源代码:

class Sum {
    int n;
    public double f() {
        double sum=0;
        for(int i=1;i<=n;i++){
            sum=sum+i;
        }
        return sum;
    }
}
 class Average extends Sum {
    double n;           //子类继承的int型变量n被隐藏
    public double f() {
        double c;
        super.n=(int)n; //子类double型变量n进行int转换运算的结果赋值给隐藏的int型变量n
        c=super.f();
        return c+n;
    }
    public double g() {
        double c;
        c=super.f();
        return c-n;
    }
}
public class Example5_7 {
    public static void main(String args[]) {
        Average aver=new Average();
        aver.n=100.5678;
        double result1=aver.f();
        double result2=aver.g();
        System.out.println("result1="+result1);
        System.out.println("result2="+result2);
    }
}

 输出样例:

D:\jdk-11.0.14\bin\java.exe "-javaagent:D:\Yingyong\IntelliJ IDEA Community Edition 2021.3.3\lib\idea_rt.jar=55318:D:\Yingyong\IntelliJ IDEA Community Edition 2021.3.3\bin" -Dfile.encoding=UTF-8 -classpath C:\Users\qq\IdeaProjects\untitled\out\production\untitled Example5_7
result1=5150.5678
result2=4949.4322

进程已结束,退出代码0

 }

 5 final关键字{

final关键字可以修饰类,方法,成员变量和方法中的局部变量

*可以理解为final为最后,被修饰的东西,就是不能再改变。

(1)final 类     可以使用final将类声明为final类,即不能有子类。

(2)final方法        如果用final修饰一个父类的方法那么这个方法不允许被重写,也就是手不允许子类隐藏可以继承的final方法

(3)final常量        如果成员变量或局部变量被修饰成了final的,则成为了常量

                常量在声明时是没有默认值的,所以在声明常量时必须指定该常量的值,而且不能再发生变化,如果不声明其变量值则会报错。

class A {
//final double PI;  非法,因为没有给常量指定值
  final double PI=3.1415926;// PI是常量
  public double getArea(final double r) {
     // r=89; 非法,因为不允许再改变r的值
     return PI*r*r;
  }
  public final void speak() {
     System.out.println("您好,How's everything here ?");
  } 
}
class B extends A {
/* 非法,不能重写speak方法
  public void speak() {
      System.out.println("你好");
  } 
  */
}
public class Example5_8 {
  public static void main(String args[]) {
      B b=new B();
      System.out.println("面积:"+b.getArea(100));
      b.speak();       //调用继承的方法
   }
}

}

6.对象的上转型对象{

格式:

Animal a;

Tiger b=new Tiger();

a=b;

称为a是b的上转型对象。

(1)上转型对象不能操作子类新增的成员变量(失掉了这部分属性);

        不能用于子类新增的方法(失掉了一些行为);

       * 上转型对象可以访问子类继承或隐藏的成员变量;

注:当父类成员变量被隐藏时,上转型对象访问的是被隐藏的成员变量而不是新增的。

        *也可以去访问子类继承的或重写的实例方法

总的一句话来说:上转型对象可以去调用访问继承的,或者隐藏的,重写的。

                                                但是不可以访问新增的。

class Anthropoid {
   double m=12.58;
   void crySpeak(String s) {
      System.out.println(s); 
   }  
}
class People extends Anthropoid {
   char m='A';
   int n=60;
   void computer(int a,int b) {
      int c=a+b;
      System.out.println(a+"加"+b+"等于"+c); 
   }
   void crySpeak(String s) {
      System.out.println(m+"**"+s+"**"+m); 
   }  
}
public class Example5_9 {
   public static void main(String args[]) {
      People  people=new People(); 
      Anthropoid monkey=people;               //monkey是people对象的上转型对象。
      monkey.crySpeak("I love this game");    //等同于people调用重写的crySpeak方法
      //monkey.n=100;                         //非法,因为n是子类新增的成员变量
      //monkey.computer(12,19);               //非法,因为computer()是子类新增的方法
       System.out.println(monkey.m) ;         //操作隐藏的m,不等同于people.m
       System.out.println(people.m) ;         //操作隐藏的m,不等同于people.m
       People zhang=(People)monkey;           //把上转型对象强制转化为子类的对象
       zhang.computer(55,33);                 //zhang是子类的对象
       zhang.m='T';                           //操作子类声明的成员的变量m
       System.out.println(zhang.m) ; 
    }
}

}

7.继承与多态

{

(1)一个类有很多子类时,这些子类都重写了父类的某个实例方法

多:子类

态:重写

(2)那么我们把子类创建的对象的引用放到一个父类的对象时我们就得到了一个上转型对象

(3)那么这个上转型对象在调用这个方法时可能具有多种形态。

        因为不同的子类在重写父类时可能产生不同的行为。

*多态性指的是父类的某个方法被其子类重写时,可以各自产生自己的功能行为。

class  动物 {
   void cry() {
     
   }
}
class 狗 extends 动物 {
   void cry() {
      System.out.println("这是狗的叫声:汪汪...汪汪"); 
   }  
}
class 猫 extends 动物 {
   void cry() {
      System.out.println("这是猫的叫声:喵喵...喵喵..."); 
   }  
}
public class Example5_10 {
   public static void main(String args[]) { 
      动物 animal=new 狗();   //animal是狗的上转型对象
      animal.cry(); 
      animal=new 猫();        //animal是狗的上转型对象
      animal.cry();
   }
}

}

8.abstract类和abstract方法(用处可以理解为用抽象类声明一个变量后,可以不断的用这个变量定义为多个子类的上转型变量,去调用它们的方法)

{

(1)使用abstract修饰的类叫做abstract类(抽象类)

如; abstract class A{

.........

}

(2)用关键字abstract修饰的方法称为abstract类对于abstract方法,只允许声明,不允许实现,而且不允许使用final和abstract同时修饰一个方法或类。

(3)abstract类的特点

*abstract类中可以有abstract方法

*abstract类不能用new运算符去创建对象

*abstract类的子类

——一个非abstract类时abstract类的子类,他就必须要重写父类的abstract方法,即去掉abstract方法的abstract修饰,并给出方法体

——如果一个abstract类是abstract类的子类,那么他可以重写父类的abstract方法,也可以继承父类abstract方法

*abstract类的对象做上转型对象

abstract class GirlFriend {  //抽象类,封装了两个行为标准
   abstract void speak();
   abstract void cooking();
}
class ChinaGirlFriend extends GirlFriend {
   void speak(){
      System.out.println("你好");
   }
   void cooking(){
      System.out.println("水煮鱼"); 
   }
}
class AmericanGirlFriend extends GirlFriend {
   void speak(){
      System.out.println("hello");
   }
   void cooking(){
      System.out.println("roast beef"); 
   }
}
class Boy {
   GirlFriend friend;
   void setGirlfriend(GirlFriend f){
       friend = f;
   }
   void showGirlFriend() {
      friend.speak();
      friend.cooking();
   }
}
public class Example5_11 {
   public static void main(String args[]) {
      GirlFriend girl = new ChinaGirlFriend(); //girl是上转型对象
      Boy boy = new Boy();
      boy.setGirlfriend(girl);
      boy.showGirlFriend();     
      girl = new AmericanGirlFriend(); //girl是上转型对象
      boy.setGirlfriend(girl);
      boy.showGirlFriend();      
   }
}

例子

abstract class 机动车 {
   abstract void 启动();
   abstract void 加速();
   abstract void 刹车();
}
class 手动档轿车 extends 机动车 {
   void 启动() {
      System.out.println("踏下离合器,换到一挡");
      System.out.println("然后慢慢抬起离合器");
   }
   void 加速() {
      System.out.println("踩油门");
   }
   void 刹车() {
      System.out.println("踏下离合器,踏下刹车板");
      System.out.println("然后将挡位换到一挡");
   }
}
class 自动档轿车 extends 机动车 { 
   void 启动() {
      System.out.println("使用前进挡");
      System.out.println("然后轻踩油门");
   }
   void 加速() {
      System.out.println("踩油门");
   }
   void 刹车() {
      System.out.println("踏下刹车板");
   }
}
public class Example5_12 {
   public static void main(String args[]) {
      机动车 car=new 手动档轿车();
      System.out.println("手动档轿车的操作:");
      car.启动();
      car.加速();
      car.刹车();
      car=new 自动档轿车();
      System.out.println("自动档轿车轿车的操作:");
      car.启动();
      car.加速();
      car.刹车();
   }
}

}
 

9.instanceof是Java语言中的一个二元运算符,它的作用是:判断一个引用类型变量所指向的对象是否是一个类(或接口、抽象类、父类)的实例,即它左边的对象是否是它右边的类的实例,该运算符返回boolean类型的数据。

public class Test_instanceof {
    public static void main(String[] args) {
        String s = "Hello";
        int[] a = {1, 2};
        if (s instanceof String) {
            System.out.println("true");
        }
        if (s instanceof Object) {
            System.out.println("true");
        }
        if (a instanceof int[]) {
            System.out.println("true");
        }
    }
}

 10:继承

java不支持多继承性,一个类只能有一个父类,为了克服这样的缺点,java就是用了接口。

——1:接口的定义与使用(注意接口里面没有变量,接口中有如果不修饰方法为default方法,那么他会被默认为abstract方法,default方法修饰实例方法,stactic修饰静态类变量)

(1)接口用interface进行定义

接口中的抽象方法和常量

public interface Printable { 
    public final int MAX = 100;  //等价写法:int MAX=100;
    public abstract void on();   //等价写法:void on();
    public abstract float sum(float x ,float y);
    public default int max(int a,int b) {   //default方法
        return a>b?a:b;
    }
    public static void f() {
       System.out.println("注意是从Java SE 8开始的");
    }
}

(2)接口中的default实例方法 

在方法前使用default修饰为实例方法。

default方法实例方法的限一定是public(允许省略public修饰符)

(3)接口中static方法

允许在接口体中定义static方法。

——2:接口的使用

(1)可以使用接口名直接访问接口的常量,调用接口中的stactic方法;

例如:

Printable.Max;

Printable.f();

(2)类实现接口

类通过使用关键字implements声明自己实现一个或多个接口

class Dog extends Animal implements Eatable,Sleepable{

。。。。。。

*一个类实现了某个接口

那么这个类就拥有了这个接口中的常量,default方法(去掉了default关键词)

该类也可以重写接口中的default方法(注意重写时应该要去掉default方法)

但是不自然拥有该接口的stactic方法

*一个非abstract类,实现了某个接口,那么这个类必须重写该接口的所有abstract,即去掉abstract关键字给出方法体。

*一个abstract类实现某个接口,该类可以选择重写接口的abstract或者直接有接口中abstract方法。

需要注意的是:接口中的方法的访问权限都是public的,

重写时不可以省略public(否则就降低了权限,这是不允许的)

public interface Printable { 
    public final int MAX = 100;  //等价写法:int MAX=100;
    public abstract void on();   //等价写法:void on();
    public abstract float sum(float x ,float y);
    public default int max(int a,int b) {   //default方法
        return a>b?a:b;
    }
    public static void f() {
       System.out.println("注意是从Java SE 8开始的");
    }
}
public class AAA implements Printable {
     public void on(){    //必须重写接口的abstract方法on
         System.out.println("打开电视");
     }
     public float sum(float x ,float y){//必须重写接口的abstract方法sum
         return x+y;
     }
}

public class Example5_14 {
   public static void main(String args[]) {
      AAA a = new AAA();
      System.out.println("接口中的常量"+AAA.MAX);
      System.out.println("调用on方法(重写的):");
      a.on();
      System.out.println("调用sum方法(重写的):"+a.sum(12,18));
      System.out.println("调用接口提供的default方法"+a.max(12,78));
      Printable.f();  
   }
}   

 ——3:接口回调

   (1)指的是:可以把实现某一接口的类创建的对象的引用赋给该接口声明的接口变量中,那么该接口变量就可以调用被类重写的接口方法。

(2)当接口变量调用被类重写的接口方法是,就是通知对应的对象调用这个方法

*非常类似上转型对象调用子类的重写方法。

interface  ShowMessage {
   void 显示商标(String s);
}
class TV implements ShowMessage {
   public void 显示商标(String s) {
      System.out.println(s);
   }
}
class PC implements ShowMessage {
   public void 显示商标(String s) {
     System.out.println(s);
   }
}
public class Example5_15 {
   public static void main(String args[]) {
      ShowMessage sm;                  //声明接口变量
      sm=new TV();                     //接口变量中存放对象的引用
      sm.显示商标("长城牌电视机");      //接口回调。
      sm=new PC();                     //接口变量中存放对象的引用
      sm.显示商标("联想奔月5008PC机"); //接口回调
   } 
}

——4 理解接口

(1)接口的语法规则很容易记住,更重要的是理解,理解的关键点是

-1接口可以抽象出重要的行为标准,该行为标准用抽象方法来表示

-2可以把实现该接口的对象的引用赋值给接口变量,该接口变量可以调用被该类实现的接口方法。

(2)接口思想在于

-1他可以要求某些类有相同名称的方法,但是方法的内容可以不同,即要求这些类实现接口,来保证这些类一定有接口中所声明的方法

-2*接口要求一些类具有相同名称的方法的同时,并不强迫这些类具有相同的父类。

abstract class MotorVehicles {
   abstract void brake();
}
interface MoneyFare {
   void charge();
}
interface ControlTemperature {
   void controlAirTemperature();
}
class Bus extends MotorVehicles implements MoneyFare { 
    void brake() {
        System.out.println("公共汽车使用毂式刹车技术");
    }
    public void charge() {
        System.out.println("公共汽车:一元/张,不计算公里数");
    }
} 
class Taxi extends MotorVehicles implements MoneyFare,ControlTemperature { 
    void brake() {
        System.out.println("出租车使用盘式刹车技术");
    }
    public  void charge() {
        System.out.println("出租车:2元/公里,起价3公里");
    }
    public void  controlAirTemperature() { 
        System.out.println("出租车安装了Hair空调");
    }
}
class Cinema implements MoneyFare,ControlTemperature {
    public  void charge() {
        System.out.println("电影院:门票,十元/张");
    }
    public void controlAirTemperature() { 
       System.out.println("电影院安装了中央空调");
    }
}
public class Example5_16 {
   public static void main(String args[]) {
       Bus bus101 = new Bus();
       Taxi buleTaxi = new Taxi();
       Cinema redStarCinema = new Cinema();
       MoneyFare  fare;
       ControlTemperature temperature;
       fare = bus101;
       bus101.brake(); 
       fare.charge();
       fare = buleTaxi;
       temperature = buleTaxi;
       buleTaxi.brake();
       fare.charge();
       temperature.controlAirTemperature();
       fare = redStarCinema;
       temperature = redStarCinema;
       fare.charge();
       temperature.controlAirTemperature();
   }
}

 ——5:abstract类和接口的比较

(1)abstract类和接口都有abstract方法

(2)接口中只可以有常量,不允许有变量

   而abstract类可以有常量也可以有变量

(3)abstract类中可以有非abstract,但是不可以有default方法

       接口不可以有非abstract方法,但是可以有default实例方法。

*注意:在设计程序中应当根据具体情况来确定是使用接口还是abstract类

*如果某个问题需要使用继承才能更好地解决,比如,子类除了需要实现父类的abstract方法,还需要从父类继承一些变量或继承一些重要的非abstract方法,可以考虑abstract类。

如果某个问题不需要继承只是需要若干个类给出某些重要的abstract方法的实现细节,就可以考虑使用接口。

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值