Bootstrap

黑马20天学会Java——面向对象进阶(超详细笔记)

1 static静态关键字

  • 实例成员变量:无static修饰,属于对象(对象名.实例成员变量)
private String name;
  • 实例方法:属于对象的,只能用对象触发访问(对象名.实例方法)
    public void study(){
        System.out.println(name + "在好好学习,天天向上~");
    }
  • 静态成员变量:有static修饰,归属于类,可以被共享,用类名访问(类名.静态成员变量)
public static int onlineNumber = 161;
  • 静态成员方法:有static修饰,归属于类,可以被共享,用类名访问(类名.静态成员方法)
    public static int getMax(int age1, int age2){
        return age1 > age2 ? age1 : age2;
    }

注意事项:
1、静态方法中不可以出现this关键字,this只能代表当前对象
2、实例方法可以访问静态成员,也可以访问实例成员(实例方法内部访问)
3、静态方法只能访问静态成员,不能"直接"访问实例成员(静态方法内部访问)
4、在本类中书写方法和变量,可以不加类名和对象名

2 static应用知识:工具类

  • 类中都是一些静态方法,每个方法都是以完成一个共用的功能为目的
  • 这个类用来给系统开发人员共同使用的
  • 优点:调用方便、提高了代码复用
  • 工具类无需创建对象,建议将工具类的构造器进行私有
package com.itheima.d2_static_util;
import java.util.Random;
public class ItheimUtil {

    /**
       注意:由于工具类无需创建对象,所以把其构造器私有化会显得很专业!
     */
    private ItheimUtil(){
    }
    public static String createVerifyCode(int n){
        // 开发一个验证码:
        // 1、定义一个变量记住验证码。
        String code = "";
        // 2、定义一个变量记住全部验证码字符。
        String data = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        // 3、定义一个循环生成几个随机索引,去得到几个字符
        Random r = new Random();
        for (int i = 0; i < n; i++) {
            // 4、获取随机索引对应的字符。链接给code
            int index = r.nextInt(data.length());
            code += data.charAt(index);
        }
        return code;
    }
}
package com.itheima.d2_static_util;
import java.util.Random;
public class Check {
    public static void main(String[] args) {
        // 开发一个验证码:
        System.out.println(ItheimUtil.createVerifyCode(6));
    }
}

3 static应用知识:代码块

  • 代码块是类的5大成分之一(成员变量、构造器,方法,代码块,内部类)
  • 定义在类中方法外
  • 在Java类下,使用 { } 括起来的代码被称为代码块
  • 静态代码块:

格式:static{}
特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发、只执行一次
使用场景:在类加载的时候做一些静态数据初始化的操作,以便后续使用

4 static应用知识:单例设计模式

4.1 饿汉单例

  • 饿汉单例是在获取对象前,对象已经提前准备好了一个
  • 这个对象只能是一个,所以定义静态成员变量
  • 必须把构造器私有化
package com.itheima.d4_static_singleinstance;
public class SingleInstance {

    public static SingleInstance instance = new SingleInstance();
    private SingleInstance(){
    }
}
package com.itheima.d4_static_singleinstance;
public class Test1 {
    public static void main(String[] args) {
        // 目标:理解饿汉单例的设计步骤。
        SingleInstance s1 = SingleInstance.instance;
        SingleInstance s2 = SingleInstance.instance;
        System.out.println(s1 == s2);// true
    }
}

4.2 懒汉单例

  • 定义一个静态的成员变量负责存储一个对象
  • 只加载一次,只有一份最好私有化
package com.itheima.d4_static_singleinstance;

/**
   懒汉单例
 */
public class SingleInstance2 {

    /**
      2、定义一个静态的成员变量负责存储一个对象。
         只加载一次,只有一份。
       注意:最好私有化,这样可以避免给别人挖坑!
     */
    private static SingleInstance2 instance;

    /**
      3、提供一个方法,对外返回单例对象。
     */
    public static SingleInstance2 getInstance() {
        if(instance == null){
            // 第一次来拿对象 :此时需要创建对象。
            instance = new SingleInstance2();
        }
        return instance;
    }


