Java11 多态,包,final关键字,权限修饰符,object类

一、多态

多态是指一个程序中相同名字表示不同含义的情况

多态有两种类型:a.编译时多态 (重载 overload; 如p.sayHello()  p.sayHello("11"))  b.运行时多态: (覆盖override 子类对父类进行覆盖 运行时系统根据调用该方法的实例的类型来决定选择哪个方法调用 所有的非final方法都会自动的进行动态绑定  虚方法调用可以实现运行时多态 ) 

Java中,普通的方法是虚方法  但是static、private,final方法不是虚方法

1.什么是多态?

同类型的对象,变现出不同的形态  ;(使用父类类型作为参数,可以接受所有子类的对象)

多态的表现形式:父亲类型 对象名称 = 子类对象  ;

多态的前提:有继承关系,有父类引用指向子类对象(FU f = new Zi),有方法重写;

package polymorphismdemo4;

public class Test {
    public static void main(String[] args) {
//创建对象
        Student s = new Student("张三",18);
        Teacher t = new Teacher("王老师",55);
        Administrator a = new Administrator("李管理",33);
    register(s);
    register(t);
    register(a);
    }
    //在测试类中写一个方法,既能接受老师,又能接受学生、管理员
    //参数只能写成这个三个类型的父类
    public static  void register(Person p){
        p.show();
    }
}

2.多态调用成员的特点

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

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

package polymorphismdemo5;

public class Test {
    public static void main(String[] args) {
        //创建对象(多态方式)
        Animal a = new Cat();
        //调用成员变量
        System.out.println(a.name); //输出动物
        //调用成员变量:编译看左边,javac编译代码的时候,会看左边的父类有没有这个变量,如果有,编译成功;反之,编译失败
        //运行看左边:java运行代码时,实际上获取的是左边父类成员变量的值
    //如果是 Cat a = new Cat() 这种方式创建对象 System.out.println(a.name); 输出的是小猫 

        //调用成员方法
        a.show();//运行的结果是Cat_____
        //编译看左边:编译看左边,javac编译代码的时候,会看左边的父类有没有这个方法,如果有,编译成功;反之,编译失败
        //运行看右边::java运行代码时,实际上运行的是子类中的方法
    }
}
class Animal {
    String name = "动物";

    public void show(){
        System.out.println("Animal_____");
    }
}
class Cat extends Animal {
    String name = "小猫";

    @Override
    public void show() {
        System.out.println("Cat_____");
    }
}


  3.多态的优势

        在多态的形式下,右边对象可以实现解耦合,便于拓展和维护

        定义一个方法时,使用父类型作为参数,可以接受所有的子对象,体现多态的拓展性与便利

4.多态的弊端

        不能调用子类特有的功能  解决方法:变回 子类类型  

eg:  Animal a = new Dog()   Dog d = (Dog) a; 转换的时候不能瞎转,如果转换成其他类的类型就会报错

//完整代码:
//先判断是不是Dog类型,如果不是先强转成Dog类型,如果不是,转换之后变量名为d
if (a instanceof Dog d){
    d.lookhome();
}else if(a instanceof Cat c){
c.catchMouse();
}else{
system.out.println("没有这个类型");
}

5. 上溯造型

将一种类型(子类)对象的引用转换成另外一种类型(父类)的对象引用(java中不需要任何特殊的标注,便允许上溯造型的使用)

上溯造型使得Java中允许创建不同类型对象的数组,但是这些类型必须都是数组声明类型或者数组声明类型的子类 如果声明的是object类,则数组中可以为任意数据类型

