目录
随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一 般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。
abstract表示抽象的,可以用来修饰类和方法。
用abstract关键字来修饰一个类,这个类叫做抽象类
1、抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类。
2、抽象类中一定有构造器,便于子类实例化时使用
3、开发中都会提供抽象类的子类,让子类对象实例化完成相关的操作。
4、抽象类中可以没有抽象方法
用abstract关键字来修饰一个方法,这个方法叫做抽象方法
1、抽象方法只有方法的声明,没有方法体
public abstract void method();
2、抽象方法只能用在抽象类中
说明:当在一个类中声明抽象方法,则表明此抽象方法不希望被调用,如果该类不是抽象类,则表明此抽象方法有被调用的可能性,因此抽象方法只能定义在抽象类中。(java的保护机制)
3、若子类重写了父类中的所有抽象方法后,此类才可以被实例化;若子类中没有重写父类中的所有的抽象方法,此子类必须也是一个抽象类,需用abstract修饰
说明:父类包括间接父类
1、abstract不能用来修饰属性、构造器等
2、abstract不能修饰私有方法、静态方法、final的方法、final的类
编写一个Employee类,声明为抽象类, 包含如下三个属性:name,id,salary。
提供必要的构造器和抽象方法:work()。
对于Manager类来说,他既是员工,还具有奖金(bonus)的属性。
请使用继承的思想,设计CommonEmployee类和Manager类,要求类中提供必要的方法进行属性访问。
- public abstract class Employee {
- private String name;
- private int id;
- private double salary;
- public Employee() {
- //构造器
- }
- public Employee(int id,String name,double salary) {
- //构造器
- this.id=id;
- this.name=name;
- this.salary=salary;
- }
-
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public double getSalary() {
- return salary;
- }
- public void setSalary(double salary) {
- this.salary = salary;
- }
- public abstract void work();
- }
- public class Manager extends Employee{
-
- private double bonus;
-
- public double getBonus() {
- return bonus;
- }
-
- public void setBonus(double bonus) {
- this.bonus = bonus;
- }
-
- /**
- * 构造器
- */
- public Manager() {
- super();
- }
-
- /**
- * @param id 账号
- * @param name 姓名
- * @param salary 工资
- */
- public Manager(int id, String name, double salary,double bonus) {
- super(id, name, salary);
- this.bonus=bonus;
- }
-
- public void work() {
- System.out.println("经理管理员工");
- }
- }
- public class CommomEmployee extends Employee {
-
- @Override
- public void work() {
- System.out.println("普通员工当牛做马");
-
- }
-
- }
- public class EmployeeTest {
- public static void main(String[] args) {
-
- Manager manager=new Manager(1001,"light",10000,200);
- CommomEmployee common=new CommomEmployee();
- manager.work();
- common.work();
- }
- }
运行结果如下

一方面,有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是Java不支持多重继承。有了接口,就可以得到多重继承的效果。接口和类是两个并列的结构
另一方面,有时必须从几个类中抽取出一些共同的行为特征,而它们之间又没有is-a的关系,仅仅是具有相同的行为特征而已。
继承是一个"是不是"的关系,而接口实现则是 "能不能" 的关系。
1、接口(interface)是抽象方法和常量值定义的集合。
2、java中接口和类是两个并列的结构
3、接口中不能定义构造器,即接口不能被实例化
4、java开发中,接口都通过类去实现(implements)的方式来使用(类实现接口)
5、定义接口中的成员
6、java类可以实现多个接口(一定程度上弥补了单继承的局限性)
格式: class A extends B implements C,D,E{}
7、接口与接口之间可以继承 ,且可以多继承
格式:
interface A{
}
interface B{
}
interface C extends A,B{
}
8、接口的使用体现多态性
9、接口实际上可以看做是一种规范,定义的是一组规则,体现了现实世界中“如果你是/要...则 必须能...”的思想
| 区别点 | 抽象类 | 方法 |
|---|---|---|
| 定义 | 包含抽象方法的类 | 主要是抽象方法和全局常量的集合 |
| 组成 | 构造方法、抽象方法、普通方法、变量 | 常量、抽象方法(jdk8.0:默认方法、静态方法) |
| 使用 | 子类继承抽象类(extends) | 子类实现接口(implements) |
| 关系 | 抽象类可以实现多个接口 | 接口不能继承抽象类,但允许继承多个接口 |
| 常见设计模式 | 模板方法 | 简单工厂、工厂方法、代理方式 |
| 对象 | 可以通过对象的多态性产生实例对象 | |
| 局限 | 抽象类有单继承性 | 接口没有此局限 |
| 实际 | 作为一个模板 | 是作为一个标准或是一种能力 |
| 选择 | 如果抽象类和接口都可以使用的话,优先使用接口,因为避免单继承的局限 | |
1、改错

