5.面向对象高级

static

static修饰成员变量

1、static是什么?

  • 叫静态,可以修饰成员变量,成员方法

2、成员变量按有无static修饰,分为两种

  • 变量:有static修饰,属于类,在计算机中只有一份会被类的全部对象共享
  • 实例变量(对象的变量):无static修饰,属于每个对象的

类变量应用场景

应用场景

  • 在开发中,如果某个数据只需要一份,且希望能够被共享(访问、修改),则该数据可以定义成类变量来使用

案例导学:

系统启动后,要求用户类可以记住自己创建了多少个用户对象了

static修饰成员方法

成员方法分类

  • 类方法:有static修饰的成员方法,属于类
  • 实例方法:无static修饰的成员方法,属于对象,只能用对象调用

应用场景

  • 类方法最常见的应用场景是做工具类

工具类是什么?

  • 工具类的方法都是类方法,每个类方法都是一个功能,是给开发人员使用的

使用类方法有什么好处

  • 提高了代码的复用性

为什么工具类中的方法用类方法,而不用实例方法?

  • 不需要生成对象,可以节省内存
  • 实例方法需要创建对象来调用,没有必要

工具类

  • 工具类没有创建对象的需求,建议将工具类的构造器私有

static注意事项

1、类方法中可以直接访问类的成员,不可以直接访问实例成员。

2、实例方法可以直接访问类成员,可以直接访问实例成员。

3、实例方法中可以出现this关键字,类方法中不可以出现this关键字。

static应用-代码块

代码块概述

  • 代码块是类的5大成分之一(成员变量、构造器、方法、代码块、内部类)

代码块分两种

1、静态代码块

  • 格式:static {}
  • 特点:类加载时自动执行,由于类只会加载一次,所以静态代码块也只会执行一次
  • 作用:完成类的初始化,例如:对类变量的初始化赋值

2、实例代码块

  • 格式:{}
  • 特点:每次创建对象时,执行实例代码块,并在构造器之前执行
  • 作用:和构造器一样,都是来完成对象的初始化的,例如:对实例变量进行初始化赋值。

static应用-单例设计模式

什么是设计模式?

  • 一个问题通常有n种解法,最优解就叫设计模式。

单例设计模式

  • 确保一个类只有一个对象
public class A {
    private static A a = new A();

    private A(){
    }

    public static A getObect() {
        return a;
    }
}

写法

  • 类的构造器私有
  • 定义一个变量记住类的一个对象
  • 定义一个方法,返回对象

单例模式的应用场景和好处?

  • Runtime
  • 任务管理器

单例模式的实现方式很多

  • 饿汉式单例:获取类的对象时,对象已经创建好了
  • 懒汉式单例:获取类的对象时,对象才开始创建

懒汉式单例设计模式

拿对象时,才开始创建对象

写法

  • 类的构造器私有
  • 定义一个变量存储类的一个对象
  • 定义一个方法,返回对象
public class B {
    private static B b;
    private B(){
    }
    public static B getInstance(){
        if (b == null) {
            b = new B();
        }
        return b;
    }
}

继承

继承的快速入门

什么是继承

Java中提供了一个关键字extends,用这个关键字,可以让一个类和另一个类建立父子关系

继承的特点

子类能继承父类的非私有成员(成员变量,成员方法)

继承后对象的创建

  • 子类的对象是由子类、父类共同完成的
  • 对象能直接访问什么成员,是由子类父类多张设计图共同决定的,多张设计图对外暴露了什么成员,对象就可以访问什么成员

继承的好处

  • 减少重复代码的编写

继承注意事项

权限修饰符

限制类中的成员能够被访问的范围

注意:

protected只能在子类中访问,在外面哪怕是子类创建的对象不行

单继承

Java是单继承的,一个类只能继承一个直接父类;Java支持继承,但是支持多层继承。

Object类

Object类是Java所有类的祖宗类。

方法重写

什么是方法重写
  • 子类觉得父类中的某个方法不好用,或无法满足自己的需求时,子类可以重写一个方法名称,参数列表一样的方法,去覆盖父类的方法
  • 注意:重写后,方法的访问,Java会遵循就近原则
注意事项
  • 小技巧:使用Override注解,会检查重写格式是否正确,可读性也会更好。
  • 子类重写父类方法时,访问权限必须大于等于父类该方法的权限。
  • 重写的方法返回值类型,必须与被重写方法的一样,或者范围更小。
  • 私有静态方法不能被重写,会报错。
