抽象类和接口


一、抽象类

1.概述

没有方法体的方法叫抽象方法,有抽象方法的类一定是抽象类。而抽象类就是对类进行抽象。在编写时,需要子类必须实现的属性和行为,可以在对父类进行一个抽象,抽象类的运用场景。

2.特点

抽象类的特点主要有四点:
1)抽象类和抽象方法用abstract修饰;
2)抽象类中不一定有抽象方法,但有抽象方法的类一定是抽象类;
3)抽象类多态。抽象类不能直接实例化,要通过子类对象的实例化来实现。
4)抽象类的子类要么重写抽象类中所有的抽象方法,要么是抽象类。

3.其成员特点

分为三类:
1)成员变量。可以是变量,也可以是常量;
2)构造方法。可以有构造方法,但不能直接实例化。作用是用于子类访问父类数据的初始化。
3)成员方法。可以有抽象方法来限定子类必须完成某些操作,也可以有非抽象方法,提高代码的复用性(继承)。

二、接口

1.概述

一种公共的规范标准,只要符合就可以通用。就像现实中的USB接口一样,只要对应的插头,都可以接上。
而java中的接口体现在对行为的抽象。
接口的运用场景,当多人实现一个项目,每个人编写的功能模块会有重合的部分,这个时候可以使用接口,便于之后的汇总。

2.特点

1)接口用interface来修饰;
2)类实现接口用implements来表示;
3)接口多态。接口不能直接实例化,要通过实现类对象实例化;
4)接口的实现类要么重写接口中的所有抽象方法,要么是抽象类;

3.其成员特点

1)成员变量。只能是常量,默认public static final;
2)构造方法。没有构造方法,因为接口是对行为的抽象,并不直接存在;一个类如果没有父类,那么默认继承Object类;
3)成员方法。在jdk8中有了新特性,除了抽象方法,接口中可以定义默认(default)实现方法和静态(static)方法。为了接口的实现类不用每个都重新实现新添加的接口方法,引入default默认实现,static的用法直接用接口名去调方法即可。
补充:“类优先”,当一个类继承了父类又实现接口,若它们的方法名相同,则优先继承父类中的同名方法,若要实现两个同名方法的接口,则要实现类手动声明默认实现哪个接口的方法。

三、抽象类和接口的区别

1.成员区别

1)抽象类。可以是变量,也可以是常量。可以有抽象方法,也可以有非抽象方法。
2)接口。只能是常量。只能是抽象方法。

2.关系区别

1)类与类。继承关系,只能单继承,也可多层继承。
2)类与接口。实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口。
3)接口和接口。继承关系,可以单继承,也可以多继承

3.设计理念区别

1)抽象类。是对类(行为和属性)的抽象。
2)接口。是对行为的抽象。

四、参数传递

1)类名作为形参和返回值,需要的和返回的是该类的对象。
2)抽象类作为形参和返回值,需要的和返回的是该抽象类的子类对象。
3)接口名作为形参和返回值,需要和返回的是该接口的实现类对象。

补充

类的属性赋值的位置及顺序

1)默认初始化
2)显示初始化 3)代码块赋值
4)构造器赋值
5)通过对象调用属性的方法赋值
2和3并列

public class Test{
public static void main(String[] args){
          Person p = new Peson();
         System.out.println(p.number);
}
class Person{
        int number;//默认初始化
       //  int number = 10;//显示初始化
        {
        number =1;//代码块赋值
        }
public Person(int number){
        this.number = number;//构造器赋值
} 
        }
}

练习

1.

按要求实现下列问题:
1) 动物类Animal包含了抽象方法 abstract void shout();
2) Cat类继承了Animal,并实现方法shout,打印“猫会喵喵叫”
3) Dog类继承了Animal,并实现方法shout,打印“狗会汪汪叫”
4) 在测试类中实例化对象Animal a1 =new Cat(),并调用a1的shout方法
5) 在测试类中实例化对象Animal a2 =new Dog(),并调用a2的shout方法