    /**
       1、私有化构造器
     */
    private SingleInstance2(){
    }
}

5 标题面向对象三大特征之二:继承

5.1 继承概述

  • 关键字:extends
  • 作用:当子类继承父类后,就可以直接使用父类公共的属性和方法
  • 优势:可以提高代码的复用性
  • 继承设计规范:

子类们相同特征(共性属性,共性方法)放在父类中定义
子类独有的的属性和行为应该定义在子类自己里面

  • 继承的特点

子类可以继承父类的属性和行为,但是子类不能继承父类的构造器
Java是单继承模式:一个类只能继承一个直接父类
Java不支持多继承、但是支持多层继承
Java中所有的类都是Object类的子类

  • 子类可以继承父类的私有成员,只是不能直接访问(get,set方法访问)
  • 子类可以继承父类的私有方法(但是无法访问)
  • 子类可以继承父类的静态成员(子类名.静态成员变量)

5.2 继承后特点

5.2.1 成员变量、成员方法的访问特点

package com.itheima.d8_extends_field_method;

public class Test {
    public static void main(String[] args) {
        // 目标:理解继承后成员的访问特点:就近原则。
        Dog d = new Dog();
        d.run(); // 子类的
        d.lookDoor(); // 子类的
        d.showName();
    }
}

class Animal{
    public String name = "动物名";
    public void run(){
        System.out.println("动物可以跑~~");
    }
}

class Dog extends Animal{
    public String name = "狗名";

    public void lookDoor(){
        System.out.println("狗可以看门~~");
    }

    public void showName(){
        String name = "局部名";
        System.out.println(name);
        System.out.println(this.name); // 当前子类对象的name
        System.out.println(super.name); // 找父类的name

        super.run(); // 找父类的方法
        run(); // 子类的run
    }

    public void run(){
        System.out.println("狗跑的贼快~~~");
    }
}

5.2.2 方法重写

  • 重写方法都加@Override注解,代码安全,优雅
  • 重写方法的名称、形参列表必须与被重写方法的名称和参数列表一致
  • 私有方法不能被重写
  • 静态方法不能重写
  • 子类重写父类方法时,访问权限必须大于或者等于父类
  • (暂时了解 :private < 缺省 < protected < public)

5.2.3 构造器

  • 子类中所有的构造器默认都会先访问父类中无参的构造器,再执行自己
  • 子类构造器访问父类有参构造器:通过调用父类有参数构造器来初始化继承自父类的数据
  • super调用父类构造器
package com.itheima.d11_extends_constructor;
import lombok.Data;

@Data
public class People {

    private String name;
    private int age;

    public People(){
    }

    public People(String name, int age) {
        this.name = name;
        this.age = age;
    }

}

package com.itheima.d11_extends_constructor;

public class Teacher extends People{

    public Teacher(){
    }
    public Teacher(String name, int age){
        // 调用父类的有参数构造器:初始化继承自父类的数据
        super(name, age);
    }
}

  • 其他形式的有参构造器
package com.itheima.d12_this;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private String name;
    private String schoolName;

    /**
        如果学生不填写学校,默认这个对象的学校是黑马
     */
    public Student(String name) {
        // 借用本类兄弟构造器
        this(name, "黑马程序员");
    }
}

6 包

  • 建包的语法格式:package 公司域名倒写.技术名称
  • 报名建议全部英文小写,且具备意义
  • 相同包下的类可以直接访问,不同包下的类必须导包(自动导包)

7 权限修饰符

  • 权限修饰符:是用来控制一个成员能够被访问的范围
  • 可以修饰成员变量,方法,构造器,内部类
  • 权限修饰符:有四种作用范围由小到大(private -> 缺省 -> protected - > public )
    在这里插入图片描述
  • 一般要求

成员变量一般私有
方法一般公开

8 final

8.1 final的作用

  • 修饰类:表明该类是最终类,不能被继承
  • 修饰方法:表明该方法是最终方法,不能被重写
  • 修饰变量:表示该变量第一次赋值后,不能再次被赋值(有且仅能被赋值一次)

