一、多态
-
面向对象三大特征:封装性、继承性、多态性。
-
extends继承或implements实现,是多态性的前提
(一)多态的概述
- 例如:小明是一个学生(学生形态),也是一个人(人类形态)。
- 小明是一个对象,这个对象既有学生形态也有人类形态。
- 定义:一个对象拥有多种形态,这就是对象的多态性。
(二)多态的格式与使用
- 代码当中体现多态性,其实就是:父类引用指向子类对象。
1、格式
父类名称 对象名 = new 子类名称 () ;
或者
接口名称 对象名 = new 实现类名称();
2、多态中成员变量和成员方法的使用
(1)多态中访问成员变量的两种方式(与之前相同):
- 直接通过对象名称访问成员变量,等号左边是谁,优先用谁,没有则向上查找。
- 间接通过成员方法进行访问,看该方法属于谁则优先用谁,没有则向上查找。
- 子类没有覆盖重写方法则使用父类,覆盖重写则使用子类
注意:成员变量不能覆盖重写。
(2)多态中成员方法的使用
- 看new的是谁,则优先用谁,没有则向上查找。
- 编译看左边,运行看右边。(成员变量:编译看左边,运行看左边)
public class Fu {
public void method(){
System.out.println("父类方法");
}
public void methodFu(){
System.out.println("父类独有!");
}
}
public class zi extends Fu {
@Override
public void method() {
System.out.println("子类方法");
}
public void methodzi(){
System.out.println("子类独有!");
}
}
public class Demo04 {
public static void main(String[] args) {
//创建一个子类多态对象
Fu one = new zi();
//调用子类方法
one.method();
//编译看左边,引用的为父类方法,父类方法中没有methodzi方法
//one.methodzi();
//运行看右边,子类方法中继承了父类方法
one.methodFu();
}
}
输出为:
子类方法
父类独有!
Process finished with exit code 0
(3)多态的好处
- 无论右边new的时候换成哪个子类对象,等号左边的调用方法都不会变化。
public abstract class employee {
public abstract void work();
}
public class teacher extends employee {
@Override
public void work() {
System.out.println("我来讲课!");
}
}
public class assistant extends employee {
@Override
public void work() {
System.out.println("我来辅导!");
}
}
public class Demo04 {
public static void main(String[] args) {
//不使用多态将代用多个不同的子类方法
teacher one =new teacher();
one.work();
assistant two =new assistant();
two.work();
for (int i = 0; i < 10; i++) {
System.out.print("==");
}
System.out.println("\n");
//使用多态将只调用一种方法
employee three = new teacher();
three.work();
employee four = new assistant();
four.work();
}
}
输出为:
我来讲课!
我来辅导!
====================
我来讲课!
我来辅导!
(4)对象的向上转型
- 定义:对象的向上转型,其实就是多态写法。(即父类引用指向子类对象)
- 格式:父类名称 对象名 = new 子类名称 ( ) ;
- 含义:右侧创建一个子类对象,将它当作父类看待。
- 注意:向上转型一定是安全的。类似于数据类型的自动转换。
(5)对象的向下转型
- 向上转型有一定弊端:一旦向上转型为父类,则无法调用子类原本特有的内容。
- 解决方案:用对象的向下转型【还原】。类似于数据类型的强制类型转换。
- 格式:子类名称 对象名 =(子类名称)父类对象;
- 含义:将父类对象还原成为本来的子类对象。
- 注意:必须保证对象本来创建的时候就是该子类,不能转换为其他子类。
-
public abstract class Aniamls { public abstract void eat(); public abstract void sleep(); } public class cat extends Aniamls{ @Override public void eat() { System.out.println("吃小鱼干!"); } @Override public void sleep() { System.out.println("喵呜~"); } public void catchmouse(){ System.out.println("抓老鼠!"); } } public class Demo04 { public static void main(String[] args) { Aniamls xiaoju=new cat(); //向下转化 cat cat1= (cat) xiaoju; cat1.catchmouse(); } } //输出为:抓老鼠!
(6)用instanceof关键字进行类型判断
- 即判断父类引用的对象,本来是什么子类,通常用于向下转型的类型判断。
格式:对象 instanceof 类型
- 这将会得到一个Boolean值结果,也就是判断前面的对象能不能当作后面类型的实例
public class pet {
public static void main(String[] args) {
pet(new cat());
for (int i = 0; i < 20; i++) {
System.out.print("=");
}
System.out.println("\n");
pet(new dog());
}
public static void pet(Aniamls animal) {
//使用instanceof关键字判断类型
if (animal instanceof cat) {
cat cat = (cat) animal;
cat.catchmouse();
cat.eat();
}
if (animal instanceof dog) {
dog dog = (dog) animal;
dog.eat();
dog.sleep();
}
}
}
输出为:
抓老鼠!
吃小鱼干!
====================
吃骨头
呼噜噜.......
(三)笔记本USB接口案例
1、问题:定义USB接口,具备最基本的开启功能和关闭功能,鼠标和键盘要想在电脑上使用,那么鼠标和键盘也必须遵守USB规范,实现USB接口,否则鼠标和键盘生产出来无法使用。
2、分析
3、代码实现
//定义一个USB接口
public interface USB {
public abstract void open();
//打开设备
public abstract void close();
//关闭设备
}
//定义一个鼠标类
public class mouse implements USB{
@Override
public void open() {
System.out.println("已接入鼠标。");
}
@Override
public void close() {
System.out.println("已拔出鼠标。");
}
public void name(String name){
System.out.println("这款鼠标的型号为:"+name);
}
}
//定义一个键盘类
public class keyborad implements USB {
@Override
public void open() {
System.out.println("已接入键盘。");
}
@Override
public void close() {
System.out.println("已拔出键盘。");
}
public void keyname(String name){
System.out.println("这款键盘的型号为:"+name);
}
}
//定义一个笔记本类
public class laptop {
public void type(String name){
System.out.println("这款笔记本电脑的型号为:"+name);
}
public void poweron(){
System.out.println("您的电脑,正在开机,请稍后。");
for (int i = 1; i <=10 ; i++) {
System.out.print(i+"s"+"\t");
}
System.out.println("\n您的设备已开机,欢迎使用。");
}
public void poweroff(){
System.out.println("您的电脑,正在关机,请稍后。");
for (int i = 1; i <=5; i++) {
System.out.print(i+"s"+"\t");
}
System.out.println("\n您的设备已关机,谢谢使用。");
}
public void laptophard(USB usb){
if (usb instanceof mouse){
usb.open();
usb.close();
}
if(usb instanceof keyborad)
{
usb.open();
usb.close();
}
}
}
//创建一个对象
public class mylaptop {
public static void main(String[] args) {
//创建一个笔记本对象
laptop mylaptop=new laptop();
mylaptop.type("拯救者2020Y7000P");
mylaptop.poweron();
USB mymouse=new mouse();
mouse my=(mouse) mymouse;
my.name("罗技350");
USB mykeborad=new keyborad();
keyborad mykey=(keyborad) mykeborad;
mykey.keyname("牧马人2000");
mylaptop.laptophard(mymouse);
mylaptop.laptophard(mykeborad);
mylaptop. poweroff();
}
}
输出为:
这款笔记本电脑的型号为:拯救者2020Y7000P
您的电脑,正在开机,请稍后。
1s 2s 3s 4s 5s 6s 7s 8s 9s 10s
您的设备已开机,欢迎使用。
这款鼠标的型号为:罗技350
这款键盘的型号为:牧马人2000
已接入鼠标。
已拔出鼠标。
已接入键盘。
已拔出键盘。
您的电脑,正在关机,请稍后。
1s 2s 3s 4s 5s
您的设备已关机,谢谢使用。
Process finished with exit code 0
二、final关键字
(一)final关键字的概念及四种用法
1、final关键字的概念
- final关键字代表最终、不可改变的
2、四种用法
- 修饰一个类
- 修饰一个方法
- 修饰一个局部变量
- 修饰一个成员变量
(二)四种用法的使用
1、修饰一个类
- 任何一个类都是Object的子类
- 格式:public final class 类名称 { ...}
- 含义:当前这个类不能有任何的子类,但可以拥有父类。
- 注意:一个类如果是final类,那么其中的成员方法都无法进行覆盖重写,但可以对其父类进行覆盖重写
2、修饰一个方法
- 当final关键字用来修饰一个方法的时候,这个方法就是最终方法,也就是不能被覆盖重写。
- 格式:修饰符 final 返回值类型 方法名称 (参数列表){...}
- 注意:对于类、方法来说,abstract关键字和final关键字不能能够同时使用,因为两者矛盾。
3、修饰一个局部变量
- 局部变量:方法中使用的变量,方法的参数也属于局部变量
- 一旦使用final用来修饰局部变量,那么这个变量就不能再进行更改,即使用final关键字进行修饰后,只能进行一次赋值且之后不可改变。
- 对于基本类型来说,不可变说的是变量当中的数据不可改变。
- 对于引用类型来说,不可变说的是变量当中的地址值不可改变,但可以改变其中的内容。
例如:
public class name {
private String name;
private int age;
public name(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class main {
public static void main(String[] args) {
name name1=new name("zhangsan",18);
System.out.println(name1.getName()+" "+name1.getAge());
System.out.println(name1);
name1=new name("lisi",19);//未用final修饰时,地址值可以改变
System.out.println(name1.getName()+" "+name1.getAge());
final name name2=new name("wangmazi",20);
System.out.println(name1);
//name2=new name("zhangwu",12)
//使用final修饰后地址值不可变,但其中的内容可以改变
name2.setName("wangwu");
name2.setAge(21);
System.out.println(name2.getName()+" "+name2.getAge());
}
}
输出为:
zhangsan 18
Demo01.name@12edcd21
lisi 19
Demo01.name@34c45dca
wangwu 21
Process finished with exit code 0
4、修饰一个局部变量
- 对于成员变量来说,final关键字修饰后,这个变量也照样不可改变。
- 由于成员变量具有默认值,所以用了final之后必须手动赋值,不会再给默认值了。
- 对于final的成员变量来说,要么使用直接复制,要么通过构造方法赋值。
- 必须保证类当中的所有重载的构造方法,都最终会对final的成员变量进行赋值。
例如:
public class students {
final private String name;
final private int age=18;
//使用final修饰后,在构造方法中赋值,且不能使用setter方法
public students() {
name = "zhangssan";
}
public String getName() {
return name;
}
public int getAge(){
return age;
}
}
public class main1 {
public static void main(String[] args) {
students stu = new students();
System.out.println(stu.getName()+' '+stu.getAge());
}
}
//输出为:zhangsan 18
5、四种权限修饰符
四种修饰符/不同场景访问 | public | protected | (default) | private |
同一个类(我自己) | YES | YES | YES | YES |
同一个包(我邻居) | YES | YES | YES | NO |
不同包子类(我儿子) | YES | YES | NO | NO |
不同包非子类(陌生人) | YES | NO | NO | NO |
- 注意:不同包访问类需要进行导包,使用import语句