常见应用场景
  • 子类重写Object类中的toString()方法,以便返回对象的内容
System.out.println(b.toString());
System.out.println(b);

打印对象时,默认会调用toString。

子类访问成员变量的特点

1、就近原则

  • 先在子类局部找
  • 然后子类成员范围找
  • 然后父类成员范围找,如果父类范围还没找到则报错

2、如果子父类中,出现了重名的成员,会优先使用子类的,如果此时一定要使用父类的怎么办?

可以通过super关键字

public void showName(){
        String name = "jubu";
        System.out.println(name);// 局部
        System.out.println(this.name);// 自己
        System.out.println(super.name);// 父类
    }

子类构造器的特点

  • 子类的全部构造器,全都会调用父类的构造器,再执行自己
子类构造器是如何实现调用父类构造器的
  • 默认情况下,子类全部构造器第一行代码都是super(),它会调用父类的无参构造器
  • 如果父类没有无参数构造器,则必须在子类构造器第一行手写super(...),指定去调用父类的有参数构造器
为什么这么干?应用场景

子类构造器可以通过调用父类构造器,把对象中包含父类这部分的数据先初始化,再回来吧对象中包含子类这部分的数据蛇进行初始化赋值

this(...)调用兄弟构造器

任意类的构造器中,可以通过this(...)去调用该类的其他构造器的

多态

认识多态

什么是多态

  • 多态是在继承/实现情况下的一种现象,表现为:对象多态、行为多态

多态具体代码实现

        People p1 = new Teacher();
        p1.run();
        People p2 = new Student();
        p2.run();

编译看左边,运行看右边

多态的前提

  • 有继承/实现关系
  • 存在父类引用子类对象
  • 存在方法重写

注意事项

  • 多态是对象、成员的多态,Java的属性(成员变量)不谈多态

多态的好处

  • 在多态形式下,右边对象是解耦合的,更便于扩展和维护
  • 定义方法时,使用父类类型的形参,可以接受一切子类对象,扩展性更强、更便利

多态的缺点

  • 无法直接调用子类的独有功能

强制类型转换

注意事项

  • 存在继承/实现关系就可以在编译阶段进行强制类型转换,编译阶段不会报错
  • 运行时,如果发现对象的真实类型与强转后的不同,会报类型转换异常的错误

强转之前,建议用instanceof判断

 public static void go(People p){
        p.run();
        if (p instanceof Student){
            Student s1 = (Student) p;
            s1.test();
        }
    }

final

  • final最终的意思,可以修饰类、方法、变量
  • 修饰类:最终类,能被继承了。
  • 修饰方法:不能被重写了。
  • 修饰变量:有且能赋值一次

final修饰变量的注意

  • final修饰基本类型,变量存储的数据不能变
  • final修饰引用类型,变量存储的地址不能变,但是地址指向对象的内容是可以变的

常量

  • 常量:public static final,变量名全大写,用写划线分隔
  • 作用:通常用于记录系统的配置信息
public static final SCHOOL_NAME = "黑马";

常量的优势

  • 可读性,维护性
  • 编译会,常量会被“宏替换”:出现常量的地方全部替换成记住的字面量,这样可以保证使用常量和直接用字面量性能是一样的。

抽象类

认识抽象类

抽象类、抽象方法是什么样的

  • 都是用abstract修饰的;抽象方法只有方法签名,不能写方法体

抽象类的注意事项、特点

  • 抽象类中不一定有抽象方法,抽象方法一定是抽象类
  • 类该有的成员(成员变量、方法、构造器)抽象类都可以有
  • 抽象类最主要的特点:抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现
  • 一个类继承抽象类,必须重写完抽象类的全部方法,否则这个类也必须定义成抽象类

抽象类的好处

  • 父类知道每个子类都要做某个行为,但是每个子类要做的情况不一样,父类就定义成抽象方法,交给子类去重写实现,我们设计这样的抽象类,就是为了更好地支持多态

抽象类常见应用场景-模板方法设计模式

模板方法设计模式解决了什么问题

  • 解决方法中存在重复代码的问题

模板方法设计模式写法

  • 定义一个抽象类
  • 在里面定义2个方法
    • 模板方法:相同代码放进去
    • 抽象方法:具体实现交给兹拉完成
      public abstract class People {
          public void write(){
              System.out.println("title");
              System.out.println(writeMain());
              System.out.println("end");
          }
      
          public abstract String writeMain();
      }
