day08_JAVAOOP
接口
概述
接口是Java语言中一种引用类型,是方法的集合,接口内部主要就是封装了方法(功能),包含抽象方法(JDK7
及以前)、默认方法和静态方法(JDK8
)、私有方法(JDK9
)
总结
- 接口就是一种公共的规范标准,只要符合规范标准,大家都可以通用
- Java中的接口更多的体现在对行为的抽象
- 应用场景:为了功能拓展
接口定义格式
接口用关键字interface
修饰
格式:public interface 接口名{}
接口的使用
接口是不能创建对象,必须有实现类才能使用,类实现接口用implements
表示
格式:public class 类名 implements 接口名{}
- 注:接口的实现类必须重写接口中所有的抽象方法,除非该类是抽象类
接口成员的特点
成员变量
只能是常量,默认修饰符:public static final(可省略)
成员方法
只能是抽象方法,默认修饰符:public abstract(可省略)
构造方法
无(因为接口主要是扩展功能的,而没有具体存在)
接口默认方法的定义和使用
-
默认方法:使用
default
修饰,不可省略,供子类调用或重写 -
定义格式:
public default 返回值类型 方法名(参数列表){
//方法体
}
- 好处:接口的默认方法,实现类可以不用重写,默认方法可用于接口升级(往写好的项目代码中进行扩展,在接口中加默认方法对其他类没有影响,代码维护性好)
接口静态方法的定义和使用
- 静态方法:使用
static
修饰,供接口直接调用 - 静态方法只能使用接口名调用,不能通过实现类的类名或对象调用
- 定义格式:
public static 返回值类型 方法名称(参数列表){
//方法体
}
代码演示
- 接口
package cn.zhuo_01;
/**
* @Auther: 不学无墅
* @Date: 2023/7/14 10:30
* @Desc: 接口
*/
public interface Inter {
//接口成员变量——只能是常量,不能更改的
int num =10;//此处省略了默认修饰符public static final
//默认修饰符:public static final(可省略)
public static final int num1 = 20;
public int num2 = 30;
static int num3 = 40;
final int num4 = 50;
static final int num5 = 60;
//构造方法——无
// public Inter() {}
//接口成员方法,默认修饰符:public abstract可以省略
void show();//接口成员方法只能是抽象方法
//接口中不能有方法主体
// public void show() {}
//接口默认方法
public default void method(){
System.out.println("默认方法,default修饰不能省略");
}
//接口静态方法
public static void show1(){
System.out.println("接口静态方法,使用static修饰");
}
}
- 实现类
package cn.zhuo_01;
/**
* @Auther: 不学无墅
* @Date: 2023/7/14 10:31
* @Desc: 实现类
*/
public class InterImpl implements Inter{
//实现类必须对接口中的抽象方法进行重写
@Override
public void show() {
//TODO 功能待优化
System.out.println("对接口中的抽象方法进行重写");
}
//接口中的默认方法,不用重写,也可以手动重写
@Override
public void method() {
System.out.println("接口中的默认方法,可以选择是否重写,也可以根据实际需求进行重写");
}
//实现类中无法重写静态方法
}
- 测试类
package cn.zhuo_01;
/**
* @Auther: 不学无墅
* @Date: 2023/7/14 11:28
* @Desc: 测试类
*/
public class Test {
public static void main(String[] args) {
//创建实现类对象
InterImpl inter = new InterImpl();
//调用方法
inter.show();
//调用默认方法
inter.method();
//调用静态方法
//静态与.class文件相关,接口的静态方法只能使用接口名调用,不可以通过实现类的类名或者实现类的对象调用
Inter.show1();
}
}
多态
什么是多态
同一个事物,在不同时刻体现的状态不一样
多态的前提
- 要有继承或实现关系
- 要有方法的重写
- 要有父类引用指向子类对象(
Father f = new Son;
)
多态格式
普通类多态的格式
父类 对象名 = new 子类();
抽象类多态的格式
抽象类 对象名 = new 抽象类子类();
接口多态的格式
接口 对象名 = new 接口实现类();
多态中的成员访问特点
成员变量
编译看左边(父类),运行看左边(父类)
成员方法
编译看左边(父类),运行看右边(子类)
代码演示
- 父类
package cn.zhuo_02;
/**
* @Auther: 不学无墅
* @Date: 2023/7/14 14:17
* @Desc: 父类
*/
public abstract class Animal {
//成员变量
int age = 40;
//成员方法
public abstract void eat();
}
- 子类
package cn.zhuo_02;
/**
* @Auther: 不学无墅
* @Date: 2023/7/14 14:17
* @Desc: 子类
* 多态的前提:
* 1. 继承或实现关系
* 2. 要有方法重写
* 3. 要有父类引用指向子类对象 fu f = new zi();
*/
public class Cat extends Animal{
//成员变量
int age = 20;
//子类独有的成员变量
int weight = 10;
//父类成员方法重写
@Override
public void eat() {
System.out.println("cat吃鱼");
}
//子类独有的成员方法
public void playGame(){
System.out.println("cat后空翻");
}
}
- 测试类
package cn.zhuo_02;
/**
* @Auther: 不学无墅
* @Date: 2023/7/14 14:21
* @Desc: 测试类
*/
public class Test {
public static void main(String[] args) {
//通过多态方法 Fu fu = new Zi();
//父类引用指向子类对象
Animal cat = new Cat();
//多态访问:成员变量
System.out.println(cat.age);//输出父类的age=40
// 【父new子】——>成员变量:编译看左边(父类) 运行看左边(父类)
//System.out.println(cat.weight);——>弊端:多态不能使用子类特有的成员
//多态访问:成员方法
cat.eat();
//【父new子】——>成员方法:编译看左边(父类) 运行看右边(子类)
//cat.playGame();——>弊端:多态不能使用子类特有的成员
}
}
多态的好处和弊端
多态的弊端
不能使用子类特有的成员
多态的好处
提高程序的扩展性,定义方法的时候,使用父类型作为参数,在使用时,使用具体的子类型参与操作
代码演示
- 父类
package cn.zhuo_03;
/**
* @Auther: 不学无墅
* @Date: 2023/7/14 14:37
* @Desc: 父类 抽象
*/
public abstract class Animal {
public abstract void eat();
}
- 子类
package cn.zhuo_03;
/**
* @Auther: 不学无墅
* @Date: 2023/7/14 14:39
* @Desc: 子类之一
*/
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("cat吃鱼");
}
}
package cn.zhuo_03;
/**
* @Auther: 不学无墅
* @Date: 2023/7/14 14:38
* @Desc: 子类之一
*/
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("dog吃骨头");
}
}
- 测试类
package cn.zhuo_03;
/**
* @Auther: 不学无墅
* @Date: 2023/7/14 14:39
* @Desc: 测试类
*/
public class Test {
public static void main(String[] args) {
/*Cat cat = new Cat();
showCatEat(cat);
Dog dog = new Dog();
showDogEat(dog);*/
Animal cat = new Cat();
showAnimal(cat);
//Animal dog = new Dog();
showAnimal(new Dog());
}
/*public static void showCatEat(Cat cat){
cat.eat();
}
public static void showDogEat(Dog dog){
dog.eat();
}*/
public static void showAnimal(Animal animal){
animal.eat();
}
}
多态中的转型
多态的弊端是不能使用子类特有的成员,为了解决这个弊端,必须做向下转型(强转)
向上转型
多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的
- 使用格式:
父类类型 变量名 = new 子类类型();
向下转型
父类类型向子类类型转换的过程,这个过程是强制的
一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型
- 使用格式:
子类类型 变量名 = (子类类型)父类变量名;
转型的异常
ClassCastException
类型转换异常
instanceof关键字
为了避免ClassCastException
异常的发生,Java提供了instanceof
关键字,给引用变量做类型的校验
- 使用格式:
变量名 instanceof 数据类型
//若变量属于该数据类型,返回true
//若变量不属于该数据类型,返回false
代码演示
- 父类
package cn.zhuo_04;
/**
* @Auther: 不学无墅
* @Date: 2023/7/14 15:29
* @Desc: 父类
*/
public abstract class Animal {
public abstract void eat();
public void show(){
System.out.println("show");
}
}
- 子类
package cn.zhuo_04;
/**
* @Auther: 不学无墅
* @Date: 2023/7/14 15:30
* @Desc:
*/
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("cat 吃鱼");
}
public void catchMouse() {
System.out.println("猫抓老鼠");
}
}
package cn.zhuo_04;
/**
* @Auther: 不学无墅
* @Date: 2023/7/14 15:33
* @Desc:
*/
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃骨头");
}
public void watchHouse(){
System.out.println("看家");
}
}
- 测试类
package cn.zhuo_04;
/**
* @Auther: 不学无墅
* @Date: 2023/7/14 15:33
* @Desc:
*/
public class Test {
public static void main(String[] args) {
//向上转型
Animal animal = new Cat();
animal.eat();//调用的是 Cat的 eat()
//向下转型 zi z = (zi)fu; 向下转型,获取子类特有的方法
Cat c=(Cat) animal;
c.eat();//调用子类重写的方法
c.catchMouse();//调用的是子类独有的方法
c.show();//调用子类继承的父类的方法
//Dog d = (Dog) animal;//引用的父类,是多态 cat类,并不是 dog
//d.watchHouse();//运行报错,调用的是 Dog的 watchHouse
Animal animal1 = new Dog();
Dog dog=(Dog) animal1;
dog.eat();
dog.watchHouse();
}
}