作业回顾
继承: 为了减少相同关联类的相关属性和方法,所抽取出来一个模板类【父类】,让当前抽取出来类和原有类产生关联,这种方式就是---》继承
提供继承信息的--》 父类 得到继承信息 --》 子类
Java中是单一继承,一个类只允许有一个直接父类,但是Java是允许间接继承【允许有爷爷辈..】
Java中若需要继承需要使用关键字 extends
语法:
public class 父类类名{
子类共有的属性
子类共有的方法
提供父类有参和无参构造方法
}
PS: 在外部操时候,父类是不会直接创建对象,不会这样做 父类 父类对象名 = new 父类();
父类--》"模板" --》就是提供信息使用 --》 父类"直接"创建对象意义不大
为了限制父类创建对象 --》 类的其他修饰符 ---》 abstract 关键字 --》 抽象类
public class 子类类名 extends 父类类名{
子类自身的属性和方法
可以继承到父类所提供的所有可见属性--》【只要不是private修饰】
子类无法继承父类的构造方法,所以子类需要提供自己的构造方法【无参和有参】
PS:子类实例化的过程--》先创建父类对象,然后在创建子类对象
子类构造方法默认调用父类构造方法
隐式调用:默认调用父类无参
显示调用:可以在子类使用super关键
super 关键字 在子类中代表是父类对象
--》 super.属性名 super.成员方法 --》 调用父类属性和父类方法
--》 在子类的构造方法中可以使用super()形式调用父类构造方法【根据传入的参数区分】
--》 super() 调用父类的构造方法,必须在子类构造方法第一句
--》PS:在开发中约定,this关键说明这个属性属于子类,使用super(有参构造方法)父类属性的创建
继承中一个专享的概念:子类可以重写父类的方法【不能重写父类使用以下任意一个修饰符修饰方法】
--》 "private、static、final"
--》 最低要求:1.必须和父类方法签名一致【方法+参数列表】
2.父类方法如何定义子类就如何定义
3.建议在子类重写方的位置上方添加一个注解 "@override"
--》 子类一旦重写父类方法,外部就无法直接获取到原有父类的实现,只能获取到子类重写之后效果
--》 非要调用:一种实在子类中使用 super 关键字 调用父类原有方法
直接创建父类对象,调用--》 否定,父类是不直接创建对象
--》为了防止你调用父类重写法方法,提供一个关键字 abstract --》抽象方法
原则问题:
"子类重写父类方法的原则:父类提供方法无法满足子类需求,此时子类就有权重写父类的方法"
"但是,如果父类方法使用以下任意修饰符,子类无权重写【private、static、final】"
1.直接打印对象的时候,是无法打印出对象中存的数据,只会打印出一个字符串
【包名+类名】类的全限定名称 + "@"+hashcode换算的十六进制
某些情况之下,我们需要打印对象的时候输出一些我们想要的"结果",此时原有对象输出就无法满足我们的需求
打印对象的"结果" 它所需要出发的方法是父类Object中的toString方法,就需要重写这个方法
2.引用类型比较问题,引用类型是不允许使用 == 进行比较 【比较的是两个对象地址】
所以引用类型需要使用API中提供equals方法
PS:"系统API类中,所有equals方法都实现完毕了【重写了父类Object所提供equals方法】"
自定义类所需要进行比较,需要重写父类所提供equals方法,才能比较引用类型是否相等
PS:"自定义类提供的equals方法只对当前类所创建出来的对象有用"
--》 equals重写原则,就是当前类中属性全部相等,或部分相等【属性中有,数组,集合,接口等等】
在重写equals比较相等对象时候,还有一天原则
--》"只要两个对象的equals是相等,那么他们的hashcode也要相等"
在重写equals的时候需要重写hashcode
hashcode的重写原则: 引用类型就调用其对应的hashcode值类型
"obejct 是所有类直接间接父类,所有类都是直接或间继承于Object "
"equals、hashcode、toString都是父类object所以提供,所以才可以重写"
}
1、机场安检系统,检查公民信息,如果信息是以下任意一个
姓名 ID
张学友, 9999
刘德华, 8888
郭富城, 7777
吴奇隆,6666
机场想起了警报,来了一群便衣将XXX带走了,否则祝XXX旅途愉快!
核心: 就是希望可以重写equals和hashcode
需要数组
一个公民类--> 提供基础信息 姓名和ID equals 和 hashcode重写
机场安监系统 --> 执行类
package com.qfedu.AirPortSystem;
import java.util.Objects;
/**
* 公民类
* PS:描述类【实体类】创建,分为两个派系
* 一个忠实拥护IDEA --》IDEA在整合一个插件 Lombok【口碑是两级分化】
* 一个是原始模板描述拥护
*
*/
public class Citizen {
//1.封装性,在类中体现,为了防止属性被恶意修饰,我们需要进行属性私有化private
//多行一次编辑 alt+shift+鼠标左键
private String name;
private String ID;
public Citizen() {
}
public Citizen(String name, String ID) {
this.name = name;
this.ID = ID;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getID() {
return ID;
}
public void setID(String ID) {
this.ID = ID;
}
//自定义公民信息打印
@Override
public String toString() {
return "公民姓名"+name+" 公民ID:"+ID;
}
//equals比较的类的属性值,所以当前类中,需要比较就是名字和ID都要完全一致
@Override
public boolean equals(Object o) {
//形参是Object类型即父类,可以接受任何子类传递,所以这里需要对父类进行--》对象的向下转型
Citizen other = (Citizen)o;
//因为name 是String类型,所以String类型中equals方法已经被重写了,所以可以只实用
//String中equals方法比较的字符串的内容
return this.name.equals(other.name) && this.ID.equals(other.ID);
}
@Override
public int hashCode() {
//引用类型使用hashcode+值类型直接使用
return name.hashCode() + ID.hashCode();
}
}
package com.qfedu.AirPortSystem;
/**
* 数据模拟类 , 存储数据使用
*/
public class CitizenDB {
//其实就是改名的工具类
private CitizenDB(){}
//随着类而加载属性并且是不可改变
private static final Citizen db[] = {
new Citizen("张学友","9999"),
new Citizen("刘德华","8888"),
new Citizen("郭富城","7777"),
new Citizen("吴奇隆","6666")};
//获取当前存储数据的公民数组
public static Citizen[] getCitizenDB(){
return db;
}
}
package com.qfedu.AirPortSystem;
import java.util.Scanner;
//机场安检系统
public class AiPortSystem {
public static void main(String[] args) throws InterruptedException {
System.out.println("-------------------------------欢迎进入机场安检系统--------------------------------");
Scanner input = new Scanner(System.in);
System.out.println("请输入您的姓名:");
String name = input.next();
System.out.println("请输入您的ID号:");
String ID = input.next();
Citizen c = new Citizen(name,ID);
System.out.println("--------------------------------请稍等正在验证您的信息-----------------------------------");
Thread.sleep(2000);
if(checkCitizenInfo(c)){
//这里直接打印了c 对象,想打印c的信息,所以需要从写toString
System.out.println("机场响起警报,"+c+"被便衣带走了.....");
}else{
System.out.println("祝:"+c.getName()+"旅行愉快....");
}
}
private static boolean checkCitizenInfo(Citizen c){
//获取存储在数组中数据进行比较
for(int i = 0 ;i<CitizenDB.getCitizenDB().length;i++){
//这里是通过equals比较公民信息的,所以需要重写equals和hashcode
if(CitizenDB.getCitizenDB()[i].equals(c)){
return true;
}
}
return false;
}
}
2.需求:
凹凸曼 1个
名字
血量
普通 必杀 一次只能打1只 随机大一只活着小怪兽
魔法 所有
凹凸曼的攻击 10%必杀 30%魔法 60%普攻
小怪兽 4只
名字
血量
普通
回合制游戏
输出:
======== 第X回合 ========
XXX凹凸曼 血量XXX
使用了 魔法攻击全体/普攻,XXX小怪兽/必杀,XXX小怪兽
XXX小怪兽 血量XXX
XXX小怪兽 血量XXX
XXX小怪兽 血量XXX
XXX小怪兽 血量XXX
小怪兽使用了普攻
凹凸曼血量为0,小怪兽胜利
所有的小怪兽都死了,凹凸曼胜利
凹凸曼 普攻和必杀不能攻击死了小怪兽 随机
魔法无所谓 小怪兽的血量不能出现负数 0
小怪兽 死了小怪兽不能攻击 0
package com.qfedu.game;
/**
* 奥特曼的类
*/
public class Ultraman {
//属性
private String name;
private int hp;
//提供有参和无参构造方法
public Ultraman() {
}
public Ultraman(String name, int hp) {
this.name = name;
this.hp = hp;
}
//get和set
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getHp() {
return hp;
}
public void setHp(int hp) {
this.hp = hp;
}
//普通攻击[一次一只]
public void attack(Monster m){
//伤害计算 20~29产生的伤害
int injury = (int)(Math.random()*10+20);
//获取 小怪兽的血量
int hp = m.getHp();
hp -= injury;
//如果小怪兽的血量只有10,会出现负数,但是打印的时候只能个出现0
if(hp >= 0){
m.setHp(hp);
}else{
m.setHp(0);
}
}
//必杀[一次一只]
public void Hugeattack(Monster m){
//伤害计算 先判断小怪兽血量4分之3之上一次就攻击4分3 否则固定输出60
int injury =(int)(m.getHp()*0.75) > 60 ? (int)(m.getHp()*0.75) : 60;
//获取 小怪兽的血量
int hp = m.getHp();
hp -= injury;
//如果小怪兽的血量只有10,会出现负数,但是打印的时候只能个出现0
if(hp >= 0){
m.setHp(hp);
}else{
m.setHp(0);
}
}
//魔法攻击[全体]
public void Magicattack(Monster[] ms){
for(Monster m : ms) {
//获取 小怪兽的血量
int hp = m.getHp();
hp -= 30;
//如果小怪兽的血量只有10,会出现负数,但是打印的时候只能个出现0
if (hp >= 0) {
m.setHp(hp);
} else {
m.setHp(0);
}
}
}
}
package com.qfedu.game;
/**
* 小怪兽的类
*/
public class Monster {
//属性
private String name;
private int hp;
//提供有参和无参构造方法
public Monster() {
}
public Monster(String name, int hp) {
this.name = name;
this.hp = hp;
}
//get和set
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getHp() {
return hp;
}
public void setHp(int hp) {
this.hp = hp;
}
//普通攻击
public void attack(Ultraman u){
//伤害计算 10~19产生的伤害
int injury = (int)(Math.random()*10+10);
//获取 小怪兽的血量
int hp = u.getHp();
hp -= injury;
//如果小怪兽的血量只有10,会出现负数,但是打印的时候只能个出现0
if(hp >= 0){
u.setHp(hp);
}else{
u.setHp(0);
}
}
}
package com.qfedu.game;
//小怪兽工具类
public class MonsterUtils {
//1. 构造方私有化
private MonsterUtils(){}
/*
挑选一只小怪兽
*/
public static Monster selectMonster(Monster[] ms){
//1.声明一个小怪兽对象,但是不赋值
Monster m;
do {
//先获取下标
int index = (int)(Math.random()*ms.length);
m = ms[index];
}while(m.getHp() == 0);
return m;
}
/*
判断是否还有活着的小怪兽
*/
public static boolean aliveMonster(Monster[] ms){
for(Monster m : ms){
if(m.getHp() > 0){
return true;
}
}
return false;
}
}
package com.qfedu.game;
//游戏执行
public class GameTest {
public static void main(String[] args) {
//1.先做先期准备
//1.1需要有奥特曼
Ultraman u = new Ultraman("5哥",1000);
//1.2创建4只小怪兽并存储到数组
String[] names = {"提莫","巨兔","腐儿","团子"};
//1.3将小怪兽存储到数组中
Monster[] monsters = new Monster[4];
for(int i = 0 ;i<monsters.length;i++){
Monster m = new Monster(names[i],300);
monsters[i] = m;
}
//2.开始游戏
//2.1设置回合数
int round = 1;
//执行操作
do {
System.out.println("=========================第"+round+"回合======================");
//2.2要求: 60% 普通 30% 魔法 10% 必杀
//随机数 [0~9) 范围
int p = (int)(Math.random()*10);
//if这套逻辑就是奥特曼攻击
if(p<6){//60% 普通 0 1 2 3 4 5
//2.3随机挑选一只或者的小怪兽
Monster m = MonsterUtils.selectMonster(monsters);
//2.4奥特曼攻击小怪兽
u.attack(m);
System.out.println(u.getName()+"使用了普通攻击"+m.getName());
}else if(p < 9){// 30% 魔法 6 7 8
//2.5 奥特曼魔法攻击小怪兽
u.Magicattack(monsters);
System.out.println(u.getName()+"使用了魔法攻击");
}else{//10% 必杀 9
//2.6随机挑选一只或者的小怪兽
Monster m = MonsterUtils.selectMonster(monsters);
//2.7奥特曼必杀攻击小怪兽
u.Hugeattack(m);
System.out.println(u.getName()+"使用了必杀攻击"+m.getName());
}
//小怪兽攻击
for(Monster m : monsters){
//只有活着的才可以攻击
if(m.getHp()>0){
m.attack(u);
}
}
System.out.println("小怪兽使用了普通攻击"+u.getName());
//打印结果值
System.out.println(u.getName()+"奥特曼HP是:"+u.getHp());
for(Monster m : monsters) {
System.out.println(m.getName()+"小怪兽HP是:"+m.getHp());
}
//回合+1;
round +=1;
//循环停止条件 ,只要一方死亡即可
}while(u.getHp()>0 && MonsterUtils.aliveMonster(monsters));
//循环已停止游戏自然结束
if (u.getHp()>0){
System.out.println("奥特曼胜利!!!");
}else{
System.out.println("小怪兽胜利!!!");
}
}
}
面向对象之多态
final关键字
final关键字的作用可以修饰**【变量、方法、类】**
1.final关键字修饰变量,这个变量就会变为**【定义】常量**
PS:final关键字即可以修饰全局也可以修饰局部
2.final修饰方法,这个方法被修饰之后只能被继承,不能被重写
3.final修饰类,这类就是终类【最终的类】,不可被继承
PS:final修饰类是类的两个其他修饰符中一个,类其他修饰符不能共存
package com.qfedu.Final;
/**
* final关键字的演示使用
*/
public class FinalTest {
//final修饰变量将变成 定义常量已经赋值 无法修改
//1.它可以修饰成员变量和静态变量,但是必须赋值【静态变量除外,需要配合使用静态代码块】
//PS:固定:常量和变量的分区,在名字上进行区分,变量名都小写, 常量都要大写比,并且每个单词之间使用_分隔
final int A = 10;
static final double PI = 3.14;
public static void main(String[] args) {
//允许修饰局部变量
final int AA = 10;
//PS:修饰局部变量的时候,它允许这样做
final int BB;
BB = 11; //这个赋值只能进行一次
}
}
//修饰符类的方法
class Father{
public final void show(){
System.out.println("让继承不让重写");
}
}
class Son extends Father{
//防止子类重写一些不能重写的方法
// public void show(){
//
// }
public static void main(String[] args) {
//允许被继承
new Son().show();
}
}
//修饰类,不可被继承 ,API中存在这个操作,实际类中少很少除非限制工具类
final class SuperClass{}
//class SubClass extends SuperClass{}
多态
PS:多态产生必须有继承关系
什么是多态?
【多种状态】同一个事物被不同对象所触发得到结果不同称之为【多态】
PS:
例如:一个父类,生出了一个女儿和一个儿子,两个孩子都是正常生产,但是女儿长得好看,儿子长得就有有点…
cut词,如果是导演听到了停止拍摄,如果理发师听到这个理发
在Java中多态分为两种
1.方法多态:同一个方法被不同参数所触发得到结果是不一样【即重载】
public int add(int a,int b)
public double add(double a,double b)
2.对象多态:同一个事物被不同对象所触发得到结果不同【必要前提,必须有继承】
事物--》 行为 --》方法
同一个方法别不同对象所触发得到结果是不一样的
如何得到不同对象? 同一个方法-->子类重写
多态概念中,提供一个软件设原则**【里氏代转换原则】**
里氏代转换原则
是对象中对多态概念的一个补充,这个概念的核心是允许【对象执行向上和向下转型】,如果要做对象向上和向下转型,需要依托于一个关系,类与类之间的而继承关系
对象的向上转型
父类的引用【对象】可以接收一个子类引用【对象】,子类会被自动提升为父类类型
注意:此时只能调用父类里面提供属性和方法,不能调用子类特有属性和方法
语法:
PS:"这个语法也是父类对象唯一创建对象方式"
父类类型 对象名 = new 子类类型();
"前提:必须是继承关系,父类与子类"
案例:
年终Boss让所有员工进行一下自我介绍,自己薪水
经理 底薪+奖金
销售 底薪+提成
普通员工 底薪+补贴
package com.qfedu.polymorphic;
//创建一个员工类 --> 父类
public class Employee {
private int salary;
public Employee() {
}
public Employee(int salary) {
this.salary = salary;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
/*
父类提供一个空方法,主要是计算薪水使用,因为每个子类计算方式都不一样,此时父类提供实现
*/
public int addMoney(){
return 0;
}
}
package com.qfedu.polymorphic;
/**
* 经理类,只要不是老板都是员工
*/
public class Manager extends Employee{
private int jiangjin;
private String name;
public Manager(){}
public Manager(String name,int jiangjin,int salary){
super(salary);
this.jiangjin = jiangjin;
this.name = name;
}
//因为要介绍自己的薪水所以需要提供一个计算薪水的方式
public int getJiangJin(){
return jiangjin;
}
@Override
public int addMoney() {
return getSalary()+jiangjin;
}
@Override
public String toString() {
return "经理名字:" + name+"薪水:"+addMoney();
}
}
package com.qfedu.polymorphic;
/**
* 销售
*/
public class Sell extends Employee {
private int ticheng;
private String name;
public Sell(){}
public Sell(String name,int ticheng,int salary){
super(salary);
this.ticheng = ticheng;
this.name = name;
}
//因为要介绍自己的薪水所以需要提供一个计算薪水的方式
@Override
public int addMoney() {
return getSalary()+ticheng;
}
@Override
public String toString() {
return "销售名字:" + name+"薪水:"+addMoney();
}
}
package com.qfedu.polymorphic;
/**
* 普通员工
*/
public class Staff extends Employee {
private int butie;
private String name;
public Staff(){}
public Staff(String name,int butie,int salary){
super(salary);
this.butie = butie;
this.name = name;
}
//因为要介绍自己的薪水所以需要提供一个计算薪水的方式
@Override
public int addMoney() {
return getSalary()+butie;
}
@Override
public String toString() {
return "普通员工名字:" + name+"薪水:"+addMoney();
}
}
package com.qfedu.polymorphic;
//测试类
public class BossTest {
public static void main(String[] args) {
System.out.println("-----------------年会中自我介绍-----------------");
BossTest bt = new BossTest();
Manager m = new Manager("小白",20000,30000);
bt.showInfosEmployee(m);
Sell sell = new Sell("小红",100000,1);
bt.showInfosEmployee(sell);
Staff staff = new Staff("小花",1000000,20000000);
bt.showInfosEmployee(staff);
}
//除了老板 都是员工 对象向上转型
/*
Employee e = m --> Employee e = new Manager("小白",20000,30000);
Employee e = sell --> Employee e = new Sell("小红",100000,1);
Employee e = staff --> Employee e = new Staff("小花",1000000,20000000);
*/
public void showInfosEmployee(Employee e){
System.out.println(e);
}
// public void showInfosManager(Manager m){
// System.out.println(m);
// }
// public void showInfosSell(Sell sell){
// System.out.println(sell);
// }
// public void showInfosStaff(Staff staff){
// System.out.println(staff);
// }
}
对象的向下转型
将已经被提升为父类类型对象,转换为原有子类类型
注意:此时不仅可以调用父类中所提供属性和行为,也可以调用自身的属性和行为
语法:
PS:"向下转型的前提一定是已经被提升过后的对象【向上转型】"
子类类型 对象名 = (子类类型)被提升为父类类型对象;
案例:
package com.qfedu.polymorphic;
//父类
public class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = 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;
}
}
package com.qfedu.polymorphic;
//子类猫类
public class Cat extends Animal {
public Cat() {
}
public Cat(String name, int age) {
super(name, age);
}
public void show(){
System.out.println("猫吃鱼");
}
}
package com.qfedu.polymorphic;
//子类狗类
public class Dog extends Animal {
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
public void show(){
System.out.println("狗吃肉");
}
}
package com.qfedu.polymorphic;
public class AnimalTest {
public static void main(String[] args) {
//1.对象的向上转型
Animal a1 = new Dog("小白",19);
Animal a2 = new Cat("小花",20);
//此时就已经发生了对象的向上转型,子类自动被提升为父类类型,仅能调用属性和行为
System.out.println(a1.getName());
//2.对象的向下转型
//有一个先决条件,必须是被提升为父类类型的对象,才可以向下转型
//只要语法对,编译时期,是不会报错,但是这里存在一个问题a2并不是Dog类型,是Cat
//强制类型转换异常ClassCastException
// Dog dog = (Dog)a2;
// dog.show();
//为了避免强制类型转换异常 Java中提供一个关键字可以用来检查对象数据类型 instanceof
/*
语法:
转型对象 instanceof 转型类型 得到一个判断结果
如果转型对象是转型类型的,返回true ,如果不是返回为false
*/
if(a2 instanceof Dog){
Dog dog = (Dog)a2;
dog.show();
}else{
System.out.println("无法强制类型转换,因为a2不是Dog类型");
}
//这种操作是完全错误
Animal a3 = new Animal();//父类类型对象
Cat cat = (Cat)a3;//不能转换
Cat cat1 = new Cat();//不能提升
}
}
PS:集合或接口的实现,数据传参,多态的应用场景
多态成员变量和成员方法方法问题
package com.qfedu.polymorphic;
class Father{
public int num = 10;
public void show(){
System.out.println("父类的show方法");
}
public Father(){}
}
class Son extends Father{
//开发绝对禁止出现子类属性和父类同名
public int num = 20;
public Son(){}
@Override
public void show() {
System.out.println("子类重写的show方法");
}
}
public class ValueAndMethod {
public static void main(String[] args) {
//1.对象的向上转型
Father f = new Son();
//当前f是被提升之后父类型, 只能调用父类属性和方法
//属性不存在重写
System.out.println(f.num);
//重写之后,必然执行子类实现方式
f.show();
//2.对象的向下转型,必然会成为子类,技能调用父类属性和方法,也能调用字节的属性和方法
Son s = (Son)f;
//既然已明确类型是子类,所以s触发的num是自身空间中num值
System.out.println(s.num);
s.show();//子类重写方法
}
}
抽象类和抽象方法
PS:抽象类就是一个特殊的父类
父类看做时一个模板,在这个模板上进行添加这个类是子类【子类会继承父类所有可见属性和行为,并且可以父类的基础上记性添加修改】
在实际开发中,父类是不会直接创建对象的【父类 对象 = new 父类()】;
现阶段,是无法防止父类直接创建对象,那么有没有什么方式即能保证父类不直接创建对象,又能保证保持原有父类的特点,Java中就提供了一个特殊类,这个类就叫做–》【抽象类】
在实际开发中,子类是可以重写父类方法的,**父类提供某些方法,子类必然重写,父类提供方法,每个子类的实现方式都不一样,父类无法给出正确实现方式,**如果单纯会将父类方法定义不实现,会出现一些问题
1.例如某些子类忘记了重写父类方法,此时子类重写不会做任何提示的
2.不仅忘记重写而且父类会对方法进行实现,此时子类调用了这个方法,必然会执行出现错误
Java为了解决这个问题,提供了一个特殊的方法 --》【抽象方法】
PS:抽象方法只能存在在抽象类
抽象类就是用来被继承的,而提供被继承的类都是父类,所以建议创建父类的时候设置成抽象类,父类提供方法,子类必然重写,建议将当前方法设置成抽象方法
语法说明:
ps:
"1.使用到一个关键字 abstract,这个关键字,只能修饰类和方法"
"2.这个关键字不能和final共存"
"3.创建抽象类"
访问权限修饰符 abstract class 类名{
如何定义父类就如何定义这个类
子类的共有属性和方法
构造方法
getter和setter
抽象类中是允许书写抽象方法
}
"4.创建抽象方法,绝对不允许有方法体并且是以[;]作为结尾"
访问权限修饰符 abstract 返回值类型 方法名 (参数列表);
"5.抽象方法必须存在在抽象类中,抽象类中可以不存在抽象方法"
案例:
package com.qfedu.Abstract;
public abstract class SunFlowerBible {
private String name;
public SunFlowerBible(){}
public String getName() {
return name;
}
public void show(){}
public static void showInfos(){}
public abstract void liangong();
}
package com.qfedu.Abstract;
public class Yuebuqun extends SunFlowerBible {
@Override
public void liangong() {
System.out.println("啊......疼.......完蛋了.....后悔了!");
}
}
package com.qfedu.Abstract;
public class Test {
public static void main(String[] args) {
//1.抽象类是一个特殊父类,所以支持多态特性
// SunFlowerBible sunFlowerBible = new SunFlowerBible();
SunFlowerBible sfb = new Yuebuqun();
}
}
抽象类的特点
"1.抽象类是一个特殊的父类,特殊在于不能直接创建对象【含义: 父类 父类对象 = new 父类()】,但是支持多态的特性,允许对应进行向上和向下转型操作"
"2.抽象类和抽象方法,不能和private、static和final关键字共存"
"3.抽象类可以作为方的参数数据类型存在,也可以作为返回值类型存在"
"4.一个普通类若继承于一个抽象类,必须实现类中所有的抽象方法"
abstract class A{
public abstract void show();
}
class B extends A{
@Override
public void show(){
}
}
"5.抽象类与抽象类之间是存在继承关系,一个抽象类继承于另外一个抽象类,此时抽象子类即可以实现父类中抽象方法,也可以不实现,并且还可以继续提供抽象方法"
abstract class A{
public abstract void show();
}
abstract class B extends A{
//可以实现父类抽象方法也可以不实现
//并且还可以继续提供抽象方法
public abstract void display();
}
PS:"无论如何继承普通类都要实现没有实现抽象方法,并且如果已经有重写过的方法,后续的子类可以继续继续重写"
abstract class A{
public abstract void show();
}
abstract class B extends A{
//可以实现父类抽象方法也可以不实现
@Override
public void show() {
}
//并且还可以继续提供抽象方法
public abstract void display();
}
class C extends B{
@Override
public void show() {
}
@Override
public void display() {
}
}
接口
PS:接口就是一个特殊的抽象父类
硬件接口
指的是两个硬件之间设置的连接方式,硬件接口包括逻辑上和物理上,硬件接口最常见的体现就是【USB接口】
软件接口
软件接口是一个特殊的类,类中存在一些规范,这些规范都是等待实现着来实现
例如:
鸟会飞,飞机也会飞,通过代码描述这个两个对象时候,可以发都具备飞行的行为,但是两者之间没有客观现实存在逻辑,所以就不可能抽取出一个父类,这个父类一共飞行方法,此时就可以提供一个解决方法,提供一个飞行规范【飞行接口】,这要在这里提供一个飞行方法,谁需要飞行,必须遵守这个规则,即【实现】这个非常接口
PS:接口可以想象成一个规范,规定一些事物的原则,若需要实现调用当前事物,必须实现接口
JDK1.8之前
接口的定义:interface 关键字
public interface 接口名{
全局静态常量
抽象方法
}
package com.qfedu.Interface;
/**
* 接口名字的规则,如果名字的在第一个字母是I,就不需要做任何任何操作
* 如果第一个字母不是I,就建议在名字的前面添加一个 大写的I字母
* 这样的目的是表示这个文件是接口文件
*/
public interface ISunFlowerBible {
//1.8之前可以在接口中定义的式
//全局静态常量 在接口中定义存在默认修饰 public static final
String BOOK_NAME = "葵花宝典";
//等价于 public static final String BOOK_NAME = "葵花宝典";
//抽象方法,默认修饰 public abstract
void liangong();
//等价于 public abstract void liangong();
}
package com.qfedu.Interface;
/*
接口是规范,如果需要实现规范就需要使用类实现接口
这个类要是实现接口,这个类的名字必须添加Impl作为名字结尾
接口是 【实现】 不是 【继承】 --》所以使用关键字需要改变 implements
只要普通类实现接口,就必须实现接口中抽象方法
*/
public class PersonImpl implements ISunFlowerBible{
@Override
public void liangong() {
System.out.println("武功秘籍:"+BOOK_NAME);
System.out.println("......");
}
}
class Demo{
public static void main(String[] args) {
//接口是一个特殊的抽象父类
/*
1.接口可以定义抽象方法
2.接口主要是用来实现的和抽象父类类似,抽象父类是用来继承
3.接口不能直接创建对象
4.接口支持多态,可以当做父类来使用,作为接口值或,作为方法的返回值类型和参数类型
*/
//ISunFlowerBible is = new ISunFlowerBible();
//这种方式必须是接口实现类否则不允许
ISunFlowerBible is = new PersonImpl();
}
}
JDK1.8之后
接口的定义:interface 关键字
public interface 接口名{
全局静态常量
抽象方法
//增加了两个方法
default 方法 --》可以有方法体 --》相当于是类中成员方法
static 方法 --》可以有方法体 --》相当于是类中静态方法
}
package com.qfedu.Interface;
//JDK1.8中的实现方式
public interface InterfaceForJDK1_8 {
//和1.8之前一样的 全局静态常量和抽象方法
int NUM = 10;
void show();
//这两个两个方法默认是public,default方法相当于是 类中成员方法
// static方法相当于是 类中静态方法
//允许有方法体
default void showInfosDefault(){
System.out.println("接口中default方法");
}
static void showInfosStatic(){
System.out.println("接口中static方法");
}
}
package com.qfedu.Interface;
//JDK1.8中的实现方式
public interface InterfaceForJDK1_8 {
//和1.8之前一样的 全局静态常量和抽象方法
int NUM = 10;
void show();
//这两个两个方法默认是public,default方法相当于是 类中成员方法
// static方法相当于是 类中静态方法
//允许有方法体
default void showInfosDefault(){
System.out.println("接口中default方法");
}
static void showInfosStatic(){
System.out.println("接口中static方法");
}
}
接口特点
"1.一个类可以实现多个接口【如果是普通类,需要实现接口中所有抽象方法,如果是抽象类,可以选择实现和不实现】"
public interface InterfaceA{
void showA();
}
public interface InterfaceB{
void showB();
}
public class InterfaceImpl implements InterfaceA,InterfaceB{
//需要实现接口中所有抽象方法
}
public abstract class InterfaceImpl implements InterfaceA,InterfaceB{
//既可以实现也可以不实现,在于抽象类中可以存在抽象方法
}
"2.一个类即可以继承一个类同时可以实现多个接口"
class C{}
public class InterfaceImpl extends C implements InterfaceA,InterfaceB{
//需要实现接口中所有抽象方法
}
"3.接口之间是存在继承关系,接口是可以单继承和多继承,继承过程中不允许出现相同方法名"
public interface A{}
public interface B{}
public interface C extends A{}
public interface D extends A,B{}
"4.接口是不能直接创建对象,但是允许使用多态【必须是接口实现类】,接口是引用类型,所以可以作为方法的返回值和参数类型"