黑马程序员—【Java基础篇】之继承、抽象及接口


------- android培训 java培训 、期待与您交流! ---------

    这篇分析总结Java的继承、抽象和接口,小伙伴们快来围观吧,来吧,来吧,相约csdn。偷笑

一、继承

1.概念

    继承的概念牵扯到2个概念。

    通俗说:父与子的关系,父亲将基因传递给儿子,儿子继承了父亲的全部功能,其中儿子又青出于蓝而胜于蓝,儿子有会有很多新的特性和才能;伙伴们清楚了吗,这就是父类与子类,简单说就是父类有的功能和方法子类都有,而且子类还有自己的功能和方法。

2.特点

(1)提高代码复用性

    定义在父类中的成员(变量和方法),可以被子类重复使用;

(2)多态关系

    二个类之间产生了关系;多态的特性的体现会使得其应用起来更方便。

(3)注意事项

    a. 不要为了获取其他类的功能简化代码而继承;必须是类与类之间有所属关系才可以继承。

    b. Java语言中,只支持单继承,不支持多继承。例:一个儿子只能只有一个父亲一样。其中原因:因为类与类多继承的话,容易带来安全隐患。如:当多个父类中定义了相同功能,当功能内容不同时,子类对象不确定要运行哪个一个,这是什么纠结与痛苦的。但是,值的表扬的是:Java保留了这种机制,并用另一种体现形式来完成。叫多实现。

3.应用

(1)了解基本功能查父类

        如果使用体系功能或者方法,要先对体系中父类的描述进行参阅,了解父类中的共性功能,即可以使用该体系了。这样既可以减少查阅时间,也能更系统的了解体系结构,以及父类的功能。

(2)调用功能,创建子类

     具体调用父类中的功能的时候,需要创建子类对象,通过子类对象对父类方法调用,实现继承。
     为何要通过创建子类对象调用父类中的方法呢?原因如下:

     a.  父类很可能不可以创建对象,如父类是一个抽象类或者接口,这就需要子类创建对象,调用方法。
     b.  创建子类对象,可以使用更多的功能,如父类公有的,和子类中自定义的特有功能。

//定义一个人父类  
class Person  
{  
    //名字和年龄是人的共有属性  
    String name;  
    int age;  
      
    //在构造函数中对名字和年龄进行初始化  
    Person(String name,int age)  
    {  
        this.name=name;  
        this.age=age;  
        System.out.println(name+"  "+age);  
    }  
    //人都具有睡觉的功能  
    void sleep()  
    {  
        System.out.println("sleep");  
    }  
}  
//定义一个学生,继承人,作为子类  
class Student extends Person  
{  
    Student(String name,int age)  
    {  
        super(name,age);    //super关键字表示父类,因为姓名和年龄在父类中进行了初始化动作,在这里可以直接调用  
    }  
    //学生具有特有的功能,学习  
    void study()  
    {  
        System.out.println("study");  
    }  
  
}  
  
class Demo  
{  
    public static void main(String[] args)  
    {  
        Student s=new Student("zhangsan",20);  
        System.out.println(s.name="wangwu");  
        s.sleep();  
        s.study();  
    }  
}  

4.继承出现后,类成员特点

    继承类成员:变量、函数、构造函数。

 (1)变量

     子父类中出现非私有的同名成员变量是,子类访问本类的同名时,要用this关键字(如果省略了this,仍是代表本类的变量);子类访问父类同名变量时,用super关键字。
    补充:this和super两者都存在与方法区中。
    this:本类对象引用,那个对象调用this所在的函数,this就代表那个对象。
    super:父类对象引用,用于子类初始化父类构造函数时等。

 (2)函数(覆盖(重写))

     当子类同父类出现相同函数时,子类对象调用该函数时,会运行子类内容,如同覆盖谷类函数一样。实际上并没有覆盖父类的函数,如果还需要调用父类的这个方法,需要用super.方法名即可。

class Father  
{  
    int num = 3;  
    void show()  
    {  
        System.out.println(num);  
    }  
}  
  
