4.复习-Java类与对象-part(1)

Java类与对象

1.为什么不允许从静态方法中访问非静态变量?

  • 1.静态变量属于类本身,在类加载的时候就会分配内存,可以通过类名直接访问;
  • 2.非静态变量属于类的对象,只有在类的对象产生时,才会分配内存,通过类的实例去访问;
  • 3.静态方法也属于类本身,但是此时没有类的实例,内存中没有非静态变量,所以无法调用。

2.关于Object类的理解

  • 1.什么是Object类?

    • Object类 是Java中所有类的基类,它是所有类的超类。在Java中,每个类都直接或间接地继承自 Object类。Object类 提供了一些通用的方法和功能,可以在所有对象上使用。
  • 2.Object类有哪些常用的方法?

    • 1.clone() :创建并返回对象的一个副本。

      • 实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。
    • 2.equals():用于判断两个对象是否相等。

      • 默认情况下,该方法比较的是对象的引用是否相等,可以根据需要重写该方法来实现自定义的相等判断逻辑。

      • java语言规范要求equals方法具有下面的特性

        • 1.自反性:对于任何非空引用x,x.equals(x)应该返回true;
        • 2.对称性:对于任何引用x,和y,当且仅当,y.equals(x)返回true,x.equals(y)也应该返回true;
        • 3.传递性:对于任何引用x,y,z,如果x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)也应该返回true;
        • 4.一致性:如果x,y引用的对象没有发生变化,反复调用x.equals(y)应该返回同样的结果;
        • 5.对于任意非空引用x,x.equals(null)返回false;
    • 3.hashCode():返回对象的哈希码值。

      • 哈希码是根据对象的内部状态计算得出的一个整数值,用于支持哈希表等数据结构的快速查找。
    • 4.toString():返回对象的字符串表示。

      • 默认情况下,该方法返回对象的类名和哈希码值的字符串表示,可以根据需要重写该方法来提供更有意义的字符串表示。
    • 5.getClass():返回对象的运行时类。

    • 6.finalize():在对象被垃圾回收之前调用,用于执行一些清理操作。

    • 7.wait():使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。

      • wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。

      • 调用该方法后当前线程进入睡眠状态,直到以下事件发生:

        • 其他线程调用了该对象的notify方法;
        • 其他线程调用了该对象的notifyAll方法;
        • 其他线程调用了interrupt中断该线程;
        • 时间间隔到了。
      • 当一个线程调用 wait() 方法后,它会释放当前持有的对象锁,并进入等待状态。

    • 8.notify() :唤醒在该对象上等待的某个线程

      • 关于是否为随即唤醒,可能与JVM的具体实现和线程调度器有关,因此不保证所有JVM或所有情况下都一致。
    • 9.notifyAll():唤醒在该对象上等待的所有线程。

  • 3.为什么要重写 equals() 和 hashCode() 方法?

    • 在使用 Java 中的集合类(如 HashMap、HashSet)时,通常需要重写 equals() 和 hashCode() 方法。
    • equals() 方法用于判断两个对象是否相等,而 hashCode() 方法是在哈希表等数据结构中使用的。
    • 按照约定,如果两个对象相等,则它们的哈希码必须相等。因此,重写 equals() 方法的同时,也应该重写 hashCode() 方法,以保证对象在集合中的正确性。