多学一招:用final修饰模板方法
  • 防止子类重写模板方法

接口

认识接口

  • Java提供关键字interface
  • 注意:接口不能创建对象;接口是用来被实现的,实现接口的类称为实现类
  • 一个类可以实现多个接口,实现类实现多个接口,则必须重写全部接口的全部抽象方法,否则实现类需要定义为抽象类。

接口好处

  1. 解决类单继承的问题,可以让类有一个亲爹的同时,还可以找个干爹
  2. 通过接口去找干爹,通过implements的接口,就可以显性地知道你是谁,从而就可以放心地把你当成谁来使用了
  3. 一个类可以实现多个接口,一个接口也可以被多个类实现。程序可以面向接口编程,灵活地切换各种业务实现

接口新增的方法jdk8开始

public interface A {
    default void test1(){
        System.out.println("==默认方法==");
        test2();
    }

    private void test2(){
        System.out.println("==私有方法==");
    }

    static void test3(){
        System.out.println("==静态方法==");
    }
}

1、jdk8开始,接口中新增了哪些方法?

  • 默认方法:default修饰,使用实现类的对象调用
  • 静态方法:static修饰,必须用当前接口名调用
  • 私有方法:private,jdk9开始才有,只能在接口内部调用
  • 都默认被public修饰

2、接口中为什么要新增这些方法

  • 增强接口的能力,便于项目的扩展和维护

接口的多继承

一个接口可以同时继承多个接口

注意事项

  1. 一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持
  2. 一个实现多个接口,如果多个接口中存在方法签名冲突,则此时不支持
  3. 一个类继承了父类,又同时实现了接口,父类和接口中有同名的默认方法,实现类会优先父类
  4. 一个类实现了多个接口,多个接口存在同名的默认方法,可以不冲突,这个类重写该方法即可

内部类

内部类概述

  • 是类中的五大成分之一(成员变量、方法、构造器、内部类、代码块),如果一个类定义在另一个类的内部,这个类就是内部类
  • 场景:一个类的内部,包含了一个完整事物,且这个事物没有必要单独设计时,就可以把这个事物设计成内部类

四种形式

  • 成员内部类
  • 静态内部类
  • 局部内部类
  • 匿名内部类【重点】

成员内部类

public class Outer {
    private int age = 99;
    public static String a;
    public class Inner{
        private String name;
        public String schoolName;
        private int age = 88;

        public void test(){
            System.out.println(age);
            System.out.println(a);

            int age = 66;
            System.out.println(age);
            System.out.println(this.age);
            System.out.println(Outer.this.age);
        }
        
    }
}

1、成员内部类是什么?如何创建其对象?

  • 就是类中的一个普通成员,类似普通成员变量、成员方法
  • 外部类名.内部类名 对象名 =  new 外部类(...).new 内部类(...);

2、成员内部类的实力方法中,访问其他成员有啥特点?

  • 可以直接访问外部类的实例成员、静态成员
  • 可以拿到当前外部类对象,格式是:外部类名.this

静态内部类

public class Outer {
    public static class Inner{
        private String name;
        public static int a;

        public void test(){

        }
    }
}

1、什么是静态内部类?如何创建对象?有啥特点?

  • static修饰的内部类,属于外部类自己持有
  • Outer.Inner in = new Outer.Inner();
  • 可以直接访问外部类的静态成员,不能直接访问外部类的实例成员

匿名内部类

  • 特殊的局部内部类;匿名指的是不需要为这个类声明名字
public class Test {
    public static void main(String[] args) {
        Aniaml a = new Aniaml(){
            @Override
            public void cry() {
                System.out.println("miaomiaomiao");
            }
        };
        a.cry();
    }
}

abstract class Aniaml{
    public abstract void cry();
}
  • 特点:匿名内部类本质就是一个子类,并会立即创建出一个子类对象
  • 作用:更方便地创建一个子类对象
常见使用场景
public class Test2 {
    public static void main(String[] args) {
        Swimming s1 = new Swimming(){
            @Override
            public void swim() {
                System.out.println("dog swim fast");
            }
        };

        go(s1);
    }

    public static void go(Swimming s){
        System.out.println("==start===");
        s.swim();
    }
}

