4. 面向对象之单例模式与多态
3.2 多态
1. 简介
多态:多种形态
2. 多态的实现
3.3 多态的实现
1. 案例
package com.imooc.dt;
/**
* 动物类,父类
*/
public class Animal {
//名称
private String name;
/**
* 介绍
*/
public void introduce() {
System.out.println("我是动物.");
}
/**
* 吃东西
*/
public void eat() {
}
}
package com.imooc.dt;
public class Cat extends Animal {
//月份
private String month;
/**
* 行为
*/
public void sleep() {
System.out.println("我喜欢睡懒觉");
}
@Override
public void eat() {
System.out.println("我喜欢吃小鱼干");
}
}
package com.imooc.dt;
public class Dog extends Animal {
//年龄
private String age;
public void walking() {
System.out.println("我喜欢奔跑");
}
@Override
public void eat() {
System.out.println("我喜欢吃大骨头");
}
}
2. 向上转型
3. 向下转型
动物转猫
猫转动物再转猫
猫转狗
第10行对比
4. instanceof类比较
3.4 抽象类
1. 简介
可以,abstract描述的类
抽象类不允许实例化,可以向上转型指向子类实例
2. 抽象类的抽象方法
1.抽象类中某方法由abstract修饰,则该方法就为抽象方法
2.抽象方法没有方法体,并且其子类必须重写该方法,如果子类不重写,则子类要设置为抽象类
3.有抽象方法的类一定是抽象类
4.抽象方法体现了抽象类存在的意义
package com.imooc.lei;
import com.sun.scenario.effect.impl.prism.PrTexture;
/**
* 抽象类
*/
public abstract class Person {
private String name;
private int age;
public void pao() {
System.out.println("我是非抽象方法");
}
/**
* 抽象方法
*/
public abstract void beat();
}
3. 总结
向上转型:就是父类转子类
4.1 接口
1. 背景
2. 案例:基于继承
父类:电话,功能打电话
package com.imooc.ex;
/**
* 电话
*/
public class Telphone {
//品牌
private String brand;
//价格
private int price;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
//功能
public void call() {
System.out.println("可以打电话");
}
}
二代手机
package com.imooc.ex;
/**
* 二代手机,继承电话所有功能,还可以发短信
*/
public class SecondPhone extends Telphone {
public void message() {
System.out.println("可以发短信");
}
}
三代手机
package com.imooc.ex;
/**
* 三代手机:继承二代手机,功能还可以看视频,听音乐
*/
public class ThirdPhone extends SecondPhone {
public void vedio() {
System.out.println("可以看视频");
}
public void music() {
System.out.println("可以听音乐");
}
}
实现一个3代手机
package com.imooc.ex.alc;
import com.imooc.ex.ThirdPhone;
public class app {
public static void main(String[] args) {
//实现一个3代手机
ThirdPhone thirdPhone = new ThirdPhone();
//一代功能
thirdPhone.call();
//二代功能
thirdPhone.message();
//三代自己的功能
thirdPhone.vedio();
thirdPhone.music();
}
}
3. 基于2的问题
继承 – 适用于有一定的演变的对象。一代一代的迭代
当遇到对于跨度比较大的不同的对象,存在某些共同点,比如照相机和电话都可以拍照,又比如电脑、手机、电话手表都可以微信电话。
那如何提取他们的共同点?— 接口interface
4. 案例:基于接口
idea快捷键:实现接口方法 ctrl+i
拍照接口
package com.imooc.im;
/**
* IPhoto接口:拍照模版,不具体如何拍照,即没有方法体
*/
public interface IPhoto {
//拍照模版,不具体如何拍照,即没有方法体
public void photo();
}
相机类:实现拍照功能
package com.imooc.im;
/**
* 相机类
*/
public class Camera implements IPhoto {
//实现IPhoto的photo,需要具体实现
@Override
public void photo() {
System.out.println("相机拍照");
}
}
手机类实现拍照功能
package com.imooc.im;
import com.imooc.ex.ThirdPhone;
/**
* 手机类
*/
public class Phone extends ThirdPhone implements IPhoto {
/**
* 实现方法:拍照
*/
@Override
public void photo() {
System.out.println("手机拍照");
}
}
测试
package com.imooc.im.app;
import com.imooc.im.Camera;
import com.imooc.im.IPhoto;
import com.imooc.im.Phone;
public class MainApp {
public static void main(String[] args) {
//创建相机
IPhoto camera = new Camera();
camera.photo();
//创建手机1:基于 IPhoto 接收,只能调用Phone实现的方法
IPhoto iPhoto = new Phone();
iPhoto.photo();
//创建手机2:基于 Phone 接收,才能调用其他非实现方法
Phone phone = new Phone();
phone.photo();
phone.message();
}
}
5. default关键字使用
接口中某些方法不强制实现类重写该方法,可以将方法由default关键字修饰
package com.imooc.im;
/**
* IPhoto接口:拍照模版,不具体如何拍照,即没有方法体
*/
public interface IPhoto {
/**
* default:在接口中修饰方法.该方法为默认方法且可以有方法体,实现类可不重写(即:可写,可不写)
*/
default void connection() {
System.out.println("接口中的默认方法");
}
/**
* 拍照模版
*/
public void photo();
}
Camera类实现IPhoto ,未重写connection默认方法
Phone类实现IPhoto ,重写connection默认方法
测试
6. static关键字使用
接口中的静态方法:该方法不能被实现类重写
测试
无法通过实现类调用
7. default和static区别
调用时: default方法可以对象去调用,static只能接口名去调用
实现类: default修饰的方法可以被重写,而static不可以。值得注意的是,default重写要调用接口方法需要接口名.super实现
8. 实现多接口:方法重复
对于实现类同时实现接口A接口B…时,他们存在同一个方法名时,实现类需要重写该方法,就算该方法是默认方法也需要重写
接口1
package com.imooc.im;
/**
* IPhoto接口:拍照模版,不具体如何拍照,即没有方法体
*/
public interface IPhoto {
/**
* default:在接口中修饰方法.该方法为默认方法且可以有方法体,实现类可不重写(即:可写,可不写)
*/
default void connection() {
System.out.println("IPhoto接口中的默认方法");
}
/**
* 拍照模版
*/
public void photo();
}
接口2
package com.imooc.im;
/**
* IPhoto接口:拍照模版,不具体如何拍照,即没有方法体
*/
public interface IPhoto1 {
/**
* default:在接口中修饰方法.该方法为默认方法且可以有方法体,实现类可不重写(即:可写,可不写)
*/
default void connection() {
System.out.println("IPhoto1接口中的默认方法");
}
/**
* 拍照模版
*/
public void photo1();
}
实现类:多接口实现
package com.imooc.im.impl;
import com.imooc.im.IPhoto;
import com.imooc.im.IPhoto1;
/**
* 相机类
*/
public class Camera implements IPhoto, IPhoto1 {
/**
* default:在接口中修饰方法.该方法为默认方法且可以有方法体,实现类可不重写(即:可写,可不写)
* 在多接口实现类中,多接口中默认方法存在名称一致时,需要重写
*/
@Override
public void connection() {
IPhoto.super.connection();
IPhoto1.super.connection();
System.out.println("默认方法需要重写!!!");
}
/**
* 实现IPhoto的photo,需要具体实现
*/
@Override
public void photo() {
System.out.println("相机拍照");
}
/**
* 实现IPhoto1的photo1,需要具体实现
*/
@Override
public void photo1() {
System.out.println("单反相机拍照");
}
}
测试
9. 接口与继承存在同名方法
父类
接口
实现类且子类:未重写同名方法connection
测试
结论:虽然未被重写,底层是子类继承connection方法,隐式重写实现类的默认connection方法
可以看到此时的connection无法被重写
10. 接口继承
4.2 内部类
1. 简介
2. 内部类分类
3. 成员内部类
3.1 定义内部类
内部类中最常见的就是成员内部类也称为普通内部类
package com.imooc.lei;
/**
* 外部类Person
*/
public class Person {
private int age;
/**
* 提供内部类获取
*
* @return
*/
public Heart getHeart() {
return new Heart();
}
public Work getWork() {
return new Work();
}
/**
* 成员内部类:隐藏在外部类里面,无法被其他类直接获取
*/
public class Heart {
public String beat() {
return "我是Person的内部类Heart";
}
}
/**
* 访问修饰符:成员内部类的访问修饰符可以任意,但是访问范围会受到影响
*/
private class Work {
public String beat() {
return "我是Person的内部类work";
}
}
}
3.2 调用内部类
内部类在外部使用时,无法直接实例化,需要借由外部类信息才能完成实例化
package com.imooc.lei.app;
import com.imooc.lei.Person;
public class MainApp {
/**
* 演示:调用内部类
*
* @param args
*/
public static void main(String[] args) {
//方式1:new 外部类.new 内部类
Person.Heart heatr = new Person().new Heart();
System.out.println("方式1: new 外部类.new 内部类:" + heatr.beat());
//方式2: 外部类对象.new 内部类
Person person = new Person();
Person.Heart heart1 = person.new Heart();
System.out.println("方式2: 外部类对象.new 内部类:" + heart1.beat());
//方式3: 外部类对象.获取方法 (推荐)
Person.Heart heart3 = person.getHeart();
System.out.println("方式3: 外部类对象.获取方法:" + heart3.beat());
//方式4:内部类未被public修饰时
// Person.Work work = new Person().new Work();//无法获取Work类
// System.out.println("方式3: 外部类对象.获取方法:"+person.getWork().beat());//无法获取Work类的beat方法
}
}
3.3 内部类使用外部类成员
内部类可以直接访问外部类的成员;如果出现同名属性,优先访问内部类中定义的
可以通过外部类.this.成员的方式,访问外部类的同名信息
package com.imooc.lei;
/**
* 外部类Person
*/
public class Person {
//名称
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 提供内部类获取
*
* @return
*/
public Heart getHeart() {
return new Heart();
}
/**
* 成员内部类:隐藏在外部类里面,无法被其他类直接获取
*/
public class Heart {
//名称
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 内部类获取外部类name属性
* 获取方式:外部类.this.成员
* @return
*/
public String getExternalName() {
return Person.this.name;
}
}
}
4. 静态内部类
4.1 定义静态内部类
package com.imooc.lei;
/**
* 外部类Person
*/
public class Person {
//名称
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 提供内部类获取
*
* @return
*/
public Heart getHeart() {
return new Heart();
}
/**
* Heart静态内部类:隐藏在外部类里面,无法被其他类直接获取
*/
public static class Heart {
//名称
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
4.2 静态内部类调用外部类成员
测试
package com.imooc.lei;
import com.sun.scenario.effect.impl.prism.PrTexture;
/**
* 外部类Person
*/
public class Person {
//名称
private String name;
private static int age = 18;
public Person() {
}
public Person(String name) {
this.name = name;
}
public void sMethod() {
System.out.println("我是外部类的非静态成员方法");
}
public static void fMethod() {
System.out.println("我是外部类的静态成员方法");
}
/**
* 提供内部类获取
*
* @return
*/
public Heart getHeart() {
return new Heart();
}
/**
* Heart静态内部类:隐藏在外部类里面,无法被其他类直接获取
*/
public static class Heart {
//名称
private String name;
/**
* 内部类调用外部类非静态成员,需要通过实例化外部类获取
* 静态成员可直接获取
*
* @param person
*/
public void setNameByWeb(Person person) {
//this.name = Person.this.name;//错误演示,无法调用外部类非静态成员
// Person person=new Person();
//获取非静态成员
System.out.println("名称:" + person.name);
person.sMethod();
//获取静态成员
Person.fMethod();
System.out.println("年龄:" + Person.age);
}
public String beat() {
return "我是静态内部类;";
}
}
}
4.3 调用静态内部类的静态成员
获取静态内部类静态方法:外部类.内部类.静态方法
5. 方法内部类
package com.imooc.lei;
import com.sun.scenario.effect.impl.prism.PrTexture;
/**
* 外部类Person
*/
public class Person {
/**
* 方法内部类方法,返回值为Object
* 方法内部类中不可以有静态成员
*
* @return new 方法内部类方法,缺点,获取到的信息不多
*/
public Object getHeart() {
/**
* 方法内部类
*/
class Heart {
//名称
private String name = "我是方法内部类的属性";
public String getName() {
return name;
}
public String beat() {
return "我是方法内部类的成员方法;";
}
}
return new Heart().beat();
}
}
6. 匿名内部类
适用于,该类项目只使用一次实例,并且内容较小
package com.imooc.lei;
import com.sun.scenario.effect.impl.prism.PrTexture;
/**
* 外部类Person
*/
public abstract class Person {
private String name;
private int age;
public abstract void beat();
}