------- 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:
//抽象学生类示例2:
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();
}
}
//抽象类
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接口在最上面,然后紧跟着抽象类,哈,这下两个的最大优点都能发挥到极至了。 这种模式就是“缺省适配模式”。
伙伴们,这篇就到这里吧,让我休息,休息以会,下篇见。