3.String

  • String 类的常用方法

    • 常见String类的获取功能

      • length():获取字符串长度;
      • charAt(int index):获取指定索引位置的字符;
      • indexOf(int ch):返回指定字符在此字符串中第一次出现处的索引;
      • substring(int start):从指定位置开始截取字符串,默认到末尾;
      • substring(int start,int end):从指定位置开始到指定位置结束截取字符串;
    • 常见String类的判断功能

      • equals(Object obj): 比较字符串的内容是否相同,区分大小写;
      • contains(String str): 判断字符串中是否包含传递进来的字符串;
      • startsWith(String str): 判断字符串是否以传递进来的字符串开头;
      • endsWith(String str): 判断字符串是否以传递进来的字符串结尾;
      • isEmpty(): 判断字符串的内容是否为空串””;
    • 常见String类的转换功能

      • byte[] getBytes(): 把字符串转换为字节数组;
      • char[] toCharArray(): 把字符串转换为字符数组;
      • String valueOf(char[] chs): 把字符数组转成字符串。valueOf可以将任意类型转为字符串;
      • toLowerCase(): 把字符串转成小写;
      • toUpperCase(): 把字符串转成大写;
      • concat(String str): 把字符串拼接;
    • 常见String类的其他常用功能

      • replace(char old,char new) 将指定字符进行互换

      • replace(String old,String new) 将指定字符串进行互换

      • trim() 去除两端空格

      • int compareTo(String str) 会对照Unicode表 从第一个字母进行减法运算 返回的就是这个减法的结果,如果前面几个字母一样会根据两个字符串的长度进行减法运算返回的就是这个减法的结果,如果连个字符串一摸一样 返回的就是0。

        String str1 = “apple”;
        String str2 = “banana”;
        String str3 = “apple”;

        System.out.println(str1.compareTo(str2)); // 输出负数,因为”a”在字典序上早于”b”
        System.out.println(str1.compareTo(str3)); // 输出0,因为str1和str3完全相等
        System.out.println(str2.compareTo(str1)); // 输出正数,因为”b”在字典序上晚于”a”

  • 1.String类可以被继承吗?

    • String类是一个被声明为final的类。由于final关键字的特性,String类不能被继承。这意味着你不能创建String类的子类。这种设计决策是为了确保String类的行为在Java中始终如一,防止由于继承可能引入的不可预知的行为。
    • 在需要自定义字符串行为的情况下,你可以考虑使用其他方式,例如创建包含String对象的新类,并在其中实现所需的行为。
  • 2.String,Stringbuffer,StringBuilder 的区别?

    • (1)可变性

      • String内部的value值是final修饰的,所以它是不可变类。所以每次修改String的值,都会产生一个新的对象。
      • StringBuffer和StringBuilder是可变类,字符串的变更不会产生新的对象。
    • (2)线程安全性

      • String是不可变类,所以它是线程安全的。
      • StringBuffer是线程安全的,因为它每个操作方法都加了synchronized同步关键字。
      • StringBuilder不是线程安全的,所以在多线程环境下对字符串进行操作,应该使用StringBuffer,否则使用StringBuilder。
    • (3)性能方面

      • String的性能是最低的,因为String是不可变的,这就意味着在做字符串拼接和修改的时候,需要重新创建新的对象以及分配内存。
      • StringBuffer因为是可变的,直接修改即可,但StringBuffer添加了重量级锁synchronized,其性能不如StringBuilder。
    • (4)存储方面

      • String存储在字符串常量池中。
      • StringBuilder和StringBuffer都存储在堆内存中。
  • 3.“+”连接符的效率为何低?

    • 使用“+”连接符时,JVM会隐式的创建StringBuilder对象,这种方式在大部分情况下不会造成效率的损失,但是,在循环中进行字符串拼接时就不一样了。
    • 因为会创建大量的StringBuilder对象在堆内存中,这肯定是不允许的,所以这时就建议在循环外创建一个StringBuilder对象,然后循环内调用append方法进行手动拼接。
    • 还有一种特殊情况,如果“+”拼接的是字符串常量中的字符串时,编译器会进行优化,直接将两个字符串常量拼接好。
    • 所以,“+”连接符对于直接相加的字符串常量效率很高,因为在编译期间便确定了它的值;但对于间接相加的情况效率就会变低,建议单线程时使用StringBuilder,多线程时使用StringBuffer替代。

