一、 Java继承概述
继承的关键字为extends.
继承说的简单点有点子承父业的味道,就是子类一旦继承了父类,父类中所的成员变量和方法都可以被子类使用。
继承的特点;
1. 提高了代码的复用性。
2. 让类产生了关系,有了这个关系,体现了多态的特性。
继承的注意事项:
1. 在Java中只能单继承,不支持多继承,即同时继承两个类;但有类似多继承的方式,叫做多实现。
2. 在java中继承可以多重继承,也就是说B继承了A,C继承B之后就可以拥有A和B所有成员变量和方法,类似于沿袭,只要上一代有的我必须都有,所以这也叫做一个继承体系。
3. 在Java中继承体系中的父类,都不是不断抽取子类的中共性内容得来的
4. 在java中有一个超类,是所有类的父类,叫做object。
5. 在Java中必须类与类有所属关系才可以继承,就像父子间的血缘关系,必须得有点联系才行,也就是父类中必须有子类中共性内容。
在Java中不得为了获取其他类的功能达到简化代码的目的而继承。
继承代码示例:
class ExtendsDemo
{
public static void main(String[] args)
{
//创建子类对象
Zi z = new Zi();
z.setage(20);
z.setname("gezi");
//直接调用study方法
z.study();
}
}
//父类
class Fu
{
private int age;
private String name;
//对外提供访问age的方法
public void setage(int age)
{
if(age<130)
this.age = age;
else
System.out.println("输入非法");
}
//对外提供得到age方法
public int getage()
{
return age;
}
public void setname(String name)
{
this.name=name;
}
public String getname()
{
return name;
}
void study()
{
System.out.println("good good study"+"\n"+"name="+name+"\n"+"age="+age);
}
}
//子类继承父类 就具备了父类中的所有成员特性
class Zi extends Fu
{
}
二、 聚集关系
在类与类之间不光有继承关系,还有聚集关系,具体的说就是聚合和组合关系。
聚合:聚合关系就像一个球队,球队包括球员,球员有事球队中一个,但是少一个球员有不会对球队产生太大的影响。
组合:组合关系就像水和鱼的关系,鱼离开水就不可生存,彼此密不可分。
三、 关键字super
super关键字的用法与this一致,不一样的地方就是super是父类,this是本类,说的在明白点,就是super是指挥老子干活的,this指挥儿子干活的。
子父类中成员变量的特点
在继承关系中,如果存在非私有且同名的成员变量时,父类的使用super关键字调用,子类的用this关键字调用。
class SuperDemo
{
public static void main(String[] args)
{
//创建子类对象
Zi z = new Zi();
//调用子类方法
z.show();
}
}
class Fu
{
int num = 5;
}
//子类继承父类
class Zi extends Fu
{
int num = 10;
void show()
{
//通过super关键字访问父类中的num,this关键字访问子类中的成员
System.out.println(super.num+"……"+this.num);
}
}
子父类中函数的特点
方法重写(覆盖)
在继承关系,如果子父类中存在同名函数,默认会执行子类中函数,这种现象叫做重写(覆盖)。
在子类继承父类方法后,如果子类中拥有和父类相同功能,但功能内容不一致是,这时我们利用函数的覆盖特性,就父类中的方法覆盖掉,但如果想保留父类的功能,可以在覆盖的方法中,使用super关键字调用父类的方法,达到拓展功能的目的。
需要注意的是:
重写(覆盖)方法时,方法必须完全一样才能被覆盖。
当子类的权限大于等于父类是方法才会被覆盖。
静态函数也能被覆盖,但是静态只能覆盖静态。
注意:
方法重写不同于方法重载,重写必须两个方法完全一样,而重载只需要参数个数或者参数类型不同。
重写和重载功能类似,都是让同名函数具备不同的功能,但重写存在一定的局限性。
重写值发生在继承中,子类重写父类方法。
子父类中构造函数的特点
1. 在子类对象初始化的时候,父类中的构造函数也会运行。
造成这个现象的主要原因就是所有子类的函数中,有一个隐式语句super();
super();必须出现在子类构造函数第一行,功能是访问父类中空参的构造函数。
2. 子类的构造函数中必须有访问父类函数的语句。
因为子类可以直接获取父类中的数据,所有在子类初始化对象之前,所有子类在初始化对象之前,要先查看一下父类是如何对这些数据初始化的,所以子类对象初始化之前必须要访问一下父类中的构造函数。
当然,如果需要访问非空参的父类够造函数时,就需要我们用super语句手动指定来访问父类中的哪个构造函数了。
super();语句只能出现在子类构造函数的第一行,且this语句不能同时使用。
继承弊端:打破了封装性,因为有继承关系发生,子类必然可以访问父类中的所有数据。class CoverDemo
{
public static void main(String[] args)
{
//创建子类对象并调用study()方法
new Zi().study();
Zi.show();
}
}
class Fu
{
Fu()
{
System.out.println("这是父类的构造函数");
}
int age = 20;
String name = "gezi";
void study()
{
System.out.println("name="+name+"age="+age+"FU");
}
static void show()
{
System.out.println("Fu");
}
}
class Zi extends Fu
{
Zi()
{
//默认的会先执行super();语句 访问父类中构造函数
super();
System.out.println("这是子类的构造函数");
}
//重写父类中的study方法
void study()
{
System.out.println("name="+name+"\n"+"age="+age+"\n"+"ZI");
}
static void show()
{
System.out.println("Zi");
}
}
四、 关键字final格式:
final int PI=3.14;
1. Final可以修饰类、变量、函数。一旦被final修饰,就表示这是最终的形式,不可修改。
2. Final修饰类之后,类便不可被继承。不可以被继承。避免了被继承,被子类复写功能。
3. Final修饰方法之后,方法便不可被重写。
4. Final修饰变量之后,变量只能被赋一次值,所以可以修饰成员变量,也可以修饰局部变量,我们可以称之为常量。
当在描述事物时,一些数据的出现值是固定的,那么这时为了增强阅读性,所以给这些值起个名字,便于阅读。
而这个值不需要改变,所以加上final修饰。
作为常量:常量的书写规范所有字母都大写,如果由多个单词组成单词间通过_连接。5. 内部类定义在类中的局部位置上时,只能访问该局部被final修饰的局部变量。
六、 抽象类 关键字abstract
抽象:抽象是从众多的事物中抽取出共同的、本质性的特征,而舍弃其非本质的特征。
可以理解为不具体、不明确、很模糊。
抽象类的由来:
当多个类中出现相同功能,但是功能主体不同,这时可以进行向上抽取。这时,只抽取功能定义,而不抽取功能主体。
抽象类的特点:
1. 抽象方法一定存在于抽象类中。
2. 在类中一旦出现抽象抽象方法,这个类也必然是抽象类,会被anstract修饰,系统默认添加,或者自己手动添加。
3. 在抽象类中可以没有抽象方法,如果类被abstract修饰,而类中没有方法被修饰,那么类就不能被创建对象。
4. 抽象类不能用new创建对象,因为调用抽象方法没意义。
5. 抽象类中的抽象方法要被使用,必须由子类复写起所有的抽象方法后,建立子类对象调用。
6. 如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。
抽象类和普通类的区别:
抽象类和一般类没有太大的不同。
该如何描述事物,就如何描述事物,只不过,该事物出现了一些看不懂的东西。
这些不确定的部分,也是该事物的功能,需要明确出现。但是无法定义主体,通过抽象方法来表示。
抽象类比一般类多个了抽象函数,就是在类中可以定义抽象方法。
抽象类不可以实例化。
特殊之处在于抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。
abstract 关键字,和哪些关键字不能共存?
final:被final修饰的类不能有子类。而被abstract修饰的类一定是一个父类。
private: 抽象类中的私有的抽象方法,不被子类所知,就无法被复写, 而抽象方法出现的就是需要被复写。
static:如果static可以修饰抽象方法,那么连对象都省了,直接类名调用就可以了。
可是抽象方法运行没意义。
抽象类中是否有构造函数?
有,抽象类是一个父类,要给子类提供实例的初始化。
抽象类练习:
/*
假如我们在开发一个系统时需要对员工进行建模,员工包含 3 个属性:
姓名、工号以及工资。经理也是员工,除了含有员工的属性外,另为还有一个
奖金属性。请使用继承的思想设计出员工类和经理类。要求类中提供必要的方
法进行属性访问。
员工类:name id pay
经理类:继承了员工,并有自己特有的bonus。
*/
class AbstractDemo
{
public static void main(String[] args)
{
//创建一个员工
Person p = new Person("gezi","001",2000);
p.work();
//创建一个经理
Manager m = new Manager("heima","002",3000,3000);
m.work();
}
}
//由员工类和经理类向上抽取的抽象类
abstract class Employee
{
private String name;
private String pid;
private int pay;
Employee(){}
//员工一入职就具备的属性
Employee(String name,String pid,int pay){
this.name = name;
this.pid = pid;
this.pay = pay;
}
public abstract void work();
}
//普通员工类继承员工类
class Person extends Employee
{
//员工一入职就具备name/pid/pay属性
Person(String name,String pid,int pay)
{
super(name,pid,pay);
}
//重写work方法
public void work()
{
System.out.println("我是普通员工");
}
}
//经理类继承员工类
class Manager extends Employee
{
//经理特有的奖金
private int bonus;
Manager(String name,String pid,int pay,int bonus)
{
//super(name,pid,pay);
//将值传给子类
this.bonus=bonus;
}
public void work()
{
System.out.println("我是经理"+"bonus="+bonus);
}
}
七、 模版方法设计模式
什么是模板方法设计模式/
在定义功能时,功能的一部分是确定的,但是有一部分是不确定的,而确定的部分在使用不确定的部分,那么这时就将不确定的那部分暴露出去,有该类的子类去完成。
例子:
1、需求:获取一段程序运行的时间
2、原理:获取程序开始和结束的时间并相减
3、获取时间:System.currnetTimeMillis();
4.代码实现
/*
需求:获取一段程序运行的时间。
原理:获取程序开始和结束的时间并相减即可。
获取时间:System.currentTimeMillis();
当代码完成优化后,就可以解决这类问题。
这种方式,模版方法设计模式。
什么是模版方法呢?
在定义功能时,功能的一部分是确定的,但是有一部分是不确定,而确定的部分在使用不确定的部分,
那么这时就将不确定的部分暴露出去。由该类的子类去完成。
*/
abstract class GetTime
{
//功能单一 禁止被复写
public final void getTime()
{
//计算开始时间
long start = System.currentTimeMillis();
runcode();
//计算结束时间
long end = System.currentTimeMillis();
//输出运行时间
System.out.println("毫秒:"+(end-start));
}
//计算运行的程序不确定 直接抽取出来
public abstract void runcode();
}
class SubTime extends GetTime
{
//需要计算运行时间的程序
public void runcode()
{
for(int x=0; x<4000; x++)
{
System.out.print(x);
}
}
}
class Test
{
public static void main(String[] args)
{
//创建对象
SubTime gt = new SubTime();
//调用计时方法
gt.getTime();
}
}
八、 接口
接口的由来
初期理解,可以认为是一个特殊的抽象类
当一个抽象类中的所有方法都为抽象方法时,我们可以用另一种方式来体现,这就是接口。
定义接口的关键字:interface
定义接口的格式:interface{ }
接口定义常量和方法的固定格式:
定义接口全局常量 public static final
定义接口抽象方法 public abstract
结论:接口中的成员都是公共的权限,都是public。
接口的注意事项:
接口是不可以创建对象的,因为有抽象方法。
接口需要被子类实现(implements),子类对接口中的抽象方法全都覆盖后,子类才可以实例化,否则子类是一个抽象类。
关键字:implements 实现
接口可以被类多实现,也是对多继承不支持的转换形式。
接口的特点:
1. 接口是对外暴露的规则。
2. 接口是程序的功能扩展。
3. 接口的出现降低耦合性。
4. 接口可以用来多实现。
5. 类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口。
6. 接口与接口之间可以有继承关系。
接口与抽象类的异同点:
相同点:都是不断向上抽取而来的。
不同点:
1. 抽象类需要被继承,而且只能单继承。接口需要被实现,而且可以多实现。
2. 抽象类中可以定义抽象方法和非抽象方法,子类继承后,可以直接使用非抽象方法。
3. 接口中只能定义抽象方法,必须由子类去实现。
4. 抽象类的继承,是is a关系,在定义该体系的基本共性内容。接口的实现是like a关系。
注意:接口的属性都是常量,而且是全局常量,且接口中的方法都是抽象的。
class InterfaceDemo
{
public static void main(String[] args)
{
//创建对象
Demo d = new Demo();
d.show();
d.study();
}
}
//定义一个接口
interface A
{
//接口的成员变量全部为全局变量
public static int NUM=10;
//接口的方法都为抽象方法
public abstract void show();
}
interface B
{
public static double PI=3.14;
public abstract void study();
}
//接口可以被多继承
class Demo implements A,B
{
//重写接口方法
public void show()
{
System.out.println("我是接口A"+NUM);
}
public void study()
{
System.out.println("我是接口B"+PI);
}
}
关于接口的总结:
接口就是程序的扩展功能,就像我们电脑的USB接口一样,可连接电脑和电脑外设,只要电脑和外设都符合接口就能使用这个接口实现功能的扩展。接口就是我们功能的主体和扩展功能的中间环节,类似一个协议。