java复习面向对象(二)

java复习面向对象(二)

1、static关键字

  • 举例图片

image-20211102155811169

  • 静态变量
    • 使用static修饰的成员变量是静态变量

    • 如果一个成员变量使用了关键字static,那么这个变量不属于对象自己,而属于所在的类多个对象共享同一份数据
      
    • 推荐写法:类.静态变量,该写法可以直接观看出变量是静态变量;

    • 不推荐写法:对象.静态变量

      • 写成对象名.静态变量,javac编译的时候会编译成类.静态变量
  • 静态方法
    • 使用static修饰的成员方法是静态方法
    • 1、静态不能直接访问非静态;
      • 内存中有静态的内容,有非静态的内容。类似与先人不知道后人,但后人知道先人。
    • 2、静态方法中不能使用this
      • 原因:this代指当前对象,谁调用方法,谁就是当前对象。
  • 一旦使用了static修饰的成员方法,那么就成为了静态方法。静态方法不属于对象,而属于类。
    如果没有static关键字,那么必须首先创建对象,然后才能通过对象使用他;
    如果有static关键字,那么不需要创建对象,直接通过类名就能使用它;
    无论是成员变量还是成员方法。如果有了static关键字修饰,都推荐使用类名进行调用。
    静态变量:类名称.静态变量;
    静态方法:类名称.静态方法;
    注意:
    1、静态不能直接访问非静态;
    - 内存中**先**有静态的内容,**后**有非静态的内容。类似与先人不知道后人,但后人知道先人。
    2、静态方法中不能使用this
    原因:this代指当前对象,谁调用方法,谁就是当前对象。
    

1.1代码示例

  • package com.one;
    
    public class DemoStatic {
    
        public static void main(String[] args) {
            Student one =new Student("章北海",35);
    
            one.room="自然选择号";//正确写法但是不推荐
            //写成对象名.静态变量,javac编译的时候会编译成`类.静态变量`
            Student.room="蓝色空间号";//推荐写法,直接看出来room是静态变量
            Student two =new Student("东方延续",35);
            System.out.println(two.getName()+"是"+two.room+"舰长"+two.getId());//东方延续是自然选择号舰长,并未设置,但是会共享数据
            System.out.println("===============================");
            MyClass.mystatic();
            MyClass myone= new MyClass();
            myone.method();
        }
    }
    
    
  