class Son extends Father  
{  
    int num = 5;  
    //复写父类函数  
    void show()  
    {  
        System.out.println(num);//this引用,此处省略this,结果是5  
        System.out.println(super.num);//super引用,结果是3.  
    }  
}  
  
class Demo  
{  
    public static void main(String [] args)  
    {  
        Son s = new Son();  
        s.show();  
    }  
}
    那么接下来,我就替毕老师来分析下父类和子类在内存中是怎样的存在 偷笑

    清楚了吗,大家,伙伴们。好吧,说心里话,到这里也是很模糊,等待毕老师吧。

(3)构造函数

    首先,这里重点分析,子类的构造函数特点。

    a. 在对子类对象进行初始化时,父类构造函数也在运行,而且是在子类之前运行。

    因为子类构造函数默认第一行有一条隐式语句:super();(没有显式的继承父类的类中,是默认继承Object的,所以构造函数第一条语句仍是super();),因此会首先访问父类中空参数的构造函数(在不手动加入含有参数的super的语句的情况下),这是系统默认的。所有的构造函数均是如此。

    b. 注意:

    1).如果父类中无空参数构造函数(即父类中显式的构造了含有参数的构造函数),必须手动加入父类中该构造函数。

    2).构造函数不存在覆盖,子类中的构造函数必定至少有一个会访问父类中的构造函数。

    构造函数结论:

    子类的所有构造函数,默认都会访问父类中空参数的构造函数。因为子类每一个构造函数内的第一行都有一句隐式super();当父类中没有空参数的构造函数时,子类必须手动通过supe语句或者this语句形式来指定要访问的构造函数。当然子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。子类中至少会有一个构造函数会访问父类中的构造函数。

(4)final关键字

    final 关键字的由来:继承的出现,打破了对象的封装性,使得子类可以随意复写父类中的功能。这也是继承的一大弊端。那么怎么解决这个问题呢?这里就引出了一个新的关键字——final。

   1 )特点

    a    final作为一个修饰符,可以修饰类、方法、变量。
    b    final修饰的类不可以被继承。为了避免被子类覆写功能
    c    final修饰的方法不可以被覆盖
    d   final修饰的变量是一个常量。只能被赋值一次,既可以修饰成员变量,又可以修饰局部变量。当在描述事物时,一些数据的值是固定的(比如π),为了增强阅读性,都给这些值取一个名字,方便阅读,而这个值不需要改变,加上final修饰。作为常量,所有字母都大写,如果多个单词组成,单词间通过_连接
    e   内部类只能访问被final修饰的局部变量
     f   使用final关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的 。

以上就是final关键字的小节啦,小伙伴们,清楚一些了吗,看看吧。

二、抽象

    关于抽象类,分享和总结一下几个方面:1. 抽象类概述;2. 抽象类的特点;3. 抽象类举例代码讲解;4. 抽象类相关问题。

1、概念

    抽象就是从多个事物中将共性的,本质的内容抽取出来。例如:猫和狗共性都是动物,动物就是抽象出来的概念。

2、抽象类

    Java中可以定义没有方法体的方法,该方法的具体实现由子类完成,该方法称为抽象方法,包含抽象方法的类就是抽象类。

(1)特点

    a、抽象类和抽象方法必须用abstract关键字来修饰。
    b、抽象方法只有方法声明,没有方法体,定义在抽象类中。
    c、格式:修饰符 abstract 返回值类型 函数名(参数列表) ;
    d、抽象类不可以被实例化,也就是不可以用new创建对象。原因如下:
抽象类是具体事物抽取出来的,本身是不具体的,没有对应的实例。例如:犬科是一个抽象的概念,真正存在的是狼和狗。而且抽象类即使创建了对象,调用抽象方法也没有意义。
    g、抽象类通过其子类实例化,而子类需要覆盖掉抽象类中所有的抽象方法后才可以创建对象,否则该子类也是抽象类。

(2)抽象类实例

    抽象类实例1:

abstract class Student//抽象学生类
{
	abstract final void study();//抽象方法(学生都有学习)
	void sleep()
	{
		System.out.println("躺着");
	}
}

class ChongCiStudent extends Student//冲刺班学生继承了Student
{
	void study()//学习方法覆盖抽象类Student
	{
		System.out.println("chongci study");//冲刺学习
	}
}

class BaseStudent extends Student//基础班学生基础抽象学生类
{
	void study()//基础学习
	{
		System.out.println("base study");//进行基础的学习
	}
}

class AdvStudent extends Student//高级班学生继承了抽象学生类
{
	void study()//进行高级学习
	{
		System.out.println("adv study");
	}
}
class AbstractDemo //主函数
{
	public static void main(String[] args) 
	{
		//new Student();
		//new BaseStudent().study();
	}
}

    抽象类实例2:

/**
需求:
假如我们在开发一个系统时需要对员工进行建模,员工包含 3 个属性:
姓名、工号以及工资。经理也是员工,除了含有员工的属性外,另为还有一个
奖金属性。请使用继承的思想设计出员工类和经理类。要求类中提供必要的方
法进行属性访问。

员工类:name id pay

经理类:继承了员工,并有自己特有的bonus。
*/
abstract class Employee//声明Employee抽象类:定义抽象雇员
{
	private String name;//定义私有变量
	private String id;
	private double pay;

	Employee(String name,String id,double pay)//定义Employee构造函数
	{
		this.name = name;
		this.id = id;
		this.pay = pay;
	}
	
	public abstract void work();//定义抽象方法

}



class Manager extends Employee//Manager继承了Employee类
{
	private int bonus;//定义Manager类私有变量bonus
	Manager(String name,String id,double pay,int bonus)//定义构造函数
	{
		super(name,id,pay);//引用父类构造函数
		this.bonus = bonus;
	}
	public void work()//定义覆盖方法
	{
		System.out.println("manager work");
	}
}

class Pro extends Employee//同理
{
	Pro(String name,String id,double pay)
	{
		super(name,id,pay);
	}
	public void work()
	{
		System.out.println("pro work");
	}
}
class  AbstractDemo   
{  
    public static void main(String[] args)   
    {  
        new Manager("manager","007",1000,20).work();  
        new Pro("pro","008",80000).work();  
    }  
}  

3、抽象方法

    多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法。
/**
例如:狼和狗都有吼叫的方法,可是吼叫内容是不一样的。所以抽象出来的犬科虽然有吼叫功能,但是并不明确吼叫的细节。
*/

4、抽象类的一些思考问题


(1)抽象类与一般类的区别

    a、抽象类和一般类没有太大的不同。该如何描述事物,还是如何描述事物。只不过,该事物中出现了一些不知道具体内容的方法部分。这些不确定的部分,也是该事物的功能,需要明确出来,但是无法定义主体。通过抽象方法来表示。
    b、抽象类比一般类多了个抽象函数。就是在类中可以定义抽象方法。
    c、抽象类不可以实例化。
    d、抽象类虽然不能创建对象,但是也有构造函数。供子类实例化调用。

(2)abstract关键字不可以和哪些关键字共存

    abstract修饰的函数不能同时被private、final、static修饰。

    原因:

    final:被final修饰的类不能有子类。而被abstract修饰的类一定是一个父类。

    private:抽象类中的私有的抽象方法,不被子类所知,就无法被复写;而抽象方法出现的就是需要被复写。

   static:如果static可以修饰抽象方法,那么连对象都省了,直接类名调用就可以了。可是抽象方法运行没意义。

    下面来一个小例子:

/** 
需求:获取一段程序的运行时间 
原理:将程序开始执行到执行结束的时间相减就是程序的运行时间了 
思路:1、由于想要获取的程序时未知的,可以将其抽象出去,通过子类继承复写的方式获得程序 
      2、利用java中提供的当前时间功能记录下程序开始执行和执行结束的时间,然后相减 
*/  
abstract class  GetTime  
{  
    public final void getTime()//加final表示不能被复写  
    {  
        long start=System.currentTimeMillis();//开始执行时间  
        program();  
        long end=System.currentTimeMillis();//执行结束时间  
        System.out.println("毫秒"+(end-start));  
    }  
    abstract void program();//由于程序不确定,故抽象出去  
}  
  
