没有方法体的方法叫抽象方法,有抽象方法的类一定是抽象类。而抽象类就是对类进行抽象。在编写时,需要子类必须实现的属性和行为,可以在对父类进行一个抽象,抽象类的运用场景。
抽象类的特点主要有四点:
1)抽象类和抽象方法用abstract修饰;
2)抽象类中不一定有抽象方法,但有抽象方法的类一定是抽象类;
3)抽象类多态。抽象类不能直接实例化,要通过子类对象的实例化来实现。
4)抽象类的子类要么重写抽象类中所有的抽象方法,要么是抽象类。
分为三类:
1)成员变量。可以是变量,也可以是常量;
2)构造方法。可以有构造方法,但不能直接实例化。作用是用于子类访问父类数据的初始化。
3)成员方法。可以有抽象方法来限定子类必须完成某些操作,也可以有非抽象方法,提高代码的复用性(继承)。
一种公共的规范标准,只要符合就可以通用。就像现实中的USB接口一样,只要对应的插头,都可以接上。
而java中的接口体现在对行为的抽象。
接口的运用场景,当多人实现一个项目,每个人编写的功能模块会有重合的部分,这个时候可以使用接口,便于之后的汇总。
1)接口用interface来修饰;
2)类实现接口用implements来表示;
3)接口多态。接口不能直接实例化,要通过实现类对象实例化;
4)接口的实现类要么重写接口中的所有抽象方法,要么是抽象类;
1)成员变量。只能是常量,默认public static final;
2)构造方法。没有构造方法,因为接口是对行为的抽象,并不直接存在;一个类如果没有父类,那么默认继承Object类;
3)成员方法。在jdk8中有了新特性,除了抽象方法,接口中可以定义默认(default)实现方法和静态(static)方法。为了接口的实现类不用每个都重新实现新添加的接口方法,引入default默认实现,static的用法直接用接口名去调方法即可。
补充:“类优先”,当一个类继承了父类又实现接口,若它们的方法名相同,则优先继承父类中的同名方法,若要实现两个同名方法的接口,则要实现类手动声明默认实现哪个接口的方法。
1)抽象类。可以是变量,也可以是常量。可以有抽象方法,也可以有非抽象方法。
2)接口。只能是常量。只能是抽象方法。
1)类与类。继承关系,只能单继承,也可多层继承。
2)类与接口。实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口。
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) 动物类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();
}
}
定义一个抽象类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();
}
}
定义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();
}
}
编写工资系统,实现不同类型员工(多态)的按月发放工资。如果当月出现某个
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));
}
}
}
}
定义一个接口用来实现两个对象的比较。
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相等");
}
}
}