4.Java 创建对象有几种方式

  • 1.使用new关键字,这是最常见的创建对象的方式。通过调用类的构造方法(构造器)来创建对象。
  • 2.使用反射,通过Java的反射API可以动态地创建对象。反射允许在运行时获取类的信息,并可以调用类的构造器来创建对象。
  • 3.使用克隆,如果一个类实现了Cloneable接口并重写了Object类的clone()方法,那么可以通过调用对象的clone()方法来创建该对象的一个副本。
  • 4.使用序列化与反序列化,如果一个类实现了Serializable接口,那么可以通过序列化(将对象转换为字节流)和反序列化(将字节流转换回对象)来创建对象。这种方式常用于对象的持久化存储和传输。
  • 5.使用依赖注入,在依赖注入框架(如Spring)中,对象的创建和管理通常由框架负责。通过配置或注解,框架会自动创建所需的对象,并将其注入到需要的地方。
  • 6.使用工厂模式,工厂模式是一种创建对象的设计模式,它隐藏了对象创建的具体逻辑,并通过一个统一的接口来创建对象。工厂模式可以分为简单工厂、工厂方法和抽象工厂等。
  • 7.使用构建器模式,构建器模式(Builder Pattern)是一种对象构建的设计模式,它允许你以更加灵活的方式创建复杂对象。构建器模式通常用于构造具有多个可选参数的类。

5.大数类

  • 背景

    • Java中的基础数据类型能存储的最大的二进制数是 2 ^ 63 - 1,只要运算过程中会超过这个数,就会造成数据溢出,就会造成错误。
    • 但在Java中有两个类BigInteger和BigDecimal分别表示大整数类和大浮点数类,至于两个类的对象能表示最大范围不清楚,理论上能够表示无线大的数,只要计算机内存足够大。
  • 介绍

    • 这两个类都在java.math.*包中,因此每次必须在开头处引用该包
    • BigInteger实现了任意精度的整数运算
    • BigDecimal实现了任意精度的浮点数运算
  • 方法

    • 普通的数值转换成大数值

      • 分别调用BigInteger.valueOf(“普通数值”),BigDecimal.valueOf(“普通数值”)即可。
    • 加法

      • add();
    • 减法

      • subtract();
    • 乘法

      • multiply();
    • 除法

      • divide();
    • 进制转化

      • 使用构造函数BigInteger(String, int index),可以把一个index进制的字符串,转化为10进制的BigInteger。
      • a.toString(radix);//把十进制数a转变为radix数进制。
    • 求最值

      • 最大值:max();
      • 最小值:min();
    • 取余

      • mod();

6.类之间的关系

  • 面向对象编程

    • 1.依赖(uses-a)

      • 如果一个类的方法使用或操作另一个类的对象,我们就说一个类依赖于另一个类依赖关系,但不拥有它
    • 2.聚合(has-a)

      • 包含关系意味着类A的对象包含类B的对象
    • 3.继承(is-a)

      • 表示一个更特殊的类与一个更一般的类之间的关系
  • 通用

    • 1.依赖

      • 含义:是类与类之间的连接,表示一个类依赖于另外一个类的定义;依赖关系仅仅描述了类与类之间的一种使用与被使用的关系;
      • 举例:人依赖于水和空气;汽车依赖汽油;
    • 2.关联

      • 含义:类与类之间的连结,关联关系使一个类知道另外一个类的属性和方法;通常含有“知道”,“了解”的含义。关联可以是双向的,也可以是单向的
      • 举例:“渔民”需要知道“天气”情况才能够出海
    • 3.聚合

      • 含义:是关联关系的一种,是一种强关联关系(has-a);聚合关系是整体和个体/部分之间的关系;
      • 举例:班级和学生,当班级删除之后,学生还是存在,学生还可能被培训机构引用
    • 4.组合

      • 含义:它也是关联关系的一种(is-a),组合关系要求聚合关系中代表整体的对象要负责代表个体/部分的对象的整个生命周期;组合关系不能共享;在组合关系中,如果代表整体的对象被销毁或破坏,那么代表个体/部分的对象也一定会被销毁或破坏
      • 举例:一个人由头、四肢、等各种器官组成,因为人与这些器官具有相同的生命周期,人死了,这些器官也挂了;房子和房间的关系,当房子没有了,房间同样不可能单独存在。
    • 聚合和组合的区别:聚合是个体离开了整体,依然可以存在.
      组合是个体和整体不可以分开,个体不能离开整体单独存在.

    • 依赖常体现为方法的参数、局部变量或静态方法的调用。
      关联则通过类的成员变量(属性)来体现,这个属性直接引用了另一个类的实例。