//要获取执行时间的程序  
class GetProgram extends GetTime  
{  
    void program()  
    {  
        for(int x=0;x<1000;x++)  
            System.out.print(x+" ");  
    }  
} 
class TemplateDemo  
{  
    public static void main(String[] args)   
    {  
        new GetProgram().getTime();  
        System.out.println("Hello World!");  
    }  
}  

    小结:抽象类中可以不定义抽象方法。这样做可以不让本来实例化,可以用于模块设计。

三、接口

1、概述

    (1)接口的理解

    接口,可以被认为是一个特殊的抽象类。当抽象类中的方法都是抽象的,那么该类可以通过接口的形式来表示。接口使用interface来表示,子类中用implements实现。格式为:
    interface 接口名{}
    子类名 implements接口名{}

    (2)格式特点

    a、接口中常见定义:常量,抽象方法。
    b、接口中的成员都有固定修饰符。
    常量:public static final
    方法:public abstract

     (3)接口中的成员:public

    在使用中,常量可以不写publicstatic final,方法可以不写publicabstract,编译时Java会自动添加这些修饰符,因为这是固定的格式修饰符;但为了方便阅读,通常我们都写上。

2、特点

   (1)、接口是对外暴露的规则。
    (2)、 接口是程序的功能扩展。
    (3)、 接口的出现降低耦合性。
   (4)、 接口可以用来多实现。这也是对多继承不支持的转换形式。java支持多实现。
   (5)、 类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口。
   (6)、 接口与接口之间可以有继承关系。而且可以多继承。

3、接口与抽象类的异同

示例1:

//抽象学生类  
abstract class Student  
{     
    //抽象的学习方法  
    abstract void study();  
    //共性内容非抽象的睡觉方法  
    void sleep()  
    {  
        System.out.println("sleep");  
    }  
}  
  
//接口,吸烟  
interface Smoking  
{  
    void smoke();  
}  
  
//Zhangsan这个对象继承学生类,实现吸烟接口  
class Zhangsan extends Student implements Smoking  
{  
    //复写学习方法  
    void study()  
    {  
        System.out.println("Zhangsan_study");  
    }  
  
    //复写吸烟方法  
    public void smoke()
{  
        System.out.println("Zhangsan_smoking");  
    }  
}  
  
//Lisi是好学生,不吸烟  
class Lisi extends Student   
{     
    //复写学习方法  
    void study()  
    {  
        System.out.println("Lisi_study");  
    }  
}  
  
  
class InterfaceDemo //主函数调用 
{  
    public static void main(String[] args)   
    {  
        Zhangsan z = new Zhangsan();  
        z.study();  
        z.smoke();  
        new Lisi().study();  
    }  
}  
示例2:

//抽象类  
abstract class A{  
    //可用各种修饰符声明  
    int x;  
    public int a;  
    private int b;  
    static int c;  
    final int d;  
    public static final int e;  
    //抽象方法必须有  
    abstract void function();  
    //还可以有非抽象方法  
    void fun(){  
        //.......  
    }  
}  
  
//接口  
interface B{  
    //声明必须加默认修饰符  
    public static final int a;  
    //方法必须是抽象的,不可有非抽象方法  
    abstract void function();  
}  
interface X{}  
interface Y{}  
//继承关系:抽象类和类间  
class C extends A{  
    void function(){  
    //......  
    }  
}  
//实现关系:类与接口间,可多实现  
class D implements B,X,Y{  
    //可直接访问B中的a  
    void function(){  
        //......  
    }  
}  
//多继承关系:接口与接口间  
interface E extends B,X implements Y  
{  
    //......  
}