- ```jaVA
  package com.one;
  
  public class Student {
      private int id;
      private String name;
      private int age;
      //如果一个成员变量使用了关键字static,那么这个变量不属于对象自己,而属于所在的类多个对象共享同一份数据
      static String room;
      private static int idCounter=0;//学号计数器,每当new了一个对象的时候计数器++
      //生成全参的构造方法
      public Student(String name, int age) {
          this.name = name;
          this.age = age;
          this.id=idCounter++;
      }
      //生成无参的构造方法
      public Student() {
          idCounter++;
      }
      /*生成对应的访问和设置函数*/
      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 int getId() {
          return id;
      }
  
      public void setId(int id) {
          this.id = id;
      }
  }
  • package com.one
    public class MyClass {
        int num=0;
        static int numstatic=1;
        public static void mystatic(){
            System.out.println("我是一个静态方法");
            //System.out.println(this);//报错,静态方法中不能写this;
            //System.out.println(num);//静态方法不能直接访问成员变量
            System.out.println("静态方法可以直接访问静态变量"+numstatic);//静态方法可以直接访问静态变量
        }
        public void method(){
            System.out.println("我是一个不同的成员方法");
            System.out.println("成员方法可以直接访问成员变量"+num);
            System.out.println("成员方法可以直接访问静态变量"+numstatic);
            //成员方法可以直接调用静态方法不用写类名
            mystatic();
        }
    }
    

1.2 静态内存图

image-20211102172549336

1.3 静态代码块

  • 特点;当第一次用到本类的时候,静态代码块执行唯一的一次

  • 静态内容总是先于非静态加载,所以静态代码块比构造方法先执行

  • 静态代码块的用途

    • 用来一次性地对静态成员变量进行赋值
    • 经常用于JDBCZ中的。
  • 静态代码块:
    类{
        static{
            //静态代块的内容
        }
    }
    
  • public class Person {
        static {
            System.out.println("静态代码执行");
        }
        public Person(){
            System.out.println("构造方法执行");
        }
    }
    
  • package com.one;
    
    public class Demo1 {
        public static void main(String[] args) {
            Person one=new Person();
            Person two=new Person();
            /*console
            静态代码执行
            构造方法执行
            构造方法执行*/
        }
    }
    

2、继承

  • 继承是多态的前提,如果没有继承就没有多态

  • 继承主要解决的就是共性抽取

  • 图示

    image-20211102203719821

2.1继承的特点与语法

  • 特点
    • 子类可以用友父类的“内容”
    • 子类还可以用友自己的专有内容
  • 语法
    //在继承关系中,“子类就是一个父类”,也就是说子类可以被当做父类看待
    //例如:父类是员工,子类是讲师,那么讲师就是一个员工;关系is-a
    // 父类的格式就是普通类的定义格式;
    
    package com.one;
    
    public class Employee {
        int num=100;
        public void method(){
            System.out.println("我是员工类中的的方法");
        }
    }
    
    
    package com.one;
    //继承的格式
    public class Teacher extends Employee{
        int num=200;
        public void methodZi(){
            //就近使用本类中的num,没有则想上寻找
            System.out.println(num);
        }
        public void three(){
            int num=300;
            System.out.println("局部变量"+num);//局部变量300
            System.out.println("本类成员变量"+this.num);//本类成员变量200
            System.out.println("父类的成员变量"+super.num);//父类的成员变量100
        }
    }
    
    
    package com.one;
    /*
    在父类的继承关系中,如果成员变量重名,则创建子类对象时,访问有两种方式
    直接通过子类对象访问成员变量
        等号左边是谁,就优先用谁,没有则向上找
    间接通过成员方法访问成员变量
        该方法属于谁,就优先用谁,没有则向上找
    即:就近原则
    * */
    public class DemoExtends {
        public static void main(String[] args) {
            Teacher teacher= new Teacher();
            teacher.method();//我是员工类中的的方法;执行了员工类中方法;
            System.out.println(teacher.num);
            teacher.methodZi();//200
            teacher.methodFu();//100
        }
    }
    
  • 补充知识点
    //三种变量的使用方法
    System.out.println("局部变量"+num);//局部变量300
    System.out.println("本类成员变量"+this.num);//本类成员变量200
    System.out.println("父类的成员变量"+super.num);//父类的成员变量100
    

2.2 重名方法的执行

  • 创建的对象是谁就优先用谁如果没有,则向上找;
  • 无论是成员方法还是成员变量,如果没有都是向上找父类,不会向下找子类

2.3 覆盖重写

  • 重写(Override)
    • 继承关系当中,方法的名称一样参数列表一样
    • 重写也叫覆盖,覆写
    • 特点:创建的是子类对象,优先用子类方法;
  • 重载(Overload)
    • 同一类中方法的名称一样,参数的列表不一样

2.4 注意事项

  • 注解@Override
    • 覆盖重写时必须保证父子类方法名称相同,参数列表也相同。
    • @Override:写在方法前面用来检测是不是有效的覆盖重写
    • 这个注解就算不写,也是正确的的方法覆盖重写;
  • 返回值
    • 子类的返回值必须小于等于父类的返回值范围
    • 扩展:java.lang.Object类是所有类的父类,
  • 权限修饰符
    • 权限等级:public>protected>(default)>private

    • defualt不是关键字,而是什么都不写留空

    • 子类方法的权限必须要大于等于父类的权限
  • package cn.day03;
    
    public class Fu {
        public void method(){
            System.out.println("父类的方法");
        }
        void sayhello(){
            //默认权限等级是(default)
            System.out.println("我是父类");
        }
        public Object showclass(){
            return null;
        }
    }
    
    
  • package cn.day03;
    
    public class Zi extends Fu{
        @Override//本注解检测是不是有效的覆盖重写,可以不写,一般都会写上
        public void method(){
            System.out.println("子类的方法");
        }
        @Override
        public void sayhello(){
            System.out.println("我的权限等级大于(default)");
        }
        @Override
        public String showclass(){
            //String属于子类返回值小于等于父类烦人范围
            return "HELLO WORLD";
        }
    }
    
    
  • package cn.day03;
    
    public class DemoExtends {
        public static void main(String[] args) {
            Zi zi=new Zi();
            zi.method();
            String str=zi.showclass();
            System.out.println(str);
        }
    }
    /*console
    子类的方法
    HELLO WORLD
    */
    

2.5 继承中的构造方法

  • 子类构造方法中默认隐含的super()调用,所以一定先调用父类构造,后执行子类的构造。

  • 子类的构造可以通过super关键字调用父类的重载构造。

  • super父类构造调用,必须是子类构造方法的第一个语句。不能一个子类调用多个super构造。

  • 总结
    • 子类必须地调用父类的构造方法,不写则赠送super(),写了则用指定的super调用,super只能有一个还必须是第一个;
  • package cn.day03;
    
    public class Fu {
        public Fu(){
            System.out.println("父类构造方法");
        }
        public Fu(int num){
            System.out.println("父类重载构造方方法");
        }
    }
    
  • package cn.day03;
    
    public class Zi extends Fu{
        public Zi(){
            super(20);//调用父类重载的有参构造方法,必须写在构造方法的第一行;
            System.out.println("子类构造方法");
        }
    }    
    
    
  • package cn.day03;
    
    public class DemoExtends {
        public static void main(String[] args) {
            Zi zi=new Zi();
        }
    }
    /*
    父类重载构造方方法
    子类构造方法
    */
    

2.6 继承的三大特征

  • Java语言是单继承
    • 一个类的直接父类只能有唯一一个
  • JAVA可以多重继承
    • Object是所有类的父类;java.lang.Object
  • 一个父类的直接父类是唯一的,但是一个父类可以拥有多个子类
  • image-20211103145436739
  • 对比:Python语言是多继承的,Python中类可以继承多个类;

2.7 继承的小案例

  • 群主发红包
  • package demo.jc;
    
    public class User {
        private double money;
        private String name;
    
        public User() {
    
        }
    
        public User(double money, String name) {
            this.money = money;
            this.name = name;
        }
        public void show(){
            System.out.println("我是"+name+"我有"+money+"块钱");
        }
    
        public double getMoney() {
            return money;
        }
    
        public void setMoney(double money) {
            this.money = money;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    
  • package demo.jc;
    
    import java.util.ArrayList;
    
    public class Manger extends User{
        public Manger() {
        }
    
        public Manger(double money, String name) {
            super(money, name);
        }
    
        public ArrayList<Double> send(double totalmoney,int count){
            //创建一个集合,用来存储红包金额
            ArrayList<Double> redlist =new ArrayList<>();
    
            //首先查看群主有多少钱
            double leftMoney=super.getMoney();
            if(totalmoney>leftMoney){
                System.out.println("余额不足");
                return redlist;//返回空集合
            }
            //扣钱,在重新设置余额
            super.setMoney(totalmoney-leftMoney);
            double avg=totalmoney/count;
            double mod=totalmoney%count;
            //除不开的余数放在最后一个红包中
            /*count.fori*///直接生成for循环
            for (int i = 0; i < count-1; i++) {
                redlist.add(avg);
            }
            //最后一个红包设置大的金额
            double last=avg+mod;
            redlist.add(last);
            return redlist;
        }
    }
    
    
  • package demo.jc;
    
    import java.util.ArrayList;
    import java.util.Random;
    
    public class Member extends User{
        public Member() {
        }
    
        public Member(double money, String name) {
            super(money, name);
        }
        public void recive(ArrayList<Double> list){
            //使用random的匿名对象,使用size获取列表长度;设置好范围
            int index=new Random().nextInt(list.size());
            //使用remove从当前集合删除,并返回对应值;即获得抢到的红包,
            double delta=list.remove(index);
            double money=super.getMoney();
            //原来金额加回去;
            super.setMoney(delta+money);
        }
    }
    
  • package demo.jc;
    
    import javax.xml.crypto.Data;
    import java.util.ArrayList;
    
    public class DemoMain {
        public static void main(String[] args) {
            Manger boss=new Manger();
            Member employee1=new Member();
            Member employee2=new Member();
            Member employee3=new Member();
            boss.setName("章北海");
            boss.setMoney(100.0);
            boss.show();
            employee1.setName("东方延续");
            employee1.show();
            employee2.setName("丁仪");
            employee2.show();
            employee3.setName("褚岩");
            employee3.show();
    
            System.out.println("==================");
            ArrayList<Double> list =boss.send(20,3);
            employee1.recive(list);
            employee2.recive(list);
            employee3.recive(list);
            employee1.show();
            employee2.show();
            employee3.show();
        }
    }
    
    

3、super关键字

  • 用法
    • 在子类的成员方法中,访问父类的成员变量。
    • 在子类的成员方法中,访问父类的成员方法。
    • 在子类的构造方法中,访问父类的构造方法。
  • package cn.day03;
    
    public class Zi extends Fu{
        public Zi(){
            super(20);//调用父类重载的有参构造方法,必须写在构造方法的第一行;
            System.out.println("子类构造方法");
        }
        @Override//本注解检测是不是有效的覆盖重写
        public void method(){
            super.method();//调用父类的成员方法
            System.out.println("==============="+super.num);//调用父类的成员变量;
            System.out.println("子类的方法");
        }
        @Override
        public void sayhello(){
            System.out.println("我的权限等级大于(default)");
        }
        @Override
        public String showclass(){
            //String属于子类返回值小于等于父类烦人范围
            return "HELLO WORLD";
        }
    }
    
    

4、this关键字

  • 用法

    • 在本类成员方法中,调用本类成员变量。
    • 在本类成员方法中,调用本类另一个成员方法。
    • 在本类的构造方法中,调用另一个构造方法。
      • 注意:this(....)调用也必须是构造方法的第一个语句。唯一一个;
      • 使用this的时候,构造方法不在默认赠送super()构造方法;
      • super()与this不能够同时使用;
  • package cn.day03;
    
    public class DemoZi extends Fu{
        public DemoZi(){
            //使用this后不在调用super()
            this(20);
        }
        public DemoZi(int num){
            System.out.println("我被调用了");
        }
        String str="Hello World";
        public void saystr(){
            bb();//普通也可以调用
            //也可以使用this调用
            this.bb();
            System.out.println(this.str);
        }
        public void bb(){
            System.out.println("bbbbbbbb");
        }
    }
    
    

    image-20211103100823946

5、抽象类

  • 如果父类的方法中不确定如何进行{}方法体的实现,那么这应该就是一个抽象方法.

  • 举例图示

    image-20211103150257946

  • 注意事项
    • 抽象类不能创建对象,创建会报错;
      • 即只要使用了关键字abstrace修饰的类都不能创建对象,即使该类不包含抽象方法;
      • 抽象类不一定包含抽象方法;
      • 包含抽象方法的类一定是抽象类;
    • 抽象类中可以有构造方法,是供子类初始化父类成员时使用的;与普通类差别不大;
    • 抽象类不一定包含抽象方法,包含抽象方法的类一定是抽象类;
    • 抽象类的子类,必须重写所有的抽象方法,否则编译报错;除非子类也是抽象类;
  • package cn.day03;
    /*
    抽象方法:就是加上abstract关键字,然后去掉大括号直接分号结束。
    抽象类:抽象方法所在的类,必须是抽象类才行。在class之前写上abstract即可;
        即含有抽象方法类一定是抽象类;
    使用抽象类和抽象方法:
    1、不能直接创建new抽象类对象
    2、必须使用一个子类来继承抽象父类
    3、子类必须覆盖重写抽象类当中的所有抽象方法;
        覆盖重写(实现):子类去掉抽象方法中的abstract关键字,然后补上大括号
    4、创建子类对象使用;
    * */
    public abstract class DemoCx {
        //这是一个抽象方法,代表吃东西,具体吃什么不知道(大括号中有什么内容,不确定);
        public abstract void eat();
        public abstract void sleep();
        //普通成员方法
        public DemoCx(){
            System.out.println("抽象类的构造方法执行");
        }
        public void say(){
            System.out.println("Hello World");
        }
    }
    
    
  • package cn.day03;
    //抽象类的子类,必须重写所有的抽象方法,否则编译报错;除非子类也是抽象类
    public abstract class Dog extends DemoCx{
        @Override
        public void eat() {
            //重写父类的抽象方法
            System.out.println("哈士奇吃雪!!!");
        }
    }
    
    package cn.day03;
    
    public class ErHa extends Dog{
    
        @Override
        public void sleep() {
            //直接父类已经实现了一个抽象方法;因此只要再实现另一个抽象方法就可以
            System.out.println("哈士奇已经睡着了");
        }
    }
    
    
  • package cn.day03;
    
    public class DeMu extends DemoCx{
        public DeMu(){
            System.out.println("德牧的构造方法执行");
        }
        //直接重写所有的抽象方法
        @Override
        public void eat() {
    
        }
    
        @Override
        public void sleep() {
    
        }
    }
    
  • package cn.day03;
    
    public class DemoMain {
        public static void main(String[] args) {
    //        DemoCx aa= new DemoCx() ;//错误写法抽象类不能直接new对象
    //        Dog dog=new Dog();//子类没有完全重写父类的构造方法因此也是抽象类
    //        dog.eat();
            ErHa erha=new ErHa();
            erha.eat();
            erha.sleep();
            System.out.println("======================");
            DeMu demu=new DeMu();
            demu.eat();
            demu.sleep();
        }
    }
    
    /*Console
    抽象类的构造方法执行
    哈士奇吃雪!!!
    哈士奇已经睡着了
    ======================
    抽象类的构造方法执行
    德牧的构造方法执行
    */
    

6、接口

6.1 接口举例及定义

  • 接口是一种公共的规范标准;只要符合标准就可以通用;

  • 图示

    image-20211105084104703

  • 定义
    • 接口是一种引用数据类型;最重要的内容就是其中的抽象方法;

    • 接口是多个类的公共规范;

    • 定义接口的格式

      public interface 接口名称{
          
      }
      //接口名称的命名规范与类名称一致;
      
  • 接口中包含的内容

    • 如果是java7(jdk1.7)

      1.常量

      2、抽象方法

    • 如果是Java8(jdk1.8)

      1. 默认方法
      2. 静态方法
    • 如果是Java9

      • 5、私有方法

6.2 接口的使用

使用步骤

1、接口不能直接使用,必须使用实现类来实现该接口;

  • 格式

    public class 实现类名称 implements 接口名称{}
    
    //实现类名称命名通常采用`接口名字`+`impl`来命名
    

2、创建实现类对象进行使用

  • 实现类名称命名通常采用接口名字+impl来命名

3、注意事项

  • 如果实现类并没有覆盖重写接口中所有的抽象方法,那么这个实现类就必须是一个抽象类;

  • 接口中不包含普通方法,因为不写关键字会有默认的public+abstract直接成为抽象方法;

    • 接口当中定义抽象方法,修饰符必须是两个关键字:public abstract
    • 这两个关键字可以选择性的省略不写

4、示例

  • package day04;
    
    /*
    * 在任何版本的Java中,接口都能定义抽象方法;
    *
    注意:
    * 接口当中定义抽象方法,修饰符必须是两个关键字:public abstract
    * 这两个关键字可以选择性的省略不写;
    * */
    
    public interface MyInterfaceAbs {
    
        //定义的是抽象方法
        public abstract void method();
    
        //省略关键字abstract
        public void method1();
        //省略关键字public
        abstract void method2();
        //省略关键字public和abstract
        void method3();
        /*以上三种省略关键字都属于抽象方法;熟练之后可以使用省略关键字的写法*/
    }
    
    //实现类
    package day04;
    //关键字implements
    public class MyInterfaceImpl implements MyInterfaceAbs{
    
        @Override
        public void method() {
            System.out.println("第1个方法");
        }
    
        @Override
        public void method1() {
            System.out.println("第一个方法");
        }
    
        @Override
        public void method2() {
            System.out.println("第二个方法");
        }
    
        @Override
        public void method3() {
            System.out.println("第三个方法");
        }
    }
    
    
    package day04;
    
    public class DemoInterface {
    
        public static void main(String[] args) {
            //实例化实现类的对象;
            MyInterfaceImpl impl=new MyInterfaceImpl();
            impl.method();
            impl.method1();
            impl.method2();
            impl.method3();
        }
    }
    

6.3 接口中的默认方法

  • Java8开始,接口支持默认方法;

  • 用途

    • 用来解决接口升级;因为接口定义完成之后会有其他方法加入,如果需要去所有的实现类中重写则比较繁琐;因此使用接口的默认方法进行升级,则实现类不重写,也不会报错;
    • lamdba表达式和函数式编程,接口的默认方法可以拼接函数模型;
  • 格式

    public default 返回值 方法名(){}
    
  • 注意事项

    • 接口的默认方法,可以通过接口的实现类对象,直接调用
    • 接口的默认方法,也可以被接口的实现类重写覆盖;
  • 编码示例

    package day04;
    public interface MyInterfaceAbs {
        //定义的是抽象方法
        public abstract void method();
        //省略关键字abstract
        public void method1();
        //省略关键字public
        abstract void method2();
        //省略关键字public和abstract
        void method3();
        /*以上三种省略关键字都属于抽象方法;熟练之后可以使用省略关键字的写法*/
        
        //添加一个默认方法
        public default void say(){
            System.out.println("Hello World");
        }
        public default void sayHello(){
            System.out.println("我是接口的默认方法,现在还没有被重写");
        }
    }
    
    
    package day04;
    public class MyInterfaceImpl implements MyInterfaceAbs{
        @Override
        public void method() {
            System.out.println("第1个方法");
        }
        @Override
        public void method1() {
            System.out.println("第一个方法");
        }
        @Override
        public void method2() {
            System.out.println("第二个方法");
        }
        @Override
        public void method3() {
            System.out.println("第三个方法");
        }
        @Override
        public void sayHello(){
            //重写接口的默认方法,也可以不重写
            System.out.println("我重写了接口的默认方法");
        }
    }
    
    package day04;
    public class DemoInterface {
        public static void main(String[] args) {
            MyInterfaceImpl impl=new MyInterfaceImpl();
            impl.method();
            impl.method1();
            impl.method2();
            impl.method3();
            System.out.println("========");
            //直接调用,默认方法直接被实现类实现;
            impl.say();
            //调用覆盖后的默认方法
            impl.sayHello();
        }
    }
    

6.4 接口中的静态方法

  • 格式:将默方法中的default变换成static即可;

  • 接口静态方法的使用
    • 通过接口名称直接调用静态方法;
    • 接口名称.静态方法名称()
  • 注意事项

    • 不能通过接口实现类的对象来调用接口当中的静态方法;
    • 一个实现类可能会实现多个接口,因此实现类对象调用易发生冲突;
  • 示例

    • 在上述接口中添加静态方法,并直接调用;
    package day04;
    
    public interface MyInterfaceAbs {
    
        public static void sayStatic(){
            System.out.println("我是接口的静态方法");
        }
    }
    
    
    package day04;
    
    public class DemoInterface {
    
        public static void main(String[] args) {
            MyInterfaceImpl impl=new MyInterfaceImpl();
            impl.method();
            impl.method1();
            impl.method2();
            impl.method3();
            System.out.println("========");
            //直接调用
            impl.say();
            //调用覆盖后的默认方法
            impl.sayHello();
            System.out.println("====================");
            MyInterfaceAbs.sayStatic();
        }
    
    }
    /*
    第1个方法
    第一个方法
    第二个方法
    第三个方法
    ========
    Hello World
    我重写了接口的默认方法
    ====================
    我是接口的静态方法
    */
    

6.5 接口中的私有方法

  • java9开始才支持私有方法

    • 静态私有方法
    • 普通私有方法
  • 本人电脑装的是java8顾不做展示;使用方法和类中的私有方法使用相同;

  • image-20211105102649048

6.7 接口中的常量

  • 接口中也可以定义成员变量,但必须使用public static final三个关键字进行修饰;

  • 从效果上看这就是接口的常量;

  • 格式

    • public static final 数据类型 常量名称=数据值;
    • 备注:一旦使final关键字进行修饰,说明不可改变;
  • 注意事项

    • 接口中的常量,可以省略public static final;不写这三个关键字,会默认添加;
    • 接口中的常量必须直接赋值,不能不赋值;
    • 接口中常量的名称,使用完全大写的字母,用下划线分割,(推荐命名规则)例如MY_CLASS
  • 示例

    package day04;
    
    public interface MyInterfaceAbs {
        //定义接口中的成员变量,即常量
        public static final int MY_CLASS=6;
        //省略关键字不写,效果相同
        String SCHOOL_NAME="哔哩哔哩大学";
    }
    
    
    package day04;
    
    public class DemoInterface {
    
        public static void main(String[] args) {
            MyInterfaceImpl impl=new MyInterfaceImpl();
            impl.method();
            impl.method1();
            impl.method2();
            impl.method3();
            System.out.println("========");
            //直接调用
            impl.say();
            //调用覆盖后的默认方法
            impl.sayHello();
            System.out.println("====================");
            MyInterfaceAbs.sayStatic();
    
            System.out.println("====================");
            //输出常量
            System.out.println(MyInterfaceAbs.SCHOOL_NAME);
            System.out.println(MyInterfaceAbs.MY_CLASS);
        }
    
    }
    /*Consloe
    第1个方法
    第一个方法
    第二个方法
    第三个方法
    ========
    Hello World
    我重写了接口的默认方法
    ====================
    我是接口的静态方法
    ====================
    哔哩哔哩大学
    6
    */
    

6.8 接口知识点截图

image-20211105143251957

6.9 接口中的注意事项

  • 1、接口没有静态代码块和构造方法;

  • 2、一个类的直接父类是唯一的,但一个类可以实现多个接口;

    • 格式:

      public class Myinterface implements MyinterfaceA,MyinterfaceB{
          //覆盖重写所有的抽象方法
      }
      
  • 3、如果实现类的多个接口当中,存在重复抽象方法,那么只需要覆盖重写一次即可;

  • 4、如果实现类没有覆盖重写所有接口的抽象方法,那么实现类就必须是一个抽象类

  • 5、如果实现类所实现的多个接口中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写;

  • 6、一个类如果直接父类当中的方法,和接口中的默认方法发生了冲突;优先父类中的方法;

  • 示例代码

    接口A,B的代码

    package day04;
    
    public interface MyInterfaceA {
    
        public abstract void methodA();
    
        public abstract void func();
        public default void hand(){
            System.out.println("欢迎来到,傻狗之够");
        }
        public default void func2(){
            System.out.println("接口A的默认方法");
        }
    }
    
    
    package day04;
    
    public interface MyInterfaceB {
    
        public abstract void mthodB();
    
        public abstract void func();
    
        public default void func2(){
            System.out.println("接口B的默认方法");
        }
        public default void sayhello(){
            System.out.println("HelloWorld,接口B");
        }
    }
    
    

    实现类的代码

    package day04;
    
    public class InterfaceImpl implements MyInterfaceA,MyInterfaceB{
    
        @Override
        public void methodA() {
    
        }
    
        @Override
        public void mthodB() {
    
        }
    
        //func方法是两个接口都有的抽象方法,只需要覆盖一次即可
        @Override
        public void func() {
    
        }
        //两个接口中都存在func2的默认方法,因此需要在实现类中进行覆盖重写一次
        @Override
        public void func2() {
            System.out.println("我该执行谁的");
            //不写谁都不调用,但是只要进行了覆盖重写,即使没有内容依然正确;
            MyInterfaceB.super.func2();
        }
    }
    
    
    package day04;
    
    public class Fu extends FuO{
        public void sayhello(){
            System.out.println("Hello World,父类方法");
        }
    }
    package day04;
    
    public class Zi extends Fu implements MyInterfaceB{
        //实现类既可以继承同时还可以实现接口;
        @Override
        public void mthodB() {
    
        }
    
        @Override
        public void func() {
    
        }
    }
    
    

    主方法

    package day04;
    
    public class Demo2Interface {
    
        public static void main(String[] args) {
            InterfaceImpl impl=new InterfaceImpl();
            impl.func2();
            System.out.println("=======================");
            Zi zi =new Zi();
            //直接父类的方法与默认方法冲突后,优先使用父类的方法,非直接父类效果一样
            zi.sayhello();//Hello World,父类方法,
        }
    }
    /*Console
    我该执行谁的
    接口B的默认方法
    =======================
    Hello World,父类方法
    */
    

6.10 接口中的多继承

  • 类与类之间是单继承的关系,直接父类只有一个;

  • 类与接口之间是多实现的,一个类可以实现多个接口

  • 接口与接口之间是多继承的

    • 注意事项

      1、多个父接口当中的抽象方法如果重复,没关系。因为抽象方法没有方法体;

      2、多个父接口当中的默认方法如果重复,那么子接口必须进行默认方法的覆盖重写,而且带着default关键字。

  • 代码示例

    父接口

    package day04;
    
    public interface MyInterfaceC {
        public abstract void func();
    
        public abstract void funcC();
        public default void sayhello(){
            System.out.println("Hello World接口C");
        }
        public default void edg(){
            System.out.println("edg夺冠了!");
        }
    }
    
    package day04;
    
    public interface MyInterfaceD {
    
        public abstract void func();
        public abstract void funcD();
        public default void sayhello(){
            System.out.println("Hello World接口D");
        }
    }
    
    

    子接口

    package day04;
    
    public interface MyInterface extends MyInterfaceC,MyInterfaceD{
        //同时继承了C,D接口,而且C,D同时包含func();方法,但因为func()是抽象方法,所以没关系;
        public abstract void mthod();
    
        //接口继承中抽象方法不用重写;
    
        //C,D同时包含默认方法sayhello(),所以必须要重写sayhello方法,而且必须加上关键字default;
        @Override
        default void sayhello() {
            MyInterfaceC.super.sayhello();
        }
    }
    

    实现类

    package day04;
    
    public class FuO implements MyInterface{
    
        @Override
        public void mthod() {
    
        }
    
        @Override
        public void func() {
    
        }
    
        @Override
        public void funcD() {
    
        }
    
        @Override
        public void funcC() {
    
        }
    }
    
    

    主方法

    package day04;
    
    public class Demo2Interface {
    
        public static void main(String[] args) {
            InterfaceImpl impl=new InterfaceImpl();
            impl.func2();
            System.out.println("=======================");
            Zi zi =new Zi();
            //直接父类的方法与默认方法冲突后,优先使用父类的方法,非直接父类效果一样
            zi.sayhello();//Hello World,父类方法,
            System.out.println("=======================");
            FuO aa =new FuO();
            aa.edg();
        }
    }
    /*
    我该执行谁的
    接口B的默认方法
    =======================
    Hello World,父类方法
    =======================
    edg夺冠了!
    */
    

7、多态

  • extends继承implements实现是多态性的前提

  • 对象具有多态性

  • 代码当中体现多态性就是一句话,父类引用,指向子类对象

  • 格式

    • 父类 对象名= new 子类();
    • 接口 对象名 =new 实现类();

7.1 多态中的成员变量与方法

  • 成员变量

    • 多态中成员变量的调用与普通类调用一样,创建对象时等号左边是谁,优先用谁。
    • 编译看左边,运行还看左边;
  • 成员方法:

    • 看new的是谁,就优先用谁,没有则向上找;
    • 编译看左边,运行看右边;

7.2 多态的优势

  • 无论右边new对象的时候换成那个子类对象,等号左边调用方法都不会发生变化;

7.3 对象的转型

  • 向上转型:向上转型一定是安全的;

  • 弊端:对象一旦向上转型,就无法使用子类特有的方法;

  • image-20211105171908677

  • 向下转型

  • image-20211105173114601

  • instanceof判断
    • 原来不是则会报转型错误的异常,因此一定要做转型判断 instanceof
      
    • //格式
      if (obj instanceof Zi) {
         Zi aa = (Zi) obj;
      }
      
  • 代码示例

    package day05;
    
    public class Fu {
        public void func(){
            System.out.println("父类方法");
        }
        public void Dad(){
            System.out.println("伟大的父爱");
        }
    }
    
    
    package day05;
    
    public class Zi extends Fu {
        @Override
        public void func(){
            System.out.println("子类方法");
        }
        public void vip(){
            System.out.println("我是子类特有的方法");
        }
    }
    
    package day05;
    
    public class Dog extends Fu{
    }
    
    

    主方法

    package day05;
    
    public class DemoMutil {
        //多态:创建对象的时候左侧是父类,右侧是子类
        public static void main(String[] args) {
            Fu obj = new Zi();
            //同名优先使用子类的方法
            obj.func();
            //子类没有的向上寻找父类的方法
            obj.Dad();
            // obj.vip();//报错,无法使用子类特有的方法,因为使用多态后对象默认向上转型,因此无法使用,
            //解决方法:将对象向下转型,注意:向下转型必须原来是 ,才能够进行向下转型;
    //        语法格式
    //        子类名称 对象名 =(子类名称)父类对象
            //进行向下转型的判断,必须原来是,才能转换为原来的
            if (obj instanceof Zi) {
                Zi aa = (Zi) obj;
                aa.vip();
            }
            //原来不是则会报转型错误的异常,因此一定要做转型判断 instanceof
            if (obj instanceof Dog) {
                Dog bb = (Dog) obj;
            } else {
                System.out.println("我没有通过验证,Obj原来不是Dog");
            }
        }
    }
    /*
    子类方法
    伟大的父爱
    我是子类特有的方法
    我没有通过验证,Obj原来不是Dog
    */
    

8、final关键字

  • 代表不可变的,最终的;
  • 四种用法

8.1 修饰类

  • 当使用final关键字修饰类的时候,该类不能有任何子类,父类依然正常

    package day05;
    // 当使用final关键字修饰类的时候,该类不能有任何子类,父类依然正常;
    // 由于本类没有子类,因此本类中的方法无法被覆盖重写,但是该类依旧可以覆盖重写父类的方法
    public final class MyClass {
        public void dreadmd(){
            System.out.println("该类不能被继承");
        }
    }
    
    

8.2 修饰方法

  • final关键字用来修饰一个方法的时候,这个方法就是最终方法,也就是不能被覆盖重写;

  • 注意

    • 对于类、方法来说,abstract关键字和final关键字不能同时使用,因为矛盾;
      • abstract :必须要子类实现,被覆盖重写;
      • final,不能有子类,不能被覆盖重写
  • 格式

    package day05;
    
    public class FuFinal {
    
        public final void readself(){
            System.out.println("此方法被final修饰了,不能被覆盖重写");
        }
    }
    
    
    //错误代码展示
    package day05;
    
    public class ZiFinal extends FuFinal{
    
        //报错,无法覆盖重写父类中被final修饰的方法
    //    @Override
    //    public final void readself(){
    //        System.out.println("此方法被final修饰了,不能被覆盖重写");
    //    }
        public abstract  final void error(){
            System.out.println("final关键字和abstract不能同时使用");
        }
    }
    
    

8.3 修饰局部变量

  • 使用final修饰后,这个变量就不能修改

  • 不可变

    • 对于基本类型来说,不可变说的是变量中的数据不可变;
    • 对于引用类型来说,不可变说的是变量中的地址值不可变;
  • 示例代码

    package day05;
    
    public class DemoFinal {
        public static void main(String[] args) {
            final int num=666;
            //使用final修饰后,这个变量就不能修改
            //一次赋值,终生不改
            System.out.println(666);
            //num=222;//错误写法不支持
            //num=666;错误写法
            //使用final只允许赋值一次,即使相同也不可以二次赋值
    
            final int age;
            age=18;//正确写法,唯一一次赋值,
            /*****************/
            System.out.println("============================");
            //对于基本类型来说,不可变说的是变量中的数据不可变;
            //对于引用类型来说,不可变说的是变量中的地址值不可变;
    
            final Student stu =new Student("傻狗");
            System.out.println(stu.getName());
            stu.setName("哈士奇");//内容发生改变,但是地址值没有发生改变;
            System.out.println(stu.getName());//哈士奇
        }
    }
    
    

8.4 final 修饰成员变量

  • 对于成员变量来说,如果使用final关键字进行修饰,那么这个变量照样不可变;

  • 由于成员变量具有默认值,所以用final之后必须手动赋值,不会再给默认赋值;

  • 对于final的成员变量,要么使用直接赋值,要么通过构造方法赋值;二者选其一;

  • 必须保证类当中所有重载的构造方法,都最终会对final的成员变量进行赋值;

  • 示例代码

    package day05;
    
    public class Person {
    //    private final String name;//不会在默认赋值
        //private final String name="傻狗";手动赋值
        private final String name;
    
    
        public Person() {
            name="二哈";
        }
    
        public Person(String name) {
            this.name = name;
        }
        //以上两个构造方法都实现了对name的赋值;
    
        public String getName() {
            return name;
        }
        //使用final后不能在被修改
    //    public void setName(String name) {
    //        this.name = name;
    //    }
    }
    
    

真累啊!

记录不易,转载请注明出处;

posted @ 2021-11-05 22:32  紫青宝剑  阅读(49)  评论(0编辑  收藏  举报