day14 多态&包&权限修饰符&代码块

今日内容

  • 多态

  • final

  • 权限修饰符

  • 代码块

第一章 多态

1.1 多态的形式

多态是继封装、继承之后,面向对象的第三大特性。

多态是出现在继承或者实现关系中的

多态体现的格式

 父类类型 变量名 = new 子类/实现类构造器;
 变量名.方法名();

多态的前提:有继承关系,子类对象是可以赋值给父类类型的变量。

1.2 多态的使用场景

有了多态之后,方法的形参就可以定义为共同的父类Person。

 父类:
 public class Person {
     private String name;
     private int age;
 ​
     空参构造
     带全部参数的构造
     get和set方法
 ​
     public void show(){
         System.out.println(name + ", " + age);
     }
 }
 
子类1:
 public class Administrator extends Person {
     @Override
     public void show() {
         System.out.println("管理员的信息为:" + getName() + ", " + getAge());
     }
 }
 ​
 子类2:
 public class Student extends Person{
 ​
     @Override
     public void show() {
         System.out.println("学生的信息为:" + getName() + ", " + getAge());
     }
 }

子类3:
 public class Teacher extends Person{
 ​
     @Override
     public void show() {
         System.out.println("老师的信息为:" + getName() + ", " + getAge());
     }
 }
 ​
 
 父类:
 public class Person {
     private String name;
     private int age;
 ​
     空参构造
     带全部参数的构造
     get和set方法
 ​
     public void show(){
         System.out.println(name + ", " + age);
     }
 }

1.3 多态的定义和前提

多态: 是指同一行为,具有多个不同表现形式。

前提【重点】

  1. 有继承或者实现关系

  2. 方法的重写【意义体现:不重写,无意义】

  3. 父类引用指向子类对象【格式体现】

    父类类型:指子类对象继承的父类类型,或者实现的父接口类型。

1.4 多态的运行特点

调用成员变量时:编译看左边,运行看左边

调用成员方法时:编译看左边,运行看右边

 Fu f = new Zi();
 //编译看左边的父类中有没有name这个属性,没有就报错
 //在实际运行的时候,把父类name属性的值打印出来
 System.out.println(f.name);
 //编译看左边的父类中有没有show这个方法,没有就报错
 //在实际运行的时候,运行的是子类中的show方法
 f.show();

1.5 多态的弊端

我们已经知道多态编译阶段是看左边父类类型的,如果子类有些独有的功能,此时多态的写法就无法访问子类独有功能了

1.6 引用类型转换

多态的写法就无法访问子类独有功能了。

想要调用子类特有的方法,必须做向下转型。

回顾基本数据类型转换

  • 自动转换: 范围小的赋值给范围大的.自动完成:double d = 5;

  • 强制转换: 范围大的赋值给范围小的,强制转换:int i = (int)3.14

多态的转型分为向上转型(自动转换)与向下转型(强制转换)两种。

1.6.2 向上转型(自动转换)

  • 向上转型:多态本身是子类类型向父类类型向上转换(自动转换)的过程,这个过程是默认的。 当父类引用指向一个子类对象时,便是向上转型。 使用格式:

 父类类型  变量名 = new 子类类型();
 如:Animal a = new Cat();

1.6.3 向下转型(强制转换)

  • 向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。 一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。

子类类型 变量名 = (子类类型) 父类变量名;
 如:Aniaml a = new Cat();
    Cat c =(Cat) a;  

1.6.4 案例演示

 abstract class Animal {  
     abstract void eat();  
 }  
 ​
 class Cat extends Animal {  
     public void eat() {  
         System.out.println("吃鱼");  
     }  
     public void catchMouse() {  
         System.out.println("抓老鼠");  
     }  
 }  
 ​
 class Dog extends Animal {  
     public void eat() {  
         System.out.println("吃骨头");  
     }  
     public void watchHouse() {  
         System.out.println("看家");  
     }  
 }

定义测试类:

 public class Test {
     public static void main(String[] args) {
         // 向上转型  
         Animal a = new Cat();  
         a.eat();                // 调用的是 Cat 的 eat
 ​
         // 向下转型  
         Cat c = (Cat)a;       
         c.catchMouse();         // 调用的是 Cat 的 catchMouse
     }  
 }

1.6.5 转型的异常

转型的过程中,一不小心就会遇到这样的问题,请看如下代码:

    // 向上转型  
         Animal a = new Cat();  
         a.eat();               // 调用的是 Cat 的 eat
 ​
         // 向下转型  
         Dog d = (Dog)a;       
         d.watchHouse();        // 调用的是 Dog 的 watchHouse 【运行报错】