8.2 final修饰变量的注意

  • final修饰的变量是基本类型:那么变量存储的数据值不能发生改变
  • final修饰的变量是引用类型:那么变量存储的地址值不能发生改变
  • 但是地址指向的对象内容是可以发生变化的
        // 注意:final修饰引用类型的变量,其地址值不能改变,但是指向的对象的内容可以改变的。
        final Teacher t2 = new Teacher("学习,授课,吹吹水~~");
        // t2 = null;  // 第二次赋值了。
        System.out.println(t2.getHobby());
        t2.setHobby("运动");
        System.out.println(t2.getHobby());

9 常量

  • 常量是使用了public static final修饰的成员变量,必须有初始化值
  • 在执行的过程中其值不能被改变
  • 常量名的命名规范:英文单词全部大写,多个单词下划线连接起来
  • 常量做信息标志和分类

10 枚举

  • 枚举的作用:“是为了做信息的标志和信息的分类”
  • 枚举类的第一行默认都是罗列枚举对象的名称的
  • 枚举都是最终类,不可以被继承

10.1 常量用法

package com.itheima.d5_enum;
public enum Season {
    // 第一行罗列枚举的实例:对象的名称。
    SPRING,SUMMER,AUTUMN, WINTER;
}
package com.itheima.d5_enum;
public class Test {
    public static void main(String[] args) {
        // 目标:认识枚举。
        Season s1 = Season.SPRING;
        // SPRING
        System.out.println(s1);
    }
}

10.2 向枚举中添加新方法

package com.itheima.d5_enum;
import lombok.Getter;
// 枚举一般只有Getter
@Getter
public enum Color {
    RED("红色", 1),
    GREEN("绿色", 2),
    BLANK("白色", 3),
    YELLO("黄色", 4);
    // 成员变量
    private String name;
    private int index;
    // 构造方法
    private Color(String name, int index) {
        this.name = name;
        this.index = index;
    }
    // 普通方法
    public static String getName(int index) {
        for (Color c : Color.values()) {
            if (c.getIndex() == index) {
                return c.name;
            }
        }
        return null;
    }
}

11 抽象类

  • 在Java中abstract是抽象的意思,可以修饰类、成员方法
    在这里插入图片描述
    在这里插入图片描述
  • 抽象的使用场景

当父类知道子类一定要完成某些行为,但是每个子类该行为的实现又不同
该父类就把该行为定义成抽象方法的形式,具体实现交给子类去完成

  • 一个类如果继承了抽象类,那么这个类必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类
  • 特征和注意事项:

1、类有的成员(成员变量、方法、构造器)抽象类都具备
2、一个类继承了抽象类必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类
3、不能用abstract修饰变量、代码块、构造器
4、最重要的特征:得到了抽象方法,失去了创建对象的能力(有得有失)

在这里插入图片描述

12 面向对象三大特征之三:多态

  • 多态的常见形式:在这里插入图片描述
  • 多态中成员访问特点

方法调用:编译看左边,运行看右边
变量调用:编译看左边,运行也看左边。(注意)

13 接口

13.1 接口的定义与特点

  • JDK8之前接口中只能是抽象方法和常量
  • 接口中的成员都是public修饰的
  • 接口的格式
    在这里插入图片描述
     // 1、常量:
     String SHCOOL_NAME = "黑马程序员";
     //public static final String SHCOOL_NAME = "黑马程序员";
    // 2、抽象方法
    void run();
    // public abstract void run();

13.2 接口的基本使用:被实现

  • 一个类可以实现一个接口,也可以实现多个接口
  • 一个类实现接口,必须重写完全部接口的全部抽象方法,否则这个类需要定义成抽象类

类和类的关系:单继承
类和接口的关系:多实现
接口和接口的关系:多继承,一个接口可以同时继承多个接口

13.3 JDK8开始接口新增的方法

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

注意:JDK8新增的3种方法我们自己在开发中很少使用,通常是Java源码涉及到的,我们需要理解、识别语法、明白调用关系即可

14 内部类

14.1 内部类基本介绍

  • 内部类就是定义在一个类里面的类
  • 里面的类可以理解成(寄生),外部类可以理解成(宿主)
  • 使用场景:当一个事物的内部,还有一个部分需要一个完整的结构进行描述时
  • 基本作用:

