09 继承 抽象类 接口

子父类中的构造函数的特点.

在子类构造对象时,发现访问子类构造函数时,父类也运行了.

为什么呢? 原因是:在子类的构造函数中,第一行有一个默认的隐式语句.

super();

/*
    子父类中的构造函数的特点
*/
class Fu
{
    Fu()
    {
        System.out.println("fu show run");
    }
    
}

class Zi extends Fu
{
    Zi()
    {
        //super();//调用的就是父类中的空参数的构造函数
        System.out.println("zi show run");
    }
}

class Demo
{

    /*
        保证程序的独立运行
    */
    public static void main(String[] args)
    {
        new Zi();
    }

}

//构造函数带参数的
class Fu
{
    Fu(int x)
    {
        System.out.println("fu show run");
    }
    
}

class Zi extends Fu
{
    Zi()
    {
        //super();//调用的就是父类中的空参数的构造函数
        super(4);
        System.out.println("zi show run");
    }
}

子类的实例化过程:子类中所有的构造函数默认都会访问父类中的空参数的构造函数.

为什么子类实例化的时候要访问父类中的构造函数呢?
因为子类继承了父类,获取到了父类中内容(属性),所以在使用父类内容之前.
要先看父类是如何对自己的内容进行初始化的.

所以子类在构造对象时,必须访问父类中的构造函数.
为了完成这个必须的动作,就在子类的构造函数中加入了super()语句.
如果父类中没有定义空参数构造函数,那么子类的构造函数必须用super明确
要调用父类中的哪个构造函数.同时子类构造函数中如果使用了this调用了
本类构造函数时,那么super就没有了,因为super和this都只能定义在第一行,
所以只能有一个.但是可以保证的是,子类中肯定有其他的构造函数访问父类
的构造函数.

注意:super语句必须要定义在子类构造函数的第一行.因为父类的初始化动作要先完成.



show()方法在子类和父类重复时,即使父类构造函数也先从子类的方法区里找show();

class Fu
{
    Fu()
    {
        super();//继承Object
        show();
        return;
    }

    void show()
    {
        System.out.println("fu show");
    }
}

class Zi extends Fu
{
    int num = 8;
    Zi()
    {
        super();
        //通过super初始化父类内容时,子类的成员变量并未显示初始化
    //等super()父类初始化完毕后,才进行子类的成员变量显示初始化.
        return;
    }
    void show()
    {
        System.out.println("zi show..."+num);
    }
}

 



一个对象实例化过程:
Person p = new Person();
1.JVM会读取指定的路径下的Person.class文件,并加载进内存,并会先加载Person的父类(如果有直接的父类的情况下).
2.在堆内存中开辟空间,分配地址.
3.并在对象空间中,对对象中的属性进行默认初始化.
4.调用对应的构造函数进行初始化.
5.在构造函数中,第一行会先调用父类中构造函数进行初始化.
6.父类初始化完毕后,再对子类的属性进行显示初始化.
7.再进行子类构造函数的特定初始化.
8.初始化完毕后,将地址值赋值给引用变量.


final关键字:

继承弊端:打破了封装性.
1.final是一个修饰符,可以修饰类,方法,变量.
2.final修饰的类不可以被继承.
3.final修改时的方法不能被覆盖.
4.final修饰的变量是一个常量,只能赋值一次.

final int x;会报错
不能用默认初始化值,必须显式初始化.

为什么要用final修饰变量,其实在程序中如果一个数据是固定的,
那么直接使用这个数据就可以了,但是这样阅读性差,所以给该数据起一个名称,
而且这个变量名称的值不能变化,所以加上final固定.

写法规范:常量所有字母都大写,多个单词,中间用_连接.


抽象类:
抽象:笼统,模糊,看不懂,不具体.

特点:
1.方法只有声明没有实现时,该方法就是抽象方法,需要被abstract修饰
 抽象方法必须定义在抽象类中,该类必须也被abstract修饰.
2.抽象类不可以被实例化,为什么?
  因为调用抽象方法没意义,方法没有方法体,无法去调用.
3.抽象类必须有其子类覆盖了所有的抽象方法后,该子类才可以实例化,否则,
这个子类还是抽象类.

问题:
1.抽象类中有构造函数吗?
  有,用于给子类对象进行初始化.
2.抽象类可以不定义抽象方法吗?
  可以的.但是很少见,目的就是不让该类创建对象.AWT的适配器对象就是这种类.
  通常这个类中的方法有方法体,但是却没有内容.

abstract class Demo
{  
  void show1(){}
  void show2(){}
}
3.抽象关键字不可以和那些关键字共存?
  private不行, 因为抽象类中的方法需要被子类覆盖.
  static不行,
  final不行,final代表不能覆盖.
4.抽象类和一般类的异同点?
相同点:抽象类和一般类都是用来描述事物的,都在内部定义了成员.
不同点:1)一般类有足够的信息描述事物,
     抽象类描述事物的信息有可能不足.
    2)一般类中不能定义抽象方法,只能定义非抽象方法.
      抽象类中可定义抽象方法,同时也可以定义非抽象方法.
    3)一般类可以被实例化,抽象类不可以被实例化.
5.抽象类一定是个父类吗?
  是的,因为需要子类覆盖其方法后才可以对子类实例化.


雇员示例:
需求:公司中程序员有姓名,工号,薪水,工作内容.
项目经理除了有姓名,工号,薪水,还有奖金,工作内容.
对给出需求进行数据建模.

分析:在这个问题领域中,先找出涉及的对象,通过名词提炼法.
程序员:属性:姓名,工号,薪水.
    行为:工作.
经理:
  属性:姓名,工号,薪水,奖金.
  行为:工作.

