代码当中体现多态性,其实就是一句话:父类引用指向子类对象。
格式:
父类名称 对象名 = new 子类名称();
或者:
接口名称 对象名 = new 实现类名称();
访问成员变量的两种方式:
- 直接通过对象名称访问成员变量:看等号左边是谁,优先用谁,没有则向上找
- 间接通过成员方法访问成员变量:看该方法属于谁,优先用谁,没有则向上找
在多态的代码当中,成员方法的访问规则是:
看new的是谁,就优先用谁,没有则向上找
口诀:
成员变量:编译看左边,运行还看左边
成员方法:编译看左边,运行看右边
- 对象的向上转型,其实就是多态的写法:
格式 :
父类名称 对象名 = new 子类名称();
注意事项:向上转型一定是安全的。从小范围转向了大范围。-
向上转型一定是安全的,没有问题的,但是也有一个弊端,对象一旦向上转型为父类,那么就无法调用子类原有的内容。 - 对象的向下转型,其实就是一个还原的动作
格式:
子类名称 对象名 = (子类名称)父类对象
含义:将父类对象,还原成为本来的子类对象
注意事项:
a:必须保证对象本来创建的时候就是猫,才能向下转型成为猫
b:如果对象创建的时候本来不是猫,现在非要向下转型成为猫,就会报错
如何才能知道一个父类引用的对象本来是什么子类?
格式:
对象 instanceof 类名称
这将会得到一个boolean值结果,也就是判断前面的对象能不能当中后面类型的实例
例:笔记本USB接口案例
final关键字代表最终的、不可变的
常见的四种用法:
- 可以用来修饰一个类;
- 可以用来修饰一个方法;
- 可以用来修饰一个局部变量;
- 可以用来修饰一个成员变量;
当final关键字用来修饰一个类的时候,格式:
public final class 类名称{
//…
}
含义:当前这个类不能有任何的子类。
注意:一个类如果是final的,那么其中所有的成员方法都无法进行覆盖重写
当final关键字用来修饰一个方法的时候,这个方法就是最终方法,也就是不能覆盖重写
格式:
修饰符 final 返回值类型 方法名称(参数列表){
//方法体
}
注意事项:对于类、方法来说,abstract关键字和final关键字不能同时使用,因为矛盾。
一旦使用final用来修饰局部变量,那么这个变量就不能进行更改。
对于基本类型来说,不可变说的是变量当中的数据不可变
对于引用类型来说,不可变说的是变量当中的地址值不可改变
对于成员变量来说,如果使用final关键字修饰,那么这个变量也照样是不可变的。
- 由于成员变量有默认值,所以用了final之后必须进行手动赋值,不会再给默认值了
- 对于final的成员变量,要么使用直接赋值,要么通过构造方法赋值。
- 必须保证类当中的所有重载的构造方法,都最终对对final的成员变量进行赋值。
访问控制权限修饰符:
- 访问控制权限修饰符来控制元素的访问范围
- 访问控制权限修饰符包括:
1. public 表示公开的,在任何位置都可以访问
2. protected 同包,子类
3. 缺省(default) 同包
4. private 表示私有的,只能在本类中访问 - 访问控制权限修饰符可以修饰类、变量、方法…
- 当某个数据只希望子类使用,使用protected进行修饰
- 修饰符的范围:
private < 缺省 < protected < public
类只能采用public和缺省的修饰符进行修饰。【内部类除外】
如果一个事物的内部包含另一个事物,那么这就是也够累内部包含另一个类。
分类:
- 成员内部类
- 局部内部类(包含匿名内部类)
成员内部类的定义格式:
修饰符 class 外部类名称{
修饰符 class 内部类名称{
//…
}
//…
}
注意:内部用外部,随意访问;外部用内部需要内部类对象。
如何使用成员内部类?有两种方式:
- 间接方式:在外部类的方法当中,使用内部类,然后main只是调用外部类的方法。
- 直接方法,公式:
外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
如果一个类是定义在一个方法内部的,那么这就是一个局部内部类。
“局部”:只有当前所属的方法才能使用它,出了这个方法外面就不能用了。
定义格式:
修饰符 class 外部类名称{
修饰符 返回值类型 外部类方法名称(参数列表){
class 局部内部类名称{
//…
}
}
}
小结类的权限修饰符:
public > protect > (default) > private
定义一个类的时候,权限修饰符规则:
- 外部类:public / (default)
- 成员内部类:public / protect / (default)/ private
- 局部内部类:什么都不能写
局部内部类:如果希望访问所在方法的局部变量,那么这个局部变量必须是【有效final的】
原因:
- new出来的对象在堆内存中;
- 局部变量是跟着方法走的,在栈内存当中;
- 方法运行结束之后,立即出栈,局部变量就会立刻消失;
- 但是new出来的对象会在堆内存中持续存在,直到垃圾回收消失;
匿名内部类
如果接口的实现类(或者是父类的子类)只需要使用唯一的一次,那么这种情况下就可以省略掉该类的定义,而改为使用【匿名内部类】。
匿名内部类的定义格式:
接口名称 对象名 = new 接口名称(){
// 覆盖重写所有抽象方法
};
对格式“new 接口名称(){…}”进行解析:
- new代表创建对象的动作
- 接口名称就是匿名内部类需要实现哪个接口
- {…}这才是匿名内部类的内容
另外还需要注意的几点问题
- 匿名内部类,在【创建对象】的时候只能使用一次
如果希望多次创建对象,而且类的内容一样的话,那么就必须使用单独定义的实现类了 - 匿名对象,在【调用方法】的时候,只能调用唯一一次
如果希望创建同一个对象,调用了多次方法,那么必须给对象起个名字 - 匿名内部类是省略了【实现类/子类名称】,但是匿名对象是省略了【对象名称】
强调:匿名内部类和匿名对象不是一回事!!!