public abstract class Animal {
    public abstract void shout();//抽象方法shout
}
public class Cat extends Animal {
    @Override//重写
    public void shout() {
        System.out.println("猫会喵喵叫");
    }
}
public class Dog extends Animal {
    @Override//重写
    public void shout() {
        System.out.println("狗会汪汪叫");
    }
}
public class Test {
    public static void main(String[] args) {
        Animal a1 = new Cat();//实例化
        a1.shout();//调用

        Animal a2 = new Dog();
        a2.shout();
    }
}

2.

定义一个抽象类Person,
有name,age,sex三个属性,创建构造函数,给这三个属性赋值,重写打印描述信息方法,打印三个属性值;这个类中有两个抽象方法work和hello;
定义两个子类Teacher,Student;教师的work实现是:教书育人,hello实现是:“同学好”;
学生的work实现是:认真学习,hello实现是“老师好”。

public abstract class Person {
    private String name;//姓名
    private int age;//年龄
    private String sex;//性别
    //构造函数
    public Person(){}
    public Person(String name,int age,String sex){
        this.name=name;
        this.age=age;
        this.sex=sex;
    }
    //设置获取姓名、年龄、性别
    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getSex() {
        return sex;
    }
    //打印输出三个属性
    public void show(){
        System.out.println("姓名:"+name+",年龄:"+age+",性别:"+sex);
    }
    //work抽象类
    public abstract void work();
    //hello抽象类
    public abstract void hello();

}
public class Student extends Person{
    @Override
    public void work() {
        System.out.println("学生的职责是认真学习");
    }

    @Override
    public void hello() {
        System.out.println("老师好");
    }
}
public class Teacher extends Person {
    @Override
    public void work() {
        System.out.println("老师的工作是教书育人");
    }

    @Override
    public void hello() {
        System.out.println("同学好");
    }
}
public class Test {
    public static void main(String[] args) {
        //学生
        Person p1 = new Student();
        p1.setName("罗辑");
        p1.setAge(22);
        p1.setSex("男");
        p1.show();
        p1.work();
        p1.hello();
        //教师
        Person p2 = new Teacher();
        p2.setName("叶文洁");
        p2.setAge(60);
        p2.setSex("女");
        p2.show();
        p2.work();
        p2.hello();
    }
}

3.

定义Shape抽象类,包含私有属性color,创建构造器为color赋值;包含计算周长的方法celPerimeter();定义子类Triangle,包含三边;定义子类Circle,包含半径radius;子类分别实现父类的计算周长功能。

public abstract class Shape {
    private String color;//私有属性颜色
    //构造器
    public Shape(){}
    public Shape(String color){
        this.color=color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String getColor() {
        return color;
    }

    //计算周长
    public abstract void celPerimeter();
}
public class Circle extends Shape{
    private double radius;//半径
    //有参赋值
    public Circle(double radius){
        this.radius=radius;
    }
    //周长
    @Override
    public void celPerimeter() {
        System.out.println(super.getColor()+"圆的周长:"+(6.28*radius));
    }
}
public class Triangle extends Shape{
    private double a,b,c;//三边
    //构造器赋值
    public Triangle(double a,double b,double c){
        this.a=a;
        this.b=b;
        this.c=c;
    }
    //计算周长
    @Override
    public void celPerimeter() {
        if(a+b>c && a+c>b && b+c>a) {
            System.out.println(super.getColor()+"三角形周长为:"+(a+b+c));
        }else{
            System.out.println("不构成三角形!");
        }
    }
}
public class Test {
    public static void main(String[] args) {
        //三角形
        Shape s1 = new Triangle(3,4,5);
        s1.setColor("红色");
        s1.celPerimeter();
        //圆
        Shape s2= new Circle(3);
        s2.setColor("蓝色");
        s2.celPerimeter();
    }
}

4.

编写工资系统,实现不同类型员工(多态)的按月发放工资。如果当月出现某个
Employee对象的生日,则将该雇员的工资增加100元。
实验说明:
(1)定义一个Employee类,该类包含:
private成员变量name,number,birthday,其中birthday 为MyDate类的对象;
abstract方法earnings();
toString()方法输出对象的name,number和birthday。
(2)MyDate类包含:
private成员变量year,month,day ;
toDateString()方法返回日期对应的字符串:xxxx年xx月xx日
(3)定义SalariedEmployee类继承Employee类,实现按月计算工资的员工处
理。该类包括:private成员变量monthlySalary;
实现父类的抽象方法earnings(),该方法返回monthlySalary值;toString()方法输
出员工类型信息及员工的name,number,birthday。
(4)参照SalariedEmployee类定义HourlyEmployee类,实现按小时计算工资的员工处理。该类包括:
private成员变量wage和hour;
实现父类的抽象方法earnings(),该方法返回wage*hour值;
toString()方法输出员工类型信息及员工的name,number,birthday。
(5)定义PayrollSystem类,创建Employee变量数组并初始化,该数组存放各类雇员对象的引用。利用循环结构遍历数组元素,输出各个对象的类型,name,number,birthday,以及该对象生日。当键盘输入本月月份值时,如果本月是某个Employee对象的生日,还要输出增加工资信息。

参考提示:
//定义People类型的数组People c1[]=new People[10];
//数组元素赋值
c1[0]=new People(“John”,“0001”,20);
c1[1]=new People(“Bob”,“0002”,19);
//若People有两个子类Student和Officer,则数组元素赋值时,可以使父类类型的数组元素指向子类。
c1[0]=new Student(“John”,“0001”,20,85.0);
c1[1]=new Officer(“Bob”,“0002”,19,90.5);
思路:
1)先定义Employee类,声明属性,注意 birthday的数据类型为MyDate,构造函数,定义set、get方法,抽象类earnings不需要方法体,最后定义方法toString进行输出信息。因为birthday是MyDate的对象,需要调用toDateString方法进行生日信息的输出。