内部类通常可以方便访问外部类的成员,包括私有的成员
内部类提供了更好的封装性,内部类本身就可以用private ,protectecd等修饰,封装性可以做更多控制

14.2 匿名内部类(重点)

  • 本质上是一个没有名字的局部内部类
  • 作用:方便创建子类对象,最终目的是为了简化代码编写

14.2.1 匿名内部类常见使用形式

package com.itheima.d8_innerclass_anonymous;

/**
      目标:学习匿名内部类的形式和特点。
 */
public class Test {
    public static void main(String[] args) {
        Animal a = new Animal(){
            @Override
            public void run() {
                System.out.println("老虎跑的块~~~");
            }
        };
        a.run();
    }
}

abstract class Animal{
    public abstract void run();
}

匿名内部类通常是在开发中调用别人的方法时,别人需要我们写的时候才会定义出来使用

15 常用API

  • API:Java已经写好一些方法,直接拿过来用(应用程序编程接口)

15.1 Object

15.1.1 toString方法

  • 默认是返回当前对象在堆内存中的地址信息:类的全限名@内存地址
  • 父类toString()方法存在的意义就是为了被子类重写,以便返回对象的内容信息
  • 写在实体类中
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", sex=" + sex +
                ", age=" + age +
                '}';
    }

15.1.2 equals方法

  • 默认是比较当前对象与另一个对象的地址是否相同,相同返回true,不同返回false
  • 直接比较两个对象的地址是否相同完全可以用“==”替代equals
  • 为了被子类重写,以便子类自己来定制比较规则(比如比较对象内容
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Student)) return false;
        Student student = (Student) o;
        return getSex() == student.getSex() 
                && getAge() == student.getAge() 
                && Objects.equals(getName(), student.getName());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getName(), getSex(), getAge());
    }

15.2 Objects

  • Objects是一个工具类,提供了一些方法去完成一些功能
  • 使用Objects的equals方法在进行对象的比较会更安全
package com.itheima.d10_api_objects;
import java.util.Objects;
public class Test {
    public static void main(String[] args) {
        String s1 = null;
        String s2 = new String("itheima");

        // System.out.println(s1.equals(s2));   // 留下了隐患,可能出现空指针异常。
        System.out.println(Objects.equals(s1, s2)); // false 更安全,结果也是对的!

        /**
             Objects:
             public static boolean equals(Object a, Object b) {
                     return (a == b) || (a != null && a.equals(b));
             }
         */
        System.out.println(Objects.isNull(s1)); // true
        System.out.println(s1 == null); // true

        System.out.println(Objects.isNull(s2)); // false
        System.out.println(s2 == null); // false

    }
}

16 StringBuilder

  • StringBuilder的核心作用:操作字符串的性能比String要更高(如拼接、修改等)
package com.itheima.d11_api_stringbuilder;
public class StringBuilderDemo1 {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder(); 
        sb.append("a");
        sb.append(1);
        sb.append(false);
        sb.append(3.3);
        sb.append("abc");
        System.out.println(sb);// abc1false3.3abc

        StringBuilder sb1 = new StringBuilder();
        // 支持链式编程
        sb1.append("a").append("b").append("c").append("我爱你中国");
        System.out.println(sb1);// abc我爱你中国

        // 反转
        // reverse把里面的元素逆序
        sb1.reverse().append("110");
        System.out.println(sb1);// 国中你爱我cba110

        System.out.println(sb1.length());// 11 字符长度

        // 注意:StringBuilder只是拼接字符串的手段:效率好。
        // 最终的目的还是要恢复成String类型。
        StringBuilder sb2 = new StringBuilder();
        sb2.append("123").append("456");
        // 恢复成String类型
        String rs = sb2.toString();
        System.out.println("rs = " + rs);// rs = 123456
    }
}

其他API

  • math
