day09.抽象 多态 接口
课前回顾:
1.封装
this:代表当前对象,哪个对象调用this所在的方法,this就代表哪个对象
区分重名的成员变量和局部变量
无参构造:
new 对象
不写jvm默认给一个
有参构造:
new 对象
为属性赋值
如果写了有参构造,无参构造就没了,所以我们都手写上
标准的javabean:私有属性 无参构造 有参构造 get/set方法
2.继承:
关键字:extends
成员访问特点:
成员变量:看等号左边是谁先调用谁
成员方法:看new的是谁先调用谁,子类没有找父类
重写:
前提:有子父类继承关系
使用场景:功能的增强,更新
特点:
继承只支持单继承,不能多继承
继承支持多层继承
一个父类可以拥有多个子类
3.super和this
super:代表父类对象
调用父类的构造:super()->super必须在构造第一行
调用父类的成员变量:super.成员变量名
调用父类的成员方法:super.成员方法名
this:代表的当前对象
调用当前类的构造:this()->this也要在构造第一行,所以,不能和super一起使用
调用当前类的成员变量:this.成员变量
调用当前类的成员方法:this.成员方法
4.代码块:
构造代码块
{
代码
}
优先于构造方法执行,且每new一次,构造代码块就执行一次
静态代码块:
static{
}
优先于构造方法和构造代码块执行的,只执行一次
今日内容:
1.会定义抽象类,以及会利用子类去实现抽象方法
2.知道抽象类的特点
3.会在多态的前提下访问成员
4.知道多态的好处
5.会定义接口,在接口中定义抽象方法,成员变量,默认方法,静态方法
6.会定义实现类实现接口
第一章.抽象
1.抽象的介绍
1.抽象方法怎么形成:
当将所有类的共性方法抽取到父类中,发现方法无法做具体实现(因为每个子类对这个方法的实现不一样),所以此方法抽取出来之后就可以定义为"抽象方法"
2.抽象类怎么形成:
抽象方法所在类一定是抽象类
3.抽象类和抽象方法是一种代码设计理念
因为抽象方法抽取出来之后,可以作为一个标准,规定,凡是我的子类都必须拥有这个方法,且必须要去做具体实现
4.抽象类和抽象方法的特点
a.抽象方法所在的类一定是抽象类
b.抽象类中不一定非得有抽象方法
(还可以包含:私有属性,构造,普通的成员方法)
c.子类继承抽象父类,需要重写父类中的抽象方法
d.抽象类不能直接new对象,需要通过子类做具体实现
1.关键字:abstract->抽象
2.抽象类的定义:
public abstract class 类名{
}
3.抽象方法:
public abstract 返回值类型 方法名();
4.注意:
抽象方法必须要重写
public abstract class Animal {
public abstract void eat();
}
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗啃骨头");
}
}
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
public class Test {
public static void main(String[] args) {
//Animal animal = new Animal();抽象类不能直接new对象
Dog dog = new Dog();
dog.eat();
System.out.println("================");
Cat cat = new Cat();
cat.eat();
}
}
2.抽象的注意事项
1.抽象类不能直接new对象的,只能创建其非抽象子类的对象。
2.抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员(属性)使用的。
3.抽象类中,可以有成员变量。
4.抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
5.抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。
public abstract class Animal {
private String name;
private String color;
public Animal() {
}
public Animal(String name, String color) {
this.name = name;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
//定义抽象方法
public abstract void eat();
public abstract void drink();
}
public class Dog extends Animal{
public Dog() {
}
public Dog(String name, String color) {
super(name, color);
}
@Override
public void eat() {
System.out.println("狗啃骨头");
}
@Override
public void drink() {
System.out.println("狗喝水");
}
}
public abstract class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
public class Test {
public static void main(String[] args) {
Dog dog = new Dog("二哈", "黑白");
}
}
第二章.综合案例
某IT公司有多名员工,按照员工负责的工作不同,进行了部门的划分(研发部、维护部)。
研发部(Developer)根据所需研发的内容不同,又分为 JavaEE工程师 、Android工程师 ;
维护部(Maintainer)根据所需维护的内容不同,又分为 网络维护工程师 、硬件维护工程师 。
公司的每名员工都有他们自己的员工编号、姓名,并要做它们所负责的工作。
工作内容:
- JavaEE工程师: 员工号为xxx的 xxx员工,正在研发淘宝网站
- Android工程师:员工号为xxx的 xxx员工,正在研发淘宝手机客户端软件
- 网络维护工程师:员工号为xxx的 xxx员工,正在检查网络是否畅通
- 硬件维护工程师:员工号为xxx的 xxx员工,正在修复打印机
请根据描述,完成员工体系中所有类的定义,并指定类之间的继承关系。进行XX工程师类的对象创建,完成工作方法的调用。
方式1:利用set赋值
//员工类
public abstract class Employee {
private int id;
private String name;
public Employee() {
}
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//抽象方法
public abstract void work();
}
//研发部
public abstract class Developer extends Employee{
}
public class JavaEE extends Developer{
@Override
public void work() {
System.out.println("编号为:"+this.getId()+"的"+this.getName()+"员工正在搞网站");
}
}
public class Android extends Developer{
@Override
public void work() {
System.out.println("编号为:"+getId()+"的"+getName()+"员工正在搞APP");
}
}
public class Test {
public static void main(String[] args) {
JavaEE javaEE = new JavaEE();
//为属性赋值
javaEE.setId(1);
javaEE.setName("柳岩");
javaEE.work();
System.out.println("===========");
Android android = new Android();
android.setId(2);
android.setName("杨幂");
android.work();
}
}
方式2:利用构造赋值
//员工类
public abstract class Employee {
private int id;
private String name;
public Employee() {
}
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//抽象方法
public abstract void work();
}
public abstract class Developer extends Employee{
public Developer() {
}
public Developer(int id, String name) {
super(id, name);
}
}
public class JavaEE extends Developer{
public JavaEE() {
}
public JavaEE(int id, String name) {
super(id,name);
}
@Override
public void work() {
System.out.println("编号为:"+this.getId()+"的"+this.getName()+"员工正在搞网站");
}
}
public class Android extends Developer{
public Android() {
}
public Android(int id, String name) {
super(id, name);
}
@Override
public void work() {
System.out.println("编号为:"+getId()+"的"+getName()+"员工正在搞APP");
}
}
public class Test {
public static void main(String[] args) {
//使用构造方法为属性赋值
JavaEE javaEE1 = new JavaEE(3, "金莲");
javaEE1.work();
}
}
小结:
关键字:abstract
抽象方法: public abstract 返回值类型 方法名();
抽象类:public abstract class 类名{}
注意:
抽象方法所在的类一定是抽象类
抽象类不一定非得有抽象方法
抽象类中还可以有(私有属性,构造,普通的成员方法)
抽象类不能直接new对象
子类继承抽象父类之后,必须要重写抽象方法
第三章.多态
怎么学多态
1.会使用多态的形式创建对象
2.知道多态的好处
1.多态的介绍
1.面向对象三大特征:封装 继承 多态
2.前提:
a.必须有子父类继承关系或者接口实现关系
b.必须有方法的重写->没有方法重写多态没有意义(利用多态访问成员变量,没任何意义)
c.创建对象:父类引用指向子类对象
父类 对象名 = new 子类()
3.弊端
利用多态的形式new对象,不能直接调用子类特有方法
2.多态的基本使用
1.创建父类
2.创建子类继承父类
3.在子类中重写方法
4.利用多态形式创建对象:父类 对象名 = new 子类()
5.调用子类重写的方法
public abstract class Animal {
public abstract void eat();
}
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗啃骨头");
}
//特有方法
public void lookDoor(){
System.out.println("狗会看门");
}
}
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
//特有方法
public void catchMouse(){
System.out.println("猫会抓老鼠");
}
}
public class Test {
public static void main(String[] args) {
Animal animal = new Dog();
animal.eat();
//animal.lookDoor();多态形式不能调用子类特有功能
System.out.println("=============");
Animal animal1 = new Cat();
animal1.eat();
}
}
3.多态的条件下成员的访问特点
3.1成员变量
看等号左边是谁,先调用谁->成员变量没有多态性
public class Fu {
int num = 100;
}
public class Zi extends Fu{
int num = 10;
}
public class Test {
public static void main(String[] args) {
Zi zi = new Zi();
System.out.println(zi.num);
Fu fu = new Zi();
System.out.println(fu.num);
}
}
3.2成员方法
看new的是谁先调用谁中的方法,子类没有,找父类->成员方法是有多态性的
public class Fu {
int num = 100;
public void method(){
System.out.println("我是父类中的method方法");
}
}
public class Zi extends Fu{
int num = 10;
public void method(){
System.out.println("我是子类中的method方法");
}
}
public class Test {
public static void main(String[] args) {
Zi zi = new Zi();
System.out.println(zi.num);
zi.method();//调用重写的
Fu fu = new Zi();
System.out.println(fu.num);
fu.method();//调用重写的
}
}
4.多态的好处(为什么学多态)
1.多态的好处不体现在new对象上,体现在方法参数传递上
2.不用多态和同多态有什么好处和弊端:
不用多态:
好处:既可以调用从父类继承过来的,还能调用重写的,还能调用自己特有的方法
弊端:在传参数的过程中扩展性很差
多态:
弊端:不能直接调用子类特有方法
好处:在传递参数的过程中扩展性强
public abstract class Animal {
public abstract void eat();
}
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗啃骨头");
}
//特有方法
public void lookDoor(){
System.out.println("狗会看门");
}
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
//特有方法
public void catchMouse(){
System.out.println("猫会抓老鼠");
}
}
public class Test {
public static void main(String[] args) {
//原始方式new对象
Dog dog = new Dog();
method(dog);
Cat cat = new Cat();
method(cat);
}
public static void method(Animal animal){//Animal animal = dog; Animal animal = cat
animal.eat();
}
}
5.多态中的转型
5.1向上转型
1.默认: 父类引用指向子类对象
父类类型 对象名 = new 子类对象
好比: doule b = 10;
5.2向下转型
1.如果想要调用子类特有方法,就需要向下转型
2.怎能转:
父类类型 对象名 = new 子类对象->向上转型
子类类型 对象名1 = (子类类型)对象名->向下转型
好比:
double b = 10;->将int转成了double
int i = (int)b;->将double强转成了int
Animal animal = new Dog();->向上转型
Dog dog = (Dog)animal;-->向下转型
public abstract class Animal {
public abstract void eat();
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
//特有方法
public void catchMouse(){
System.out.println("猫会抓老鼠");
}
}
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗啃骨头");
}
//特有方法
public void lookDoor(){
System.out.println("狗会看门");
}
}
public class Test {
public static void main(String[] args) {
Animal animal = new Dog();
animal.eat();
//向下转型
Dog dog = (Dog)animal;
dog.lookDoor();
System.out.println("=================");
Animal animal1 = new Cat();
animal1.eat();
//向下转型
Cat cat = (Cat) animal1;
cat.catchMouse();
}
}
6.转型可能会出现的问题
1.向下转型时注意的问题:
如果等号左右两边类型不一致时:ClassCastException(类型转换异常)
2.如何去判断类型:
关键字:instanceof -> 结果是一个boolean型
使用格式: 对象名 instanceof 具体类型
关键字前面的对象是否属于关键字后面的类型
public abstract class Animal {
public abstract void eat();
}
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗啃骨头");
}
//特有方法
public void lookDoor(){
System.out.println("狗会看门");
}
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
//特有方法
public void catchMouse(){
System.out.println("猫会抓老鼠");
}
}
public class Test {
public static void main(String[] args) {
Dog dog = new Dog();
method(dog);
method(new Cat());
}
public static void method(Animal animal){
if (animal instanceof Dog){
animal.eat();
Dog dog = (Dog) animal;
dog.lookDoor();
}
if (animal instanceof Cat){
animal.eat();
//将代表dog的animal强转成Cat
Cat cat = (Cat)animal;
cat.catchMouse();
}
}
}
小结:
1.前提:
a.必须有子父类继承关系或者接口实现关系
b.必须有方法的重写(多态没有方法的重写,多态没有意义)
c.父类引用指向子类对象
2.成员访问特点:
成员变量:看等号左边是谁,先调用谁
成员方法:看new的是谁,先调用谁,子类没有找父类
3.多态的好处:
弊端:不能调用子类特有的方法
好处:当作为方法参数传递的时候,扩展性强
4.转型
向上转型:默认 父类引用指向子类对象
向下转型:强转,将父类类型强转会子类类型
5.转型容易出现的问题:ClassCastException(类型转换异常)
原因:等号左右两边的类型不一致
解决:做判断
对象名 instanceof 类型->可以判断类型
第四章.接口
1.接口的介绍
1.概述:标准,规则,引用数据类型
2.关键字:interface(接口) implements(实现)
3.成员比较单一的
jdk7:
抽象方法:带abstract的方法 不写也有
成员变量:带static final的,表示最终的变量,所以值不能改变 不写static final也有
jdk8:
默认方法:public default 返回值类型 方法名(参数){}
静态方法:public static 返回值类型 方法名(参数){}
jdk9:
私有方法:private 返回值类型 方法名(参数){}
2.接口的定义以及使用
1.定义:
public interface 接口名{
}
2.定义实现类
public class 类名 implements 接口名{
重写接口中的抽象方法
}
3.注意:
a.定义接口之后需要实现类去实现它
b.实现类实现接口的时候,要重写接口中的抽象方法
c.接口不能new对象,只能通过new实现类对象调用重写的方法
public interface USB {
//定义抽象方法
public abstract void open();
void close();
}
public class Mouse implements USB{
@Override
public void open() {
System.out.println("鼠标插进去打开了");
}
@Override
public void close() {
System.out.println("鼠标拔出来就关闭了");
}
}
public class Test01 {
public static void main(String[] args) {
//USB usb = new USB();接口不能直接new对象
Mouse mouse = new Mouse();
mouse.open();
mouse.close();
System.out.println("=================");
//利用多态的形式去new
USB usb = new Mouse();
usb.open();
usb.close();
}
}
3.接口中的成员
3.1抽象方法
1.定义:
public abstract 返回值类型 方法名(参数);
2.使用:
a.定义实现类实现接口
b.在实现类中重写抽象方法
c.new实现类对象,调用重写方法
3.注意:
如果在接口中定义一个没有方法体的方法,就是抽象方法
即使不写abstract,默认也有
public interface USB {
//定义抽象方法
public abstract void open();
//没有写abstract,默认也有
void close();
}
public class KeyBoard implements USB{
@Override
public void open() {
System.out.println("键盘开启");
}
@Override
public void close() {
System.out.println("键盘关闭");
}
}
public class Test {
public static void main(String[] args) {
KeyBoard keyBoard = new KeyBoard();
keyBoard.open();
keyBoard.close();
System.out.println("=================");
//多态形式
USB usb = new KeyBoard();
usb.open();
usb.close();
}
}
3.2默认方法
1.定义:
public default 返回值类型 方法名(参数){
方法体
return 结果
}
2.使用:
a.定义实现类,实现接口
b.如果不对接口中的默认方法进行功能修改,就不用重写了
如果要对接口中的默认方法进行功能修改,就需要重写默认方法(不要带default)
c.创建实现类对象,调用默认方法或者重写的方法
public interface USB {
//默认方法
public default void start(){
System.out.println("USB打开了");
}
}
public class Mouse implements USB{
@Override
public void start(){
System.out.println("鼠标打开了");
}
}
public class Test {
public static void main(String[] args) {
Mouse mouse = new Mouse();
mouse.start();
}
}
3.3静态方法
1.定义格式:
public static 返回值类型 方法名(参数){
方法体
return 结果
}
2.使用:
接口名直接调用
public interface USB {
//静态方法
public static void start(){
System.out.println("usb开启了");
}
}
public class Test {
public static void main(String[] args) {
USB.start();
}
}
在类中定义的静态方法,也不能被重写
3.4成员变量
1.定义格式:
public static final 数据类型 变量名 = 值
即使不写public static final默认也有
2.使用:
接口名直接调用
3.注意:
a.接口中的成员变量即使不写public static final默认也有
b.接口中的成员变量需要手动赋值
c.接口中的成员变量不能被二次赋值
d.被static final修饰的变量名字一般都要大写(习惯上的写法)
public interface Interface {
public static final int NUM = 100;
//num = 200;被final修饰的成员变量不能被二次赋值
int I = 10;
}
public class Test {
public static void main(String[] args) {
System.out.println(Interface.NUM);
}
}
4.接口的特点
1.接口可以多继承
public interface InterfaceC extends InterfaceA,InterfaceB{
}
2.一个实现类可以同时实现一个或者多个接口->需要重写接口中所有的抽象方法
public class InterfaceImpl implements InterfaceA,InterfaceB{
}
3.一个实现类可以继承一个父类的同时实现一个或者多个接口->需要重写父类中和接口中所有的抽象方法
public class Zi extends Fu implements InterfaceA,InterfaceB{
}
如果抽象方法有重名的,只需要重写一次
如果默认方法有重名的,必须重写一次
5.接口和抽象类的区别
相同点:
都位于继承的顶端,用于被其他类实现或继承;
都不能直接实例化对象;
都包含抽象方法,其子类都必须重写这些抽象方法;
不同点:
抽象类:一般作为父类使用,可以有成员变量 构造方法 成员方法等
接口:成员单一,一般抽取接口,抽取的都是方法,是功能的大集合
类不能多继承,但是接口可以
6.综合练习
定义笔记本类,具备开机,关机和使用USB设备的功能。具体是什么USB设备,笔记本并不关心,只要符合USB规格的设备都可以。鼠标和键盘要想能在电脑上使用,那么鼠标和键盘也必须遵守USB规范,不然鼠标和键盘的生产出来无法使用;
进行描述笔记本类,实现笔记本使用USB鼠标、USB键盘
- USB接口,包含开启功能、关闭功能
- 笔记本类,包含运行功能、关机功能、使用USB设备功能
- 鼠标类,要符合USB
- 键盘类,要符合USB接口
public interface USB {
//开启
void open();
//关闭
void close();
}
public class Mouse implements USB{
@Override
public void open() {
System.out.println("鼠标开启");
}
@Override
public void close() {
System.out.println("鼠标关闭");
}
}
public class KeyBoard implements USB{
@Override
public void open() {
System.out.println("键盘开启");
}
@Override
public void close() {
System.out.println("键盘关闭");
}
}
public class NoteBook {
//开机
public void start(){
System.out.println("开机了,来啊,使用我呀");
}
//使用USB方法
public void useUsb(USB usb){
usb.open();
usb.close();
}
//关机
public void stop(){
System.out.println("关机了,你不要来了");
}
}
public class Test {
public static void main(String[] args) {
//创建鼠标和键盘对象
Mouse mouse = new Mouse();
KeyBoard keyBoard = new KeyBoard();
//创建笔记本类对象
NoteBook noteBook = new NoteBook();
noteBook.start();
noteBook.useUsb(mouse);
noteBook.useUsb(keyBoard);
noteBook.stop();
}
}
7.综合练习升级版
public interface USB {
//开启
void open();
//关闭
void close();
}
public class Mouse implements USB{
@Override
public void open() {
System.out.println("鼠标开启");
}
@Override
public void close() {
System.out.println("鼠标关闭");
}
//特有方法
public void click(){
System.out.println("我可以单击");
}
}
public class KeyBoard implements USB{
@Override
public void open() {
System.out.println("键盘开启");
}
@Override
public void close() {
System.out.println("键盘关闭");
}
//特有方法
public void input(){
System.out.println("键盘输入");
}
}
public class NoteBook {
//开机
public void start(){
System.out.println("开机了,来啊,使用我呀");
}
//使用USB方法
public void useUsb(USB usb){
if (usb instanceof Mouse){
usb.open();
usb.close();
//向下转型
Mouse mouse = (Mouse)usb;
mouse.click();
}
if (usb instanceof KeyBoard){
usb.open();
usb.close();
//向下转型
KeyBoard keyBoard = (KeyBoard)usb;
keyBoard.input();
}
}
//关机
public void stop(){
System.out.println("关机了,你不要来了");
}
}
public class Test {
public static void main(String[] args) {
//创建鼠标和键盘对象
Mouse mouse = new Mouse();
KeyBoard keyBoard = new KeyBoard();
//创建笔记本类对象
NoteBook noteBook = new NoteBook();
noteBook.start();
noteBook.useUsb(mouse);
noteBook.useUsb(keyBoard);
noteBook.stop();
}
}
第五章.权限修饰符
5.1 概述
在Java中提供了四种访问权限,使用不同的访问权限修饰符修饰时,被修饰的内容会有不同的访问权限,
- public:公共的。
- protected:受保护的
- default:默认的,不写任何权限修饰符,那么整个权限就是默认权限
- private:私有的
5.2 不同权限的访问能力
public | protected | default(空的) | private | |
---|---|---|---|---|
同一类中 | √ | √ | √ | √ |
同一包中不同类(子类与无关类) | √ | √ | √ | x |
不同包的子类 | √ | √ | ||
不同包中的无关类 | √ |
可见,public具有最大权限。private则是最小权限。
编写代码时,如果没有特殊的考虑,建议这样使用权限:
- 成员变量使用
private
,隐藏细节。 - 构造方法使用
public
,方便创建对象。 - 成员方法使用
public
,方便调用方法。
第六章.final关键字
1.概述:最终的
2.用法:
修饰类
修饰方法
修饰成员变量
修饰局部变量
修饰对象
1.final修饰类
1.格式:
public final class 类名{
}
2.特点:
被final修饰的类不能被继承
public final class Animal {
public void eat(){
System.out.println("动物要吃饭");
}
}
public class Dog /*extends Animal*/{//被final修饰的类不能被继承
}
2.final修饰方法
1.格式:
public final 返回值类型 方法名(参数){
方法体
return 结果
}
2.特点:
被final修饰的方法不能被重写
public abstract class Animal {
public final void eat(){
System.out.println("动物要吃饭");
}
//public abstract final void drink(); abstract和final冲突
}
public class Dog extends Animal{
//被final修饰的方法不能被重写
/* public void eat(){
System.out.println("动物要吃饭");
}*/
}