public abstract class Employee {
    private String name;//姓名
    private int number;//编号
    private MyDate birthday;//生日
    //构造
    public Employee(){}
    public Employee(String name,int number,MyDate birthday){
        this.name=name;
        this.number=number;
        this.birthday=birthday;
    }
    //设置获取姓名编号生日
    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public int getNumber() {
        return number;
    }

    public void setBirthday(MyDate birthday) {
        this.birthday = birthday;
    }

    public MyDate getBirthday() {
        return birthday;
    }

    //工资
    public abstract double earnings();
    //输出
    public String toString(){
        return "姓名:"+name+",编号:"+number+",生日:"+birthday.toDateString();//birthday是MyDate对象调用方法输出
    }
}

2)定义MyDate类,私有年月日,构造方法,设置获取年月日,定义方法toDateString为String类型,返回输出生日字符串。

public class MyDate {
    //年月日
    private int year,month,day;
    //构造
    public MyDate(){}
    public MyDate(int year,int month,int day){
        this.year=year;
        this.month=month;
        this.day=day;
    }
    //设置获取年月日
    public void setMonth(int month) {
        this.month = month;
    }

    public int getMonth() {
        return month;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public int getYear() {
        return year;
    }

    public void setDay(int day) {
        this.day = day;
    }

    public int getDay() {
        return day;
    }

    //输出
    public String toDateString(){
        return year+"年"+month+"月"+day+"日";
    }
}

3)定义SalariedEmployee类,继承Employee类,声明私有月薪属性,构造方法,设置获取月薪,因为是抽象类Employee类的子类,所以需要重写earnings方法。

public class SalariedEmployee extends Employee {
    private double monthSalary;//月薪
    //构造
    public SalariedEmployee(){}
    public SalariedEmployee(String name,int number,MyDate birthday,double monthSalary){
        super(name, number, birthday);
        this.monthSalary=monthSalary;
    }
    //设置获取
    public void setMonthSalary(double monthSalary) {
        this.monthSalary = monthSalary;
    }

    public double getMonthSalary() {
        return monthSalary;
    }

    //工资
    @Override
    public double earnings() {
        return monthSalary;
    }
    //输出
    @Override
    public String toString() {
        return "员工类型:全职员工,"+super.toString();
    }
}

4)仿照SalariedEmployee类,earnings方法返回的是wage*hour,输出方法要标注员工类型。