interface Swimming{
    void swim();
}
  • 匿名内部类通常作为一个参数传输给方法

枚举类

枚举是一种特殊类

public enum A {
    X,Y,Z;
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Compiled from "A.java"
public final class com.itheima.d6_enum.A extends java.lang.Enum<com.itheima.d6_enum.A> {
  public static final com.itheima.d6_enum.A X;
  public static final com.itheima.d6_enum.A Y;
  public static final com.itheima.d6_enum.A Z;
  public static com.itheima.d6_enum.A[] values();
  public static com.itheima.d6_enum.A valueOf(java.lang.String);
  public java.lang.String getName();
  public void setName(java.lang.String);
  static {};
}
  • 枚举类第一行只能罗列一些名称,这些名称都是常量,并且每个常量记住的都是枚举类的一个对象
  • 枚举类的构造器都是私有的,因此,枚举类不能对外创建对象
  • 枚举类都是最终类,不可以被继承
  • 枚举类中,从第二行开始,可以定义类的其他各种成员
  • 编译器为枚举类新增了几个方法,枚举类都是继承java.lang.Enum的。

抽象枚举

package com.itheima.d6_enum;

public enum B {
    X(){
        @Override
        public void go() {

        }
    },
    Y("zhangsan"){
        @Override
        public void go() {
            System.out.println(getName() + " is running~~");
        }
    };
    public abstract void go();

    private String name;

    B() {
    }

    B(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

枚举常见应用场景

  • 用来表示一组信息,然后作为参数传输
  • 参数值不受约束  选择定义枚举表示一组信息,并作为参数传输
  • 代码可读性好,参数值得到了约束,对使用者更友好

泛型

泛型的认识

  • 定义类、接口、方法时,同时声明了一个或者多个变量(如:<E>),称为泛型类,泛型接口,泛型方法,他们统称为泛型
public class Test {
    public static void main(String[] args) {
        

        ArrayList<String> list1 = new ArrayList<>();
        list1.add("java1");
        list1.add("java2");
        list1.add("java3");
        for (int i = 0; i < list1.size(); i++) {
            String e = list1.get(i);
            System.out.println(e);
        }
    }
}
  • 作用:泛型提供了在编译阶段约束所能操作的数据类型,并进行自动检查的能力。这样可以避免强制类型转换,及可能出现的异常
  • 泛型的本质:把具体的数据类型作为参数传给类型变量

泛型类

public class MyArrayList <E>{
    private Object[] arr = new Object[10];

    private  int size;
    public boolean add(E e){
        arr[size++] = e;
        return true;
    }

    public E get(int index){

        return (E) arr[index];
    }
}

用extend限制类型

public class MyClass3 <E extends Animal>{
}

class Animal{
    
}

泛型接口

是用来给实现类实现的

// 泛型接口
public interface Data <T>{
    void add(T t);
    ArrayList<T> getByName(String name);
}

// 实现类1
public class StudentData implements Data<Student>{
    @Override
    public void add(Student student) {

    }

    @Override
    public ArrayList<Student> getByName(String name) {
        return null;
    }
}

// 实现类2
public class TeacherData implements Data<Teacher>{
    @Override
    public void add(Teacher teacher) {

    }

    @Override
    public ArrayList<Teacher> getByName(String name) {
        return null;
    }
}

泛型方法

public class Test {
    public static void main(String[] args) {
        String rs = test("java");
        System.out.println(rs);

        Dog d = test(new Dog());
        System.out.println(d);

        ArrayList<Car> cars = new ArrayList<>();
        cars.add(new BMW());
        cars.add(new BENZ());
        go1(cars);

        ArrayList<BMW> bmws = new ArrayList<>();
        bmws.add(new BMW());
        go1(bmws);

        ArrayList<BENZ> benzs= new ArrayList<>();
        benzs.add(new BENZ());
        go1(benzs);
    }

    public static <T extends Car> void go1(ArrayList<T> cars){

    }

    // ?通配符,使用泛型的时候代表一切类型 ? extends Car(上限) ? super Car(下限)
    public static void go2(ArrayList<? extends Car> cars){

    }


    public static <T> T test(T t){
        return  t;
    }

}

泛型注意事项

  • 泛型是工作在编译阶段的,一旦程序编译成class文件,class文件中就不存在泛型了,这就是泛型擦除
  • 泛型不支持基本数据类型,只支持对象类型。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值