程序员和经理不存在着直接继承关系.
但是程序员和经理却具有着共性的内容,可以进行抽取.因为他们都是公司的雇员.
可以将程序员和经理进行抽取,建立体系.
//描述雇员
abstract class Employee
{
    private String name;
    private String id;
    private double pay;
    Employee(String name,String id,double pay)
    {
        this.name=name;
        this.id=id;
        this.pay = pay;
    }

    public abstract void work();
}

//描述程序员
class Programmer extends Employee 
{
    Programmer(String name,String id,double pay)
    {
        super(name,id,pay);
    }
    public void work()
    {
        System.out.println("code...");
    }
}

//描述经理.
class Manager extends Employee
{
    private int bonus;
    Manager(String name,String id,double pay,int bonus)
    {
        super(name,id,pay);
        this.bonus = bonus;
    }
    public void work()
    {
        System.out.println("Manage...");
    }
}

 

当一个抽象类中的方法都是抽象的时候,这时可以将该抽象类用另一种形式来定义和表示,就是接口interface.

定义接口使用的关键字不是class,是interface.
对于接口当中常见的成员:而且这些成员都有固定的修饰符.
1.全局常量:
  public static final
2.抽象方法:
  public abstract
注:不写会帮你默认写上,即可以省略.最好自己写上,不利于阅读性.
由此得出结论,接口中的成员都是公共的权限.

接口不用继承,用实现.
为什么叫实现?
  接口里的方法全部是抽象的,必须全部实现.
继承可以有不需要做,拿来直接用的东西,实现是全部重写覆盖.
类与类之间是继承的关系,类与接口之间是实现关系.
接口不可以实例化,只能由实现了接口的子类并覆盖了接口中所有的抽象方法后,
该子类才可以实例化.否则,这个子类就是一个抽象类.
interface Dm
{
    public static final int NUM=4;
    public abstract void show1();
    public abstract void show2();
}


class DemoImpl implements /*实现*/Dm
{
    public void show1(){}
    public void show2(){}
}

在java中,不直接支持多继承,因为会出现调用的不确定性.所以java将多继承机制

进行改良,在java中变成了多实现.

一个类可以实现多个接口.

interface A
{
    public void show();
}

interface Z
{
    public void show();//abstract都被省略掉了
  public int add(int a,int b); }
class Test implements A,Z //多实现 { public void show() { }
  public int add(int a,int b )
  {
    return a+b;
  }
}

  class Q
  {
    public void method(){}
    
  }


  class Test2 extends Q implements A,Z
  {

  }

 

这样避免了多继承的不确定性.

一个类在继承另一个类的同时,还可以实现多个接口.

接口的出现避免了单继承的局限性.

接口与接口直接可以多继承,

interface CC
{
    void show();
}
interface MM
{
    void method();
}
interface QQ extends CC,MM//接口与接口直接是继承关系,而且接口
{                        //可以多继承
}
class WW implements QQ
{
  public void show(){}
  public void method(){}
  public void function(){}
}

因为接口中没有方法体,所以不会冲突,故可以多继承.

接口的特点:

1.接口是对外暴露的规则.

2.接口是程序的功能扩展.

3.接口的出现降低耦合性.

4.接口可以用来多实现.

5.类与接口之间是实现关系,而且类可以继承一个类

的同时实现多个接口.

6.接口与接口之间可以有继承关系.

 

接口和抽象类的异同点:
相同点:都是不断向上抽取而来的.

不同点:1.抽象类需要被继承,而且只能单继承

    接口需要被实现,而且可以多实现.

  2.抽象类中可以定义抽象方法和非抽象方法.

  子类继承后,可以直接使用非抽象方法.

接口中只能定义抽象方法,必须由子类去实现.

3.抽象类的继承,是is a关系.在定义该体系的基本共性内容.

接口的实现时like a关系.在定义体系的额外功能.

 

犬:按功能分:有导盲犬,搜爆犬.等

abstract class 犬

{

  abstract void 吼叫();

}

//abstract class 导盲

interface 导盲able

{

  abstract void 导盲();

}

 

class 导盲犬 extends 犬 implements 导盲able

{

  public void 吼叫()

  {

  }

  public void 导盲()

  {  

  }  

}  
如果想继承吼叫和导盲,就不能同时继承,此时可以用interface多实现.

但是:对于导盲犬来说,最基本的功能是犬的基本功能,只有类才能做到定义好

基本的功能.

导盲是额外的功能,用interface实现.

 

/*
    笔记本电脑使用.
    为了扩展笔记本的功能,但日后出现什么功能设备不知道.
    定义一个规则,只要日后出现的设备都符合这个规则就可以了.
    规则在java中就是接口.
*/
/*
class Mouse
{
}

class Demo
{
    public static void main(String[] args)
    {
        System.out.println();
    }
    
    public static void userMouse(Mouse m)
    {
        m.open();
    }
}
*/

interface USB//规则
{
    public void open();
    public void close();
}

class Demo
{
    public static void main(String[] args)
    {
        useUSB(new UPan());//功能扩展了.
     useUSB(new UsbMouse()); }
//使用规则
public static void useUSB(USB u)//接口类型的引用,用于接收(指向)接口的子类对象 { u.open(); u.close(); } } //一年后.-----------------------
//实现规则
//这些设备和电脑的耦合性降低了. class UPan implements USB { public void open() { System.out.println("upan open"); } public void close() { System.out.println("upan close"); } }
class UsbMouse implements USB
{
    public void open()
    {
        System.out.println("UsbMouse open");
    }
    public void close()
    {
        System.out.println("UsbMouse close");
    }
}
 

 

posted on 2016-12-04 23:06  夜行锦衣  阅读(84)  评论(0编辑  收藏  举报

导航