(1)异

    a、与类间关系不同:
        抽象类是一种被子类继承(extends)的关系。
        而接口和类是一种实现(implements)关系。
        接口和接口是继承(extends)关系。
    注:
        1) 、子类只能继承一个抽象类。
        2)、 一个类却可以实现多个接口。
        3)、接口可以继承多个接口。
   b、定义特点不同:
       1)、抽象类可以定义变量、非抽象方法以及抽象方法(必须有一个抽象方法)。
       变量:private、public、final、static等等修饰符。
       抽象方法:abstract(必须有)、public、static等等修饰符。
       2)、接口可以定义常量、抽象方法
        常量:public static final(都是存在的,如果没有会默认加上),赋值后,不可再次赋值。
        方法:public abstract。
   c、权限不同:
        1)、抽象类可以有私有变量或方法,子类继承抽象父类必须复写全部的抽象方法。
        2)、接口是公开(public)的,里面不能有私有变量或方法,因为接口是对外暴露的,是提供给外界使用的。
        3))、实现接口必须重写接口中的全部抽象方法。
    d、成员不同:
        1)、接口中只能有静态的不能被修改的成员变量(即常量),而且所有成员方法皆为抽象的。
    e、变量类型不同:
        1)、抽象类中的变量默认是friendly型的,即包内的任何类都可以访问它,而包外的任何类都不能访问它(包括包外继承了此类的子类),其值可以在子类中重新定义,也可重新赋值。
        2)、接口中定义的变量是默认的public static final,且必须进行初始化即赋初值,并不可改变。
    f、设计理念不同:
        1)、抽象类表示的是:"si-a"的关系。
        2)、接口表示的是:"like-a"的关系。

(2)联系

    a、其实接口是抽象类的延伸,可以将它看做是纯粹的抽象类,就是说接口比抽象类还抽象。
    b、抽象类和接口都必须被一个类(子类)复写里面的全部抽象方法。
    c、接口和抽象类都不可创建对象,因为其中含有抽象方法,需要被子类实现后,对接口中抽象方法全覆盖后,子类才可以实现实例化。

(3)总结

    Java接口和Java抽象类有太多相似的地方,又有太多特别的地方,究竟在什么地方,才是它们的最佳位置呢?把它们比较一下,你就可以发现了。
a、Java接口和Java抽象类最大的一个区别,就在于Java抽象类可以提供某些方法的部分实现,而Java接口不可以,这大概就是Java抽象类唯一的优点吧,但这个优点非常有用。
    如果向一个抽象类里加入一个新的具体方法时,那么它所有的子类都一下子都得到了这个新方法,而Java接口做不到这一点,如果向一个Java接口里加入一个新方法,所有实现这个接口的类就无法成功通过编译了,因为你必须让每一个类都再实现这个方法才行,这显然是Java接口的缺点。
b、一个抽象类的实现只能由这个抽象类的子类给出,也就是说,这个实现处在抽象类所定义出的继承的等级结构中,而由于Java语言的单继承性,所以抽象类作为类型定义工具的效能大打折扣。
    在这一点上,Java接口的优势就出来了,任何一个实现了一个Java接口所规定的方法的类都可以具有这个接口的类型,而一个类可以实现任意多个Java接口,从而这个类就有了多种类型。
c、从第2点不难看出,Java接口是定义混合类型的理想工具,混合类表明一个类不仅仅具有某个主类型的行为,而且具有其他的次要行为。
d、结合1、2点中抽象类和Java接口的各自优势,具精典的设计模式就出来了:声明类型的工作仍然由Java接口承担,但是同时给出一个Java抽象类,且实现了这个接口,而其他同属于这个抽象类型的具体类可以选择实现这个Java接口,也可以选择继承这个抽象类,也就是说在层次结构中,Java接口在最上面,然后紧跟着抽象类,哈,这下两个的最大优点都能发挥到极至了。
这种模式就是“缺省适配模式”。

    伙伴们,这篇就到这里吧,让我休息,休息以会,下篇见。



------- android培训 java培训 、期待与您交流! ---------





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值