这段代码可以通过编译,但是运行时,却报出了 ClassCastException ,类型转换异常!这是因为,明明创建了Cat类型对象,运行时,当然不能转换成Dog对象的。

1.6.6 instanceof关键字

为了避免ClassCastException的发生,Java提供了 instanceof 关键字,给引用变量做类型的校验,格式如下:

 变量名 instanceof 数据类型 
 如果变量属于该数据类型或者其子类类型,返回true。
 如果变量不属于该数据类型或者其子类类型,返回false。

所以,转换前,我们最好先做一个判断,代码如下:

 public class Test {
     public static void main(String[] args) {
         // 向上转型  
         Animal a = new Cat();  
         a.eat();               // 调用的是 Cat 的 eat
 ​
         // 向下转型  
         if (a instanceof Cat){
             Cat c = (Cat)a;       
             c.catchMouse();        // 调用的是 Cat 的 catchMouse
         } else if (a instanceof Dog){
             Dog d = (Dog)a;       
             d.watchHouse();       // 调用的是 Dog 的 watchHouse
         }
     }  
 }
 //新特性
 //先判断a是否为Dog类型,如果是,则强转成Dog类型,转换之后变量名为d
 //如果不是,则不强转,结果直接是false
 if(a instanceof Dog d){
     d.lookHome();
 }else if(a instanceof Cat c){
     c.catchMouse();
 }else{
     System.out.println("没有这个类型,无法转换");
 }

第二章 包

2.1 包

包在操作系统中其实就是一个文件夹。包是用来分门别类的管理技术,不同的技术类放在不同的包下,方便管理和维护。

包名的命名规范

 路径名.路径名.xxx.xxx
 // 例如:com.itheima.oa
  • 包名一般是公司域名的倒写。例如:黑马是www.itheima.com,包名就可以定义成com.itheima.技术名称。

  • 包名必须用”.“连接。

  • 包名的每个路径名必须是一个合法的标识符,而且不能是Java的关键字。

第三章 权限修饰符

3.1 权限修饰符

  • public:公共的,所有地方都可以访问。

  • protected:本类 ,本包,其他包中的子类都可以访问。

  • 默认(没有修饰符):本类 ,本包可以访问。

    注意:默认是空着不写,不是default

  • private:私有的,当前类可以访问。 public > protected > 默认 > private

3.2 不同权限的访问能力

PUBLICPROTECTED默认PRIVATE
同一类中
同一包中的类
不同包的子类
不同包中的无关类
  • 成员变量使用private ,隐藏细节。

  • 构造方法使用public ,方便创建对象。

  • 成员方法使用public ,方便调用方法。

小贴士:不加权限修饰符,就是默认权限

第四章 final关键字

4.1 概述

  • final: 不可改变,最终的含义。可以用于修饰类、方法和变量。

    • 类:被修饰的类,不能被继承。

    • 方法:被修饰的方法,不能被重写。

    • 变量:被修饰的变量,有且仅能被赋值一次。

4.2 使用方式

4.2.1 修饰类

final修饰的类,不能被继承。

 final class 类名 {
 }

4.2.2 修饰方法

final修饰的方法,不能被重写。

 修饰符 final 返回值类型 方法名(参数列表){
     //方法体
 }

代码:

 class Fu2 {
     final public void show1() {
         System.out.println("Fu2 show1");
     }
     public void show2() {
         System.out.println("Fu2 show2");
     }
 }

4.2.3 修饰变量-局部变量

  1. 局部变量——基本类型 基本类型的局部变量,被final修饰后,只能赋值一次,不能再更改。

  // 声明变量,直接赋值,使用final修饰
         final int b = 10;
         // 第二次赋值
         b = 20; // 报错,不可重新赋值

写法1:

 final int c = 0;
 for (int i = 0; i < 10; i++) {
     c = i;
     System.out.println(c);
 }//报错

写法2:

 for (int i = 0; i < 10; i++) {
     final int c = i;
     System.out.println(c);
 }//通过
 //每次循环,都是一次新的变量c

4.2.4 修饰变量-成员变量

  • 显示初始化(在定义成员变量的时候立马赋值)(常用);

 public class Student {
     final int num = 10;
 }
  • 构造方法初始化(在构造方法中赋值一次)(不常用,了解即可)。

    注意:每个构造方法中都要赋值一次!

 public class Student {
     final int num = 10;
     final int num2;
 ​
     public Student() {
         this.num2 = 20;
 //     this.num2 = 20;
     }
     
      public Student(String name) {
         this.num2 = 20;
 //     this.num2 = 20;
     }
 }

被final修饰的常量名称,一般都有书写规范,所有字母都大写

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值