看完了面向对象的三大特性,接着我们进一步理解Java的抽象类
和接口
本篇介绍抽象类,下篇介绍接口
一、抽象类
抽象类 可以定义抽象方法, 同时 抽象方法必须存在于抽象类中
关键字:abstract
英文含义是"抽象的"
格式: abstract class 类名
1、抽象类的好处:
可以避免父类对某个方法进行实现,子类继承父类就必须重写抽象类中的抽象方法
抽象类不能创建对象: 抽象类用于被继承的类,可以定义抽象类的子类,由子类创建对象
2、抽象类的子类分类:
(1)子类重写了所有的抽象方法,子类就是一个普通类,可以创建对象
(2) 如果没有完全重写,此时还是一个抽象类,必须使用abstract关键字修饰,子类还是无法创建对象
抽象方法 例如 public abstract void eat();
abstract 修饰 有继承关系 需要被子类重写方法
- 只有方法的声明,没有方法的实现,没有大括号,在参数列表后直接加上分号
3、抽象类的特点
抽象类和抽象方法都需要使用abstract关键字
(1) 抽象方法:public abstract 返回值类型 方法名称(参数列表);
(2) 抽象类:abstract class 类名
4、抽象类方法的关系
(1) 抽象方法必须存在于抽象类中
(2) 抽象类中可以没有抽象方法
public class Demo01 {
}
//抽象方法必须存在于抽象类中
abstract class Pet{
public abstract void eat();
}
//被继承的Pet类中有抽象方法,抽象类的抽象方法,会强制要求子类一定要重写
class Dog extends Pet {
//父类中的抽象方法,子类必须进行重写,否则编译报错
@Override
public void eat() {
System.out.println("吃骨头");
}
}
class Cat extends Pet {
@Override
public void eat() {
System.out.println("吃猫粮");
}
}
class Monkey extends Pet {
@Override
public void eat() {
System.out.println("吃香蕉");
}
}
public class Demo02 {
public static void main(String[] args) {
// Fu f = new Fu();抽象类不能创建对象
Zi z = new Zi();
z.test1();
z.test2();
z.test3();
// Zi2 z2 = new Zi2();
}
}
abstract class Fu{//有抽象方法的类,一定是抽象类
public abstract void test1();
public abstract void test2();
//抽象类中不一定有抽象方法
public void test3(){
System.out.println("今天是周一,愉快的黑色星期一");
}
}
class Zi extends Fu{
//将光标放在报错的位置,alt+enter会提示解决问题的方式,选择即可
@Override
public void test1() {
System.out.println("实现了抽象方法test1");
}
@Override
public void test2() {
System.out.println("实现了抽象方法test2");
}
}
//如果一个抽象类中的抽象方法,子类没有完全实现,那么这个类还是一个抽象类,不能创建对象
abstract class Zi2 extends Fu{
@Override
public void test1() {
System.out.println("~~~~~~~~~~~");
}
}
3、注意事项
1、抽象类可以定义成员变量
(1) 抽象类可以定义成员变量,也可以定义常量,由于抽象类不能实例化,所以定义的属性不能被抽象类使用,但是能够被抽象类的子类去使用
2、抽象类能不能有构造方法
(1) 可以有构造方法,虽然不能创建对象,但是抽象类一般都会有子类,子类会访问父类的构造方法,来完成对父类的成员变量的初始化赋值
(2) 能否定义构造方法,不是取决于该类能否创建对象,关键在于能否定义成员变量,一个类能定义成员变量,那么就可以有构造方法
3、抽象类也可以有成员方法
(1) 抽象类也可以有成员方法,这里定义的方法,子类一般不会去重写
(2) 抽象方法的目的就是为了让子类重写
4、抽象类:一般适合用于定义事物先天具有的属性和行为,先天具备
public class Demo03 {
public static void main(String[] args) {
Person.say();
Student s = new Student("陈毅1");
System.out.println(s.name);
s.name = "陈毅";
System.out.println(s.name);
}
}
//人类作为只能用于被继承的类
abstract class Person{
//定义成员变量
int a = 20;
String name;
//定义常量
final int VERSION = 1;//final表示最终的不可修改的
//有成员变量,就初始化 默认显式构造
public Person(){}
public Person(String name){
this.name = name;
}
//抽象方法
public abstract void sleep();
//普通方法
public void eat(){
System.out.println("~~~~~~~~~~~干饭时间又快到了");
}
//抽象类中可以有静态方法,直接通过类名访问
public static void say(){
System.out.println("~~~~~~~~~~~~~");
}
}
class Student extends Person{
//此时默认会有一个空参
public Student(){
super();
}
//可以提供一个有参构造
public Student(String name){
super(name);
}
@Override
public void sleep() {
System.out.println("一起睡觉");
}
}
练习
1、定义宠物类:属性 姓名 性别 年龄 行为 吃 喝 睡
2、定义狗: 属性 姓名 性别 年龄 行为 吃 喝 睡 咬你的好朋友(他叫陈毅)
3、定义猫: 属性 姓名 性别 年龄 行为 吃 喝 睡 抓你的好朋友(他也叫陈毅)
package com.ujiuye.test;
public class Demo01 {
public static void main(String[] args) {
Cat c = new Cat("小黑","母",11);
c.catchC();
System.out.println(c.getName());
c.drink();
c.eat();
}
}
//1、定义宠物类:属性 姓名 性别 年龄 行为 吃 喝 睡
// 2、定义狗: 属性 姓名 性别 年龄 行为 吃 喝 睡 咬陈毅
// 3、定义猫: 属性 姓名 性别 年龄 行为 吃 喝 睡 抓陈毅
abstract class Pet{
private String name;
private String sex;
private int age;
public Pet() {
}
public Pet(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public abstract void eat();
public abstract void drink();
public void sleep(){
System.out.println("闭眼睛睡觉");
}
}
class Dog extends Pet{
public Dog() {
}
public Dog(String name, String sex, int age) {
super(name, sex, age);
}
@Override
public void eat() {
System.out.println("吃陈毅");
}
@Override
public void drink() {
System.out.println("喝水");
}
public void bite(){
System.out.println("咬陈毅");
}
}
class Cat extends Pet{
public Cat() {
}
public Cat(String name, String sex, int age) {
super(name, sex, age);
}
@Override
public void eat() {
System.out.println("吃猫粮");
}
@Override
public void drink() {
System.out.println("喝牛奶");
}
public void catchC(){
System.out.println("抓陈毅");
}
}
扩展: 模板设计模式
1、设计模式:是一种反复使用,多人知晓,经过分析编辑代码、代码设计经验的总结
2、使用设计模式的目的: 为了让代码更容易被别人理解,保证代码的可靠性和程序的重用性
3、模板设计模式:把抽象类整体看做一个模板,不能决定的内容 使用抽象方法表示,让使用模板的类【抽象类的子类】去重写抽象方法实现需求
4、好处:优势在于设定好通用的结构,使用者只需要直接拿着去用就可以,只需要关注自己实现的内容即可
public class Demo02 {
public static void main(String[] args) {
Mark m = new Mark();
m.write();
}
}
//作文模板类
abstract class Template{
//书写作文的方法
public void write(){
//书写作文的标题
System.out.println("陈毅和他的女朋友去放风筝");
//作文的正文
body();
//作文的结尾
System.out.println("放风筝可是真开心啊!!!");
}
//把作文的内容提取到一个方法中,方法如果有方法体正文就写死了,所以写成一个抽象方法
public abstract void body();
}
//模板使用者
class Mark extends Template{
@Override
public void body() {
System.out.println("今天风和日丽,陈毅和他的女朋友去公园放风筝,但是没有风筝,后来就陈毅就把他女朋友绑在线上放飞了");
}
}
补充:
1、多态关系的构建语法格式是? 父类的引用指向子类对象
2、多态的前提是? 先构建继承关系,没有继承就没有多态
3、多态访问成员方法的特点 编译看左运行看右
4、多态访问成员变量的特点 编译看左运行看左
5、多态的好处是什么 提高了代码的扩展性
6、什么是向上转型,什么是向下转型
多态的体现就是向上转型,父类的引用指向子类对象
恢复子类本身的访问范围,类型强制转换 子类类型 新对象名 = (子类类型)对象名;
7、抽象方法如何定义
public abstract 返回值类型 方法名称(参数列表);
8、抽象类和抽象方法有什么关系
抽象类中不一定有抽象方法,
抽象方法必须在抽象类中
9、抽象类和普通类有什么区别
多了抽象方法
不能创建对象
子类必须重写抽象类中的抽象方法
10、抽象类可以创建对象吗
不能
11、抽象类的子类一定能够创建对象吗
不一定
子类如果重写了所有的抽象方法 可以创建
如果没有全部重写父类的抽象方法,还是一个抽象类
12. 定义一个Man类, 属性有姓名, 方法: 开车
有一个公交车类Bus, 属性有:速度 方法有: 跑
有一个卡车类Truck, 属性有:速度 方法有: 跑
有一个跑车类SportsCar: 属性有:速度 方法有: 跑
要求:编写一个测试类: 创建一个Man对象,可以驾驭上面任意一款车型
Man m = new Man();
public class Demo01 {
public static void main(String[] args){
Man m = new Man();
m.name = "陈毅";
m.driverCar(new Bus(100));
m.driverCar(new SportsCar(30));
m.driverCar(new Truck(120));
}
}
//12. 定义一个Man类, 属性有姓名, 方法: 开车
// 有一个公交车类Bus, 属性有:速度 方法有: 跑
// 有一个卡车类Truck, 属性有:速度 方法有: 跑
// 有一个跑车类SportsCar: 属性有:速度 方法有: 跑
// 要求:编写一个测试类: 创建一个Man对象,可以驾驭上面任意一款车型
class Man{
String name;
public void driverCar(Car c){
c.run();
}
}
abstract class Car{
private int speed;
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public Car(int speed) {
this.speed = speed;
}
public abstract void run();
}
class Bus extends Car{
public Bus(int speed) {
super(speed);
}
@Override
public void run() {
System.out.println("摇摇晃晃" +getSpeed());
}
}
class Truck extends Car{
public Truck(int speed) {
super(speed);
}
@Override
public void run() {
System.out.println("横推一切" + getSpeed());
}
}
class SportsCar extends Car{
public SportsCar(int speed) {
super(speed);
}
@Override
public void run() {
System.out.println("风驰电掣" + getSpeed());
}
}
13.编一个Perosn, 包含属性姓名, 年龄, 行为:说话, 吃饭, 睡觉
Person有一个子类Student, 比Person多一个属性分数, 重写说话, 吃饭,睡觉的方法
Person有一个子类Teacher, 比Person多一个属性薪资, 重写说话, 吃饭,睡觉的方法
人类下每个子类对行为的实现均不相同
编写测试类Student和Teacher对象,并调用每个对象的方法.
public class Demo02 {
}
//13.编一个Perosn, 包含属性姓名, 年龄, 行为:说话, 吃饭, 睡觉
// Person有一个子类Student, 比Person多一个属性分数, 重写说话, 吃饭,睡觉的方法
// Person有一个子类Teacher, 比Person多一个属性薪资, 重写说话, 吃饭,睡觉的方法
// 人类下每个子类对行为的实现均不相同
// 编写测试类Student和Teacher对象,并调用每个对象的方法.
//
abstract class Person{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public abstract void say();
public abstract void eat();
public abstract void sleep();
}
class Student extends Person{
private int score;
public Student() {
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public Student(String name, int age, int score) {
super(name, age);
this.score = score;
}
@Override
public void say() {
System.out.println("谈天说地就是不聊学习");
}
@Override
public void eat() {
System.out.println("干饭人,干饭魂。吃最重要");
}
@Override
public void sleep() {
System.out.println("教室里睡的最香");
}
}
class Teacher extends Person{
private int salary;
public Teacher() {
}
public Teacher(String name, int age, int salary) {
super(name, age);
this.salary = salary;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
@Override
public void say() {
System.out.println("那叫一个说啊,一直说,一说六个小时");
}
@Override
public void eat() {
System.out.println("吃,也是最重要的,同是干饭人");
}
@Override
public void sleep() {
System.out.println("上班天天打瞌睡 不能睡");
}
}
14. 有如下代码,请问哪些是不正确的?( )
class ClassA{}
class ClassB extends ClassA{}
class ClassC extends ClassA{}
//BC是A的子类
ClassA p0 = new ClassA();//A类引用指向A类对象
ClassB p1 = new ClassB();//B类引用指向B类对象
ClassC p2 = new ClassC();//C类引用指向C类对象
ClassA p3 = new ClassB();//A类的引用指向B类的对象
ClassA p4 = new ClassC();//A类的引用指向C类的对象
// A类的引用 = B类的对象
p0 = p1; //合理
//sp1 = p2;//b类的引用 = C类的对象 BC都是子类 没有直接关系 所以不可以
//必须是父类的引用指向子类对象才可以
p1 = (ClassB)p3;//B类的引用 向下转型 将P3转为B类的引用B类的对象
p2 = (ClassC)p4;//同上