public class HourEmployee extends Employee{
    private double wage;//时薪
    private double hour;//工作小时
    //构造
    public HourEmployee(String name,int number,MyDate birthday,double wage,double hour){
        super(name, number, birthday);
        this.wage=wage;
        this.hour=hour;
    }
    //设置获取
    public void setWage(double wage) {
        this.wage = wage;
    }

    public double getWage() {
        return wage;
    }

    public double getHour() {
        return hour;
    }

    public void setHour(double hour) {
        this.hour = hour;
    }

    //返回工资
    @Override
    public double earnings() {
        return wage*hour;
    }
    //输出
    public String toString() {
        return "员工类型:小时工,"+super.toString();
    }
}

5)测试类,键盘输入月份,定义Employee类型数组,创建对象并赋值,遍历输出对象。
这里判断需要的是输入的月份,和员工生日信息中的月份信息。

import java.util.Scanner;
public class PayrollSystem {
    public static void main(String[] args) {
        //键盘输入月份
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入本月月份:");
        int month = sc.nextInt();
        //创建Employee类型数组
        Employee e1[] = new Employee[2];
        //创建对象
        e1[0] = new SalariedEmployee("小红",001,new MyDate(2000,01,01),5000.0);
        e1[1] = new HourEmployee("小绿",002,new MyDate(1998,02,02),150,12);
        //遍历输出对象
        for(int i=0;i< e1.length;i++){
            System.out.println(e1[i].toString());
            System.out.println("月工资为"+e1[i].earnings());
            if(month == e1[i].getBirthday().getMonth()){//若是本月生日则增加工资并输出
                System.out.println("本月是"+e1[i].getName()+"的生日,月工资增加100后"+(e1[i].earnings()+100));
            }
        }
    }
}

5.

定义一个接口用来实现两个对象的比较。
interface CompareObject{
public int compareTo(Object o); //若返回值是 0 , 代表相等; 若为正数,代表当前对象大;负数代表当前对象小
}
定义一个Circle类,声明redius属性,提供getter和setter方法
定义一个ComparableCircle类,继承Circle类并且实现CompareObject接口。在ComparableCircle类中给出接口中方法compareTo的实现体,用来比较两个圆的半径大小。
定义一个测试类InterfaceTest,创建两个ComparableCircle对象,调用compareTo方法比较两个类的半径大小。
思 考 : 参 照 上 述 做 法 定 义 矩 形 类 Rectangle 和 ComparableRectangle 类 , 在
ComparableRectangle类中给出compareTo方法的实现,比较两个矩形的面积大小。

public class Circle {
    //声明半径
    private double radius;
    //构造
    public Circle(){}
    public Circle(double radius){
        this.radius=radius;
    }
    //设置获取半径
    public void setRadius(double radius) {
        this.radius = radius;
    }

    public double getRadius() {
        return radius;
    }
}
public interface CompareObject {
    public abstract int compareTo(Object o);
}

定义一个ComparableCircle类,继承Circle类并且实现CompareObject接口。在ComparableCircle类中给出接口中方法compareTo的实现体,用来比较两个圆的半径大小。

public class ComparableCircle extends Circle implements CompareObject{
    //构造
    public ComparableCircle(double radius){
       super(radius);
    }
    //重写
    @Override
    public int compareTo(Object o) {
        if(o instanceof ComparableCircle){//判断对象类型
           ComparableCircle c1 = (ComparableCircle) o;//给出实现体,比较圆半径大小
           if(this.getRadius() > c1.getRadius()){
               return -1;
           }else if(this.getRadius() < c1.getRadius()){
               return 1;
           }else{
               return 0;
           }
//            return this.getRadius().compareTo(c1.getRadius());
        }else{
            System.out.println("输入有误!");
            return 0;
        }
    }

}
public class InterfaceTest {
    public static void main(String[] args) {
        //创建两个对象
        ComparableCircle c1 = new ComparableCircle(3.1);
        ComparableCircle c2 = new ComparableCircle(3.2);
        //输出比较结果
        int r = c1.compareTo(c2);
        if(r > 0 ){//当前对象c2大
            System.out.println("c2半径比较大");
        }else if(r < 0){//被比较的对象c1大
            System.out.println("c1半径比较大");
        }else{
            System.out.println("c1和c2相等");
        }
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值