package com.itheima.d12_math;
public class MathDemo {
    public static void main(String[] args) {
        // 1.取绝对值:返回正数
        System.out.println(Math.abs(10)); // 10
        System.out.println(Math.abs(-10.3)); // 10.3

        // 2.向上取整: 5
        System.out.println(Math.ceil(4.00000001)); // 5.0
        System.out.println(Math.ceil(4.0)); // 4.0
        // 3.向下取整:4
        System.out.println(Math.floor(4.99999999)); // 4.0
        System.out.println(Math.floor(4.0)); // 4.0

        // 4.求指数次方
        System.out.println(Math.pow(2 , 3)); // 2^3 = 8.0
        // 5.四舍五入 10
        System.out.println(Math.round(4.49999)); // 4
        System.out.println(Math.round(4.500001)); // 5

        System.out.println(Math.random());  // 0.0 - 1.0 (包前不包后)

        // 拓展: 3 - 9 之间的随机数  (0 - 6) + 3
        //  [0 - 6] + 3
        int data =  (int)(Math.random() * 6) + 3;
        System.out.println(data);


    }
}
  • system
package com.itheima.d13_system;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.Arrays;
public class SystemDemo {
    public static void main(String[] args) {
    
        // System.exit(0); // JVM终止!

        // 2、计算机认为时间有起源:返回1970-1-1 00:00:00 
        // 走到此刻的总的毫秒值:时间毫秒值。
        long time = System.currentTimeMillis();
        System.out.println(time);// 1684828821688
        
        // 3、做数组拷贝(了解)
        /**
         arraycopy(Object src,  int  srcPos,
         Object dest, int destPos,
         int length)
         参数一:被拷贝的数组
         参数二:从哪个索引位置开始拷贝
         参数三:复制的目标数组
         参数四:粘贴位置
         参数五:拷贝元素的个数
         */
        int[] arr1 = {10, 20, 30, 40, 50, 60, 70};
        int[] arr2 = new int[6]; // [0, 0, 0, 0, 0, 0] ==>  [0, 0, 40, 50, 60, 0]
        System.arraycopy(arr1, 3, arr2, 2, 3);
        System.out.println(Arrays.toString(arr2));
        
        System.out.println(k1);// 换行输出
        System.out.print(k1);// 不换行输出
        
    }
}
  • BigDecimal大数据类
  • 浮点型运算的时候直接+ * / 可能会出现数据失真(精度问题)
  • BigDecimal可以解决浮点型运算数据失真的问题
package com.itheima.d14_bigdecimal;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.NumberFormat;
public class BigDecimalDemo {
    public static void main(String[] args) {
        // 浮点型运算的时候直接+  * / 可能会出现数据失真(精度问题)。
        System.out.println(0.09 + 0.01);// 0.09999999999999999
        System.out.println(1.0 - 0.32);// 0.6799999999999999
        System.out.println(1.015 * 100);// 101.49999999999999
        System.out.println(1.301 / 100);// 0.013009999999999999

        System.out.println("-------------------------");
        double a = 0.1;
        double b = 0.2;
        double c = a + b;
        System.out.println(c);// 0.30000000000000004
        System.out.println("--------------------------");
        // 包装浮点型数据成为大数据对象 BigDeciaml
        BigDecimal a1 = BigDecimal.valueOf(a);
        BigDecimal b1 = BigDecimal.valueOf(b);
        BigDecimal c1 = a1.add(b1);
        // a1.add(b1) = 0.3
        System.out.println("a1.add(b1) = " + a1.add(b1));
        // a1.subtract(b1) = -0.1
        System.out.println("a1.subtract(b1) = " + a1.subtract(b1));
        // a1.multiply(b1) = 0.02
        System.out.println("a1.multiply(b1) = " + a1.multiply(b1));
        // a1.divide(b1) = 0.5
        System.out.println("a1.divide(b1) = " + a1.divide(b1));

        // 目的:double
        double rs = c1.doubleValue();
        System.out.println(rs);// 0.3

        // 注意事项:BigDecimal是一定要精度运算的
        BigDecimal a11 = BigDecimal.valueOf(10.0);
        BigDecimal b11 = BigDecimal.valueOf(3.0);
        /**
           参数一:除数 参数二:保留小数位数  参数三:舍入模式
         */
        BigDecimal c11 = a11.divide(b11, 2, RoundingMode.HALF_UP); // 3.3333333333
        System.out.println(c11);// 3.33
    }
}


;