public class Main {
    public static void main(String[] args) {
        // 创建一个 Scanner 对象用于从控制台读取输入
        Scanner sc = new Scanner(System.in);
        // 读取一个整数 n,表示要创建的形状的数量
        int n = sc.nextInt();
        // 创建一个 Shape 类型的数组,长度为 n
        Shape[] shapes = new Shape[n];
        // 循环 n 次,创建不同的形状对象并存入数组
        for (int i = 0; i < n; i++) {
            // 读取一个字符串,判断是创建矩形还是圆形
            String str = sc.next();
            if ("rect".equals(str)) {
                // 如果是矩形,读取长度和宽度,创建矩形对象并存入数组
                int length = sc.nextInt();
                int width = sc.nextInt();
                shapes[i] = new Rectangle(length, width);
            } else {
                // 如果是圆形,读取半径,创建圆形对象并存入数组
                int radius = sc.nextInt();
                shapes[i] = new Circle(radius);
            }
        }
        // 输出所有形状的周长之和,调用 sumAllPerimeter 方法计算并返回
        System.out.println(sumAllPerimeter(shapes));
        // 输出所有形状的面积之和,调用 sumAllArea 方法计算并返回
        System.out.println(sumAllArea(shapes));
        // 输出所有形状的信息,使用 Arrays.deepToString 方法将数组转换为字符串输出
        System.out.println(Arrays.deepToString(shapes));

        // 遍历形状数组,输出每个形状的类型和父类型
        for (Shape shape : shapes) {
            // 输出形状的类型
            System.out.print(shape.getClass() + ",");
            // 输出形状的父类型
            System.out.println(shape.getClass().getSuperclass());
        }
    }

    // 编写 double sumAllArea 方法计算并返回传入的形状数组中所有对象的面积和
    public static double sumAllArea(Shape[] shapes) {
        double sum = 0;
        // 增强 for 循环遍历形状数组
        for (Shape shape : shapes) {
            // 将每个形状的面积累加到 sum 变量中
            sum += shape.getArea();
        }
        // 返回面积之和
        return sum;
    }

    // 编写 double sumAllPerimeter 方法计算并返回传入的形状数组中所有对象的周长和
    public static double sumAllPerimeter(Shape[] shapes) {
        double sum = 0;
        // 增强 for 循环遍历形状数组
        for (Shape shape : shapes) {
            // 将每个形状的周长累加到 sum 变量中
            sum += shape.getPerimeter();
        }
        // 返回周长之和
        return sum;
    }
}

6. 向下造型——对象的强制类型转换

将父类类型的对象强制变量强制转换为子类类型 Java中允许上溯造型的存在,使得父类类型的变量可以指向子类对象,但是通过该变量只能访问父类定义的方法和变量,子类特有的部分被隐藏;只有将父类类型强制转换为子类类型,才能通过该变量访问子类成员

7.

package polymorphismdemo6;

public class Person {
    private String name;
    private int age;
    public Person(){

    }
    public Person(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 void keepPet(Dog dog,String s){
//        System.out.println("年龄为"+age+"岁的"+name+"养了一只"+dog.getColor()+"颜色的"+dog.getAge()+"岁的狗");
//        dog.eat(s);
//    }
//    public void keepPet(Cat cat,String s){
//        System.out.println("年龄为"+age+"岁的"+name+"养了一只"+cat.getColor()+"颜色的"+cat.getAge()+"岁的狗");
//        cat.eat(s);
//    }//方法重载

    //想要一个方法,能够接受所有的动物,包括猫,包括狗
    //方法的形参可以写这些类的父类
    public void keepPet (fuAniaml a ,String s){
        if(a instanceof Dog d){
            System.out.println("年龄为"+age+"岁的"+name+"养了一只"+a.getColor()+"颜色的"+a.getAge()+"岁的狗");
            d.eat(s);
        }else if(a instanceof  Cat c){
            System.out.println("年龄为"+age+"岁的"+name+"养了一只"+a.getColor()+"颜色的"+a.getAge()+"岁的狗");
            c.eat(s);
        }else{
            System.out.println("没有这种动物");
        }

    }
}
package polymorphismdemo6;

public class Test {
    public static void main(String[] args) {
//        Person p1 =new Person("小明",23);
//        Dog d = new Dog (3,"黄w");
//        p1.keepPet(d,"骨头");
//
//        Person p2 =new Person("小红",19);
//        Cat c = new Cat(3,"红");
//        p2.keepPet(c,"鱼");

        Person p = new Person("小天",16);
        Dog d = new Dog(2,"黑");
        Cat c = new Cat(3,"红");
        p.keepPet(d,"骨头");
        p.keepPet(c,"🐟");

    }
}

     二、包

包就是文件夹,用来管理各种不同功能的Java类

包是相关类和接口的一个集合,有效的解决了命名冲突的问题

1.包名的规则 

        公司域名反写+包的作用,全部英文小写

2.导包

        a.使用同一个包中的类时,不需要导包

        b.使用java.lang包中的类时,不需要导包

        c.其他情况都需要导包

package 引入源程序,格式:

  import   包名.*;

  import   包名. 类名;

        d.如果同时使用两个包中的同类名,需要用全类名(包名.类名)

包定义语句在每个源程序中只能有一条,  即一个类只能属于一个包。

包定义语句必须在程序的第一行(之前可有空格及注释)。

包名用“.” 分隔。

3.包名与包中类的存储位置

包分隔符相当于目录分隔符,包存储的路径由包根路径加上包名指明的路径组成。包的根路径由CLASSPATH环境变量指出。

    三、final关键字

final可以修饰方法:表示该方法是最终方法,不能被重写;

final修饰类:表示该类是最终类,不被继承;

final修饰变量:叫做常量,只能赋值一次;

final修饰的变量是基本类型,那么变量存储的数据值不能发生改变;如果修饰的是引用类型,那么变量存储的地址值不能发生改变,对象内部的可以发生改变

1.常量命名规则

        单个单词全部大写;多个单词,全部大写,单词之间用下划线隔开

如果类的final变量在声明时没有赋初值,则所属类的每个构造方法中必须对该变量赋值;

如果未被赋初值的变量是局部变量,则可以在所属方法体中的任何位置对其赋值,但是只能赋一次

     四、权限修饰符

用来控制一个成员能够被访问的范围的,可以修饰变量、方法、构造方法、内部类

实际开发中:一般只用private和public , 成员变量私有 方法公开(如果方法在的代码是抽取其他方法中共性代码,这个方法一般也私有)

对于类的成员变量和方法可以有这四种访问级别;对于类(除了内部类)只有public和default两种

同一个类的不同对象之间可以访问对方的私有变量和方法,访问控制是在类的级别上,而不是对象的级别上

p86

      五、代码块

1.局部方法块:写在方法里面的局部代码块  提前结束变量的生命周期

2.构造代码块:写在成员位置的代码块;多个构造方法中重复的代码写在构造代码块里面;在创建本类对象的时候会优先执行构造代码块,在执行构造方法——(淘汰)

        当多个构造方法有重复的代码时可以:

3.静态代码块

        a.格式:static{}

        b.特点:需要通过static关键字修饰,睡着类的加载二加载,并且自动触发,只执行一次

        c.使用场景:在类加载的时候,做一些数据初始化的时候使用

        六、object类

1.Object定义了所有对象都需要的状态和行为。如对象之间的比较、将对象转换为字符串、等待某个条件变量、当某条件变量改变时通知相关对象以及返回对象的类。

2.clone()方法

可以将一个对象复制给另外一个对象 

aCloneableObject.clone()创建一个与其类型相同的对象,并将该对象成员变量的值初始化为aCloneableObject中成员变量的值

注意事项:提供复制能力的类必须自己实现Cloneable接口;该方法是浅复制,而不是深复制(如果被复制的对象成员是一个应用型变量,那么复制对象中将不包括该变量指向的对象

3.equals()方法

比较当前对象的引用是否与参数指向同一个对象

== 对于引用型变量比较的是这两个变量所指对象的地址,故比较两个字符串是否相同应该使用equals()方法  str1.equal(str2)

4.toString()

返回对象的字符串表示,表达的内容因具体的对象而异 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值