多态

  1. 多态的弊端,不能使用子类特有的内容
  2. 多态前提
    1. 必须要有关系,继承,实现
    2. 必须要有重写

多态向上转型

1
2
有一个动物类Animal,子类猫cat
Animal a = new Cat()

这什么意思呢,看看基本属性类型的强转:

1
byte x = 2; int a = x //这里x会自动提升为int

可以把上面的Animal看作int,cat看作byte,所以这里新new出来的猫类,会自动提升为动物类

提升成动物类之后,只能用动物类里面的方法和自己类里面重写的方法,但是不能使用猫类自己特有的方法了

可以限制功能使用,提高拓展性

多态向下转型

1
Cat c = (Cat) a;

将动物类的a,强转为猫类,然后赋给c,因为动物类是父类,所以这里强转为猫类就是向下转型

向下转型就可以使用子类特有的方法了

误区

1
2
3
4
Animal a = new Animal();
Cat c = (Cat)a;
Animal a = new dog();
Cat c = (Cat)a;

上面两种操作都是不行的

  1. 不能将父类强转为子类,上面能转,是因为其本身new的就是猫类,所以可以强转回来
  2. 两个毫不相关的类也不能转,猫可以是动物,也可以是猫,但是狗只能是狗,不能叫它猫
  3. 小可以转大,但大不能转小

判断是否为正确的对象

a instanceof Cat:判断a是否为Cat类型的对象

instanceof 只能用于引用数据类型的判断

多态中的成员变量

参考引用型变量所属的类中,是否有调用的成员变量,有就通过,没有就失败

1
2
3
4
5
6
7
8
9
class fu(){
int num = 4;
}
class zi extends fu(){
int num = 1;
}

fu f = new zi();
System.ou.println(f.num); //4

引用类型为哪个类,直接调用时,就会访问到哪个类里面的成员变量

编译和运行时,参考等号的左边

多态中的成员方法

自动类型提升了,就隐藏了子类特有的方法

编译看左边,运行看右边,动态绑定,谁调用就绑定谁

多态中的静态方法

静态方法在类生成的时候就绑定了,并不具备多态性

多态是基于对象的,静态方法是基于类的

重写

子类里面定义了一个和父类里一个相同的方法,则叫重写

可以理解子类从父类那儿复制了一个方法,子类修改这个方法的时候,父类不会受影响

决定重写的因素

  1. 子类与父类之间
  2. 方法名和参数必须都相同

重写系统方法

因为Object是所有类的祖类,所以在自定义类中,是可以重写系统方法的

一些小细节

子类返回值类型和父类的返回值类型存在一个继承关系,则可以设定为不一样的返回值类型

访问修饰符也差不多意思,父类的修饰符只要大于子类的范围,子类就可以设定其他的修饰符

抽象类

如果一个class定义了方法,但没有具体执行代码,这个方法就是抽象方法,抽象方法用abstract修饰。

1
abstract class 类名{}

如果父类本身的方法不需要实现任何功能,仅仅是为了定义方法格式,目的是让子类去重写它,那么,就可以把父类声明为抽象方法

1
2
3
4
class 类名{
public abstract void run();
}
//会报错

包含抽象方法的父类,父类必须也为抽象类

1
2
3
abstrract class 类名{
public abstract void run();
}

抽象类本身是不能被实例化的,所以只能被用于继承

接口

当一个抽象类中的方法都是抽象的时候,这时候就可以用接口来表示

接口里面定义方法,里面定义的方法默认都是public abstract,所以修饰符都不用写出来

用interface来声明一个接口

1
2
3
4
interface 类名{
public static final 类型 变量名;//定义全局常量
返回值类型 方法名();
}

接口中的成员都是公共的权限

类与类是继承关系,类与接口是实现关系,接口不可以实例化

子类实现接口

子类实现接口时,需要用到implements关键,和普通继承不一样的是,子类可以选择实现多个接口

1
class 子类名 implements 接口1,接口2,接口3....{}

不要在多个接口里面,定义相同方法名的方法

一个类是可以继承一个父类,实现多个接口的

接口继承接口

接口可以通过extends关键字继承其他接口,可以多继承

1
interface  接口1 extends 接口2, 接口3, 接口4....

default方法

在接口中,也可以用default来修饰一个方法,被修饰的方法,子类在继承接口的时候,可以选择是否重写这个方法

1
2
3
4
interface 类名{
default void run();
String getName();
}

没被default所修饰的方法,子类里面必须要重写一遍的

default可以避免接口新增一个方法时,下面的子类都得重写

lambda表达式

1
2
3
(参数)->{
方法体
}

和js的箭头函数类似,实质上是一种简化过程,多用于函数式接口

lambda能省略的情况

​ ①、省略形参():当形参的个数有且只有1个的时候,同时省略形参的数据类型!
​ ②、省略{}:当方法体中有且只有一行代码的时候省略!
​ ③、省略形参的数据类型:当省略形参的数据类型将全部参数的类型都省略!
​ ④、省略return:当方法体中只有一个返回值的之后。省略return,但是要将{}一并省略!

接口和抽象类的区别

多数参考廖雪峰老师的java教程

访问修饰符

访问修饰符 同类中 同package中 不同package中 子类与父类之间(不在同一个包)
private:私有的 允许 不允许 不允许 不允许
缺省:家庭权限 允许 允许 不允许 不允许
protected:家族权限 允许 允许 不允许 ???
public公共的 允许 允许 允许 允许