答案如下:

2、定义一个接口用来实现两个对象的比较。
interface CompareObject{
public int compareTo(Object o); //若返回值是 0 , 代表相等; 若为正数,代表当 前对象大;负数代表当前对象小
}
定义一个Circle类,声明redius属性,提供getter和setter方法
定义一个ComparableCircle类,继承Circle类并且实现CompareObject接口。在 ComparableCircle类中给出接口中方法compareTo的实现体,用来比较两个圆的半径大小。
定义一个测试类InterfaceTest,创建两个ComparableCircle对象,调用compareTo 方法比较两个类的半径大小。
- public class Circle {
- private double redius;
-
- public double getRedius() {
- return redius;
- }
-
- public void setRedius(double redius) {
- this.redius = redius;
- }
-
- /**
- * @param redius 半径
- * 带参数构造器
- */
- public Circle(double redius) {
- super();
- this.redius = redius;
- }
-
- /**
- * 无参构造器
- */
- public Circle() {
- super();
- }
-
- }
- interface ComparableObject{
- public int compareTo(Object o);
- }
-
- public class ComparableCircle extends Circle implements ComparableObject {
- /**
- * 无参构造器
- */
- public ComparableCircle() {
- super();
- }
-
- /**
- * @param redius 半径
- */
- public ComparableCircle(double redius) {
- super(redius);
- }
-
- /**
- * 比较两圆半径大小,相等返回0,正数说明当前对象大,负数说明当前对象小
- */
- @Override
- public int compareTo(Object o) {
- if(this==o) {
- return 0;
- }
- if(o instanceof ComparableCircle) {
- ComparableCircle o1=(ComparableCircle)o;
- if(this.getRedius()>o1.getRedius()) {
- return 1;
- }else if(this.getRedius()==o1.getRedius()) {
- return 0;
- }else {
- return -1;
- }
- }else {
- return 0;
- }
- }
-
- }
- public class InterfaceTest {
- public static void main(String[] args) {
- ComparableCircle circle1=new ComparableCircle(3.6);
- ComparableCircle circle2=new ComparableCircle(3.6);
- int compareResult = circle1.compareTo(circle2);
- System.out.println(compareResult);
-
- }
- }
测试结果如下:

当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类。
在Java中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类。
Inner class一般用在定义它的类或语句块之内,在外部引用它时必须给出完整的名称。
Inner class的名字不能与包含他外部类的类名相同
内部类可分为成员内部类(静态、非静态)和局部内部类(方法内、代码块内、构造器内)
1、成员内部类作为外部类成员
注意:
2、成员内部类作为外部类的类
1、局部内部类只能声明在方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类
2、局部内部类的对象可以通过外部方法的返回值返回使用,返回值类型只能是局部内部类的父类或父类的接口类型
1、成员内部类和局部内部类,在编译后都能生成字节码文件
2、格式:
1、在局部内部类中,如果调用局部内部类所声明的方法的局部变量时,要求此局部变量声明为final的
2、jdk7及7之前要求局部变量必须显示声明;jdk8及8以后可以省略final的声明