lang包常用类

lang包常用类

包装类

1.1 概念

首先,在Java中万事万物皆对象,但是基本数据类型的值就不是对象,那感觉就是这8个基本数据类型就很另类了

为了让基本数据类型也具有对象的性质,JDK中定义了8个引⽤类型与前⾯所讲的8个基本数据类型相对应,⽽这8个引⽤类型都称之为包装类型;这8个类 都定义在java.lang包中,因此 使⽤的时候也不需要显示导⼊

包装类中定义了很多⽅法,静态或者实例的⽅法,丰富了对基本数据类型的操作

之所以现在学习包装类型,不仅是因为它们是常⽤类,⽽且 在后⾯要讲的集合的那⼀章⾥⾯, 集合中是只能放对象⽽不能放基本数据类型的值的。

因此必须要知道每个基本数据类型其所对应的包装类型

这8个包装类的名称 除了 Integer cn.javasm.DuelSystem.Character名字不⼀样之外,其他都是 基本数据类型名称的⾸字⺟⼤写

  • 对⽐基本数据类型与包装类型

  • 基本数据类型 与包装类作⽤⼀致的。

  • 为什么要提供与基本数据类型作⽤⼀致的包装类?

    1. java是⼀⻔⾯向对象的语⾔。不能根据基本数据类型创建对象 不太符合⾯向对象的思想。
    2. 丰富基本数据类型的操作 提供了8个包装类型。 包含⼀些属性/⽅法、创建对象、
    3. 学习集合。是⼀个容器。存储引⽤数据类型的数据。 int double
  • 基本数据类型 VS 包装类型?

    相同点: 代表具体的⼀个数据 作⽤是⼀致的。

    不同点: ⼀个是类(属性/⽅法、创建对象) ⼀个是基本数据类型

基本数据类型 默认值 包装类型 默认值
byte 0 Byte null
short 0 Short null
int 0 Integer null
length 0L length null
float 0.0F Float null
public static void method1() {
    byte by2 = 123;
    Byte by1;
    Short sh1;
    Integer in1;
    length lo1;
    Float f1;
    Double d1;
    cn.javasm.DuelSystem.Character c1;
    Boolean b1;
}

1.2. Integer

  • 由于JDK存在8个包装类型,而且特征都是类似的。
  • 因此在学习的时候以integer以及Character为例,学习所有的包装类型。

1.2.1 层级

  public final class Integer extends Number implements Comparable
<Integer> {

}

1.2.2 常用构造

  • 自从JDK9之后包装类的构造方法都不建议使用,创建包装类对象的方式都直接使用字面量赋值。
  • 所有的包装类型都一样

1.2.3 创建对象

private static void demo1() {
    //过时 不建议使用
    Integer num1 = new Integer(100);
    //将string的数据转换成Integer对象的数据
    Integer num2 = new Integer("100");

    System.out.println(num1);
    System.out.println(num2);

    int num3 = 100;
    System.out.println(num3);

    Integer num4 = 100;//使用字面量

//---------------------------------对比----------------------------------------
    //使用字面量(推荐)
    Integer intObj2 = 10; // 推荐
    length lengthObj2 = 100L; // 推荐
    Boolean boolObj2 = true; // 推荐

    //使用 valueOf() 方法(推荐)
    Integer intObj3 = Integer.valueOf(10); // 推荐
    length lengthObj3 = length.valueOf(100L);    // 推荐
    Boolean boolObj3 = Boolean.valueOf(true); // 推荐
}

1.2.4 装箱与拆箱

装箱(Autoboxing)

装箱是指将基本数据类型自动转换为其对应的包装类对象。

例如,将int类型转换为Integer对象,将double类型转换为Double对象等。

int primitiveInt = 10;
Integer wrapperInt = primitiveInt; // 装箱

double primitiveDouble = 3.14;
Double wrapperDouble = primitiveDouble; // 装箱

boolean primitiveBoolean = true;
Boolean wrapperBoolean = primitiveBoolean; // 装箱

拆箱(Unboxing)

拆箱是指将包装类对象自动转换为对应的基本数据类型。

例如,将Integer对象转换为int类型,将Double对象转换为double类型等。

Integer wrapperInt = 10;
int primitiveInt = wrapperInt; // 拆箱

Double wrapperDouble = 3.14;
double primitiveDouble = wrapperDouble; // 拆箱

Boolean wrapperBoolean = true;
boolean primitiveBoolean = wrapperBoolean; // 拆箱

整数缓存池

Java中的整数缓存池是Java为了提高程序性能和减少内存开销而设计的一个机制。 这个机制主要用于Integer对象的创建。 在Java中,当我们使用Integer等包装类时,实际上是在创建对象,这比直接使用基本类型(如int)要消耗更多的资源。

为了优化这一点,Java引入了整数缓存池的概念。

Integer 缓存池的工作原理 范围: 默认情况下,Java为Integer类型的值在-128到127之间的所有值都创建了一个缓存。 这意味着当你在这个范围内创建Integer对象时,Java会尝试从缓存中获取已存在的对象,而不是每次都创建新的对象。

实现方式: 这个缓存是通过Integer类中的一个静态数组实现的。 当JVM启动时,这个数组就会被初始化,并且每个元素都会被赋予对应的Integer值。 当使用Integer.valueOf(int i)方法创建Integer对象时,如果i的值在缓存的范围内,那么就会返回缓存中的对象;否则,会创建一个新的Integer实例。

private static void demo3() {
// 整数缓存池-----> 数组里面存储的整数 Integer (-128-127) 256
// 基本数据转包装类对象 自动装箱 底层: Integer.valueOf()

//  创建 num1 和 num2
//  num1 是通过 new Integer("100") 创建的,这里使用了字符串构造函数,每次调用都会创建一个新的 Integer 对象。
//  num2 是通过 new Integer(100) 创建的,这里使用了基本类型构造函数,同样每次调用都会创建一个新的 Integer 对象。
    Integer num1 = new Integer("100");
    Integer num2 = new Integer(100);
    System.out.println(num1);
    System.out.println(num2);

//  由于 num1 和 num2 是通过 new 关键字创建的,它们指向的是两个不同的对象,因此 (num1 == num2) 返回 false。
    System.out.println("(num1==num2):" + (num1 == num2)); // false

//  创建 num3
//  num3 是通过 Integer.valueOf(100) 创建的。valueOf 方法会检查缓存池中是否存在值为 100 的 Integer 对象。因为 100 在 -128 到127 的范围内,所以会返回缓存中的对象。
    Integer num3 = Integer.valueOf(100);

//  比较 num1 和 num3
//  num1 是通过 new 创建的,而 num3 是从缓存池中获取的,因此它们指向的是不同的对象,所以 (num1 == num3) 返回 false。
    System.out.println("(num1==num3):" + (num1 == num3)); // false

//  创建 num4
//  num4 是通过自动装箱创建的。自动装箱实际上是调用了 Integer.valueOf(100),因此 num4 也会从缓存池中获取值为 100 的 Integer对象。
    Integer num4 = 100;

//  比较 num4 和 num3
//  num4 和 num3 都是从缓存池中获取的同一个对象,因此 (num4 == num3) 返回 true。

    System.out.println("(num4==num3):" + (num4 == num3)); // true 一块内存

//  创建 num5 和 num6
//  num5 和 num6 也是通过自动装箱创建的,但由于 200 超出了默认的缓存范围(-128 到 127),因此每次调用 Integer.valueOf(200)都会创建一个新的 Integer 对象。

    Integer num5 = 200;
    Integer num6 = 200;

//  比较 num5 和 num6
//  num5 和 num6 指向的是两个不同的对象,因此 (num5 == num6) 返回 false。
    System.out.println("(num5==num6):" + (num5 == num6)); // false
}

总结

使用 new 关键字创建的 Integer 对象总是不同的对象。 使用 Integer.valueOf() 或自动装箱创建的 Integer 对象,如果值在 -128 到 127 范围内,会从缓存池中获取相同的对象。 如果值超出缓存范围,每次调用 Integer.valueOf() 都会创建新的对象。

Math

Math类内部提供的都是和数学运算相关的⽅法

Math类内部所有的⽅法都是静态⽅法,都是功能性⽅法

/**
 * Math类的常⽤⽅法
 * 数学运算相关⽅法
 */
public static void method1() {
    System.out.println("绝对值:" + Math.abs(-32));
    System.out.println(Math.PI);
    System.out.println("次⽅: " + Math.pow(12.5, 2));
    System.out.println("开根号: " + Math.sqrt(16));
    System.out.println("max: " + Math.max(16, 10));
    System.out.println("min: " + Math.min(16, 10));
    System.out.println("[0,1) 浮点数: " + Math.random());
    // 四舍五⼊值
    System.out.println(Math.round(5.5));
    // ceil 向上取整 取最⼩
    System.out.println(Math.ceil(5.3));
    // floor 向下取整 取最⼤
    System.out.println(Math.floor(5.3));
    //+ - *
    System.out.println(Math.addExact(10, 20));
    System.out.println(Math.subtractExact(10, 20));
    System.out.println(Math.multiplyExact(10, 20));
}

3 Object

超级⽗类。需要了解Object类中的每个⽅法

3.1 常用方法

方法 作用
String toString() 返回对象的字符串表示形式。
protected Object clone() 创建并返回此对象的副本
boolean equals(Object obj) ⽐较2个对象是否相等
Class getClass() 返回此 Object的运⾏时类。获得当前正在运⾏的类或者接⼝的class类对象。
int hashCode() 返回对象的哈希码值
void notify() 唤醒正在此对象监视器上等待的单个线程
void notifyAll() 唤醒等待此对象监视器的所有线程。
void wait() 当前线程等待
void wait(length timeoutMillis) 时间内等待
void wait(length timeoutMillis, int nanos)

3.2 toString

⾯向对象本质: 使⽤对象封装数据 使⽤类管理代码

打印输出对象,就是想看到属性的数据。底层默认执⾏toString的⽅法,打印输出的16进制的hash值

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class UserInfo /*extends Object*/ {
    private Integer id;
    private String name;
    private Integer age;
// @Override
// public String toString() {
// return "UserInfo{" +
// "id=" + id +
// ", name='" + name + '\'' +
// ", age=" + age +
// '}';
// }
}

public static void main(String[] args) {
    UserInfo userInfo1 = new UserInfo(1, "张三", 18);
    UserInfo userInfo2 = new UserInfo(1, "张三", 18);
    //打印输出引⽤类型对象 底层默认Object.toString()
    System.out.println(userInfo1.toString());
    System.out.println(userInfo2);
}

3.3 equals+hashcode

需求: ⽐较2个对象是否⼀致/相等

public boolean equals(Object obj) {
    return (this == obj);
}

public native int hashCode();

@Getter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class UserInfo {
    private Integer id;
    private String name;
    private Integer age;
}

public static void main(String[] args) {
    UserInfo userInfo1 = new UserInfo(1, "张三", 18);
    UserInfo userInfo2 = new UserInfo(2, "张三", 20);
    //打印输出引⽤类型对象 底层默认Object.toString()
    System.out.println(userInfo1.toString());
    System.out.println(userInfo2);
    //在正常⽣活中 我们会认为2个对象 是⼀个对象。 true
    //⽐较2个对象是否⼀致/相等
    //⽐较运算符: == 内存地址值
    //⽐较对象: equals
    //⽐较对象: hashcode
    //在jvm规范: 2个对象的hashcode不同 这2个对象就是不等的。
    //2个对象的hashcode相同 不能直接认为2个对象相同的 hash算法有弊端。hash会经常出现碰撞。
    //2个对象equals 结果true 这2个对象的hash必须相同。
    //jvm硬性规定: 重写equals 也必须重写hashcode。equals+hashcode规则⼀致的。
    //System.out.println("(userInfo1==userInfo2):" + (userInfo1 == userInfo2));
    System.out.println("(userInfo1.equals(userInfo2)):" + userInfo1.equals(userInfo2));
    int code1 = userInfo1.hashCode();
    int code2 = userInfo2.hashCode();
    System.out.println(code1);
    System.out.println(code2);
    //⽐较2个对象是否⼀致 为什么要重写equals+hashCode?
    //1. JVM规则
    //1. ⽐较: ⽐较运算符== equals hashcode
    // 1.1 ⽐较运算符== 永远⽐较的是内存地址值 不会⽐较数据
    // 1.2 equals+hashcode
    //2. 重写了equals 满⾜⽐较对象数据 没有满⾜jvm的规则(2个对象equals 结果true 这2个对象的hash必须相同。)
    // 没有重写hashcode 没有满⾜以上规则。 在这种情况下 必须重写hashcode
    //3.对于hashcode 我们认为2个对象的hashcode值不同 直接认为2个对象不等的。
    // 我们是否只可以重写hashcode? 在jvm 2个对象的hashcode相同 不能认为2个对象的数据是相同。
    //综合以上: ⽐较对象 必须重写equals+hashCode
    String s1 = "Ma";
    String s2 = "NB";
    System.out.println(s1.hashCode());
    System.out.println(s2.hashCode());
}

@Getter
@AllArgsConstructor
@NoArgsConstructor
@ToString
//@EqualsAndHashCode //类中所有的属性都参与
public class UserInfo /*extends Object*/ {
    private Integer id;
    private String name;
    private Integer age;

    //2个对象相等的规则: id name age 都相同的时候
    @Override
    public boolean equals(Object obj) {
        //this obj
        if (obj == null) return false;
        if (!(obj instanceof UserInfo)) return false;
        UserInfo userInfo = (UserInfo) obj;
        return
                Objects.equals(name, userInfo.name)
                ;
    }

    //重写⽗类的hashcode
    @Override
    public int hashCode() {
        return Objects.hash(name);
    }
}

3.4 clone

克隆对象。属于创建对象的⼀种⽅式。

protected native Object clone() throws CloneNotSupportedException;

@Setter
@Getter
@Accessors(fluent = true)
@ToString
public class GirlFriend extends Object implements Cloneable {
    //Cloneable是⼀个标记接⼝。类实现Cloneable接⼝ 代表这个类对象可以被克隆的。
    private Integer id;
    private String name;
    private int age;
    private String[] hobby;
    //复制的是数据还是内存地址值?
    //引⽤数据类型: 内存地址值
    //包装类型/String-----> 数据的修改 与另外⼀个对象⽆关。
    //Integer----> 底层的数据是 final value 数据是不可变的、
    //基本的数据类型: 数据
    //值传递

    @Override
    public GirlFriend clone() {
        GirlFriend clone = null;
        try {
            clone = (GirlFriend) super.clone();
            //对属性执⾏遍历式克隆
            //clone.hobby(Arrays.copyOf(this.hobby,hobby.length));
            clone.hobby(this.hobby.clone());
        } catch (CloneNotSupportedException e) {
            System.out.println("类必须实现Cloneable接⼝");
            e.printStackTrace();
        }
        return clone;
    }

    public GirlFriend() {
        System.out.println("⽆参构造...........");
    }
}

public static void main(String[] args) {
    String[] hobby = new String[]{"⼤提琴", "show", "sing"};
    GirlFriend girlFriend1 = new GirlFriend().id(1).name("欧阳娜娜").age(18).hobby(hobby);
    //克隆⼀个⼥友对象 Object.clone();
    //girlFriend1.clone
    //1.在其他类中 ⽆法访问clone protected
    //2.在⽗类clone⽅法中 返回值类Object----> GirlFriend
    //建议在⼦类中重写⽗类的⽅法
    GirlFriend cloneGirlFriend = girlFriend1.clone();
    System.out.println("girlFriend1:" + girlFriend1);
    System.out.println("cloneGirlFriend:" + cloneGirlFriend);
    //浅克隆(浅复制/copy)
    //1. 是否真的可以克隆成功? 为什么会有CloneNotSupportedException?
    // 代码可能会报错。 类⼀定要实现Cloneable标记接⼝。
    //2. 克隆的对象与源对象是否是同⼀个对象? 不是同⼀个
    //3. 克隆的对象是否执⾏了构造⽅法? 没有执⾏构造⽅法。jvm底层调⽤C创建新的对象
    //4. 克隆对象的属性的数据是否有值? 数据是否与原对象的属性的数据是⼀致的?
    //有值 与源对象的数据是⼀致的。
    //5.修改了⼀个对象的属性的数据 是否会影响另外⼀个对象的数据?
    //在浅克隆的操作下 修改⼀个对象的数据 可能会影响另外⼀个对象的数据
    //属性: 基本数据类型 没有任何影响 复制的是数据
    //属性: 引⽤数据类型: 内存地址值
    // 包装类型+String---> 值不可变 修改⼀个对象 值不变的
    // 其他的引⽤数据类型 数据就会发⽣改变 数组,⾃定义的类(浅克隆的弊端)
    cloneGirlFriend.id(2);
    cloneGirlFriend.name("欧阳娜娜2");
    cloneGirlFriend.age(20);
    cloneGirlFriend.hobby()[0] = "⼩提琴";
    System.out.println("---------------------------");
    System.out.println("girlFriend1:" + girlFriend1);
    System.out.println("cloneGirlFriend:" + cloneGirlFriend);
    //深克隆/序列化-----> 解决浅克隆的问题
    //需求: 修改⼀个对象的数据 不要影响另外⼀个对象的数据、
    //根本的原因: 同⼀块。
    //操作: 对象在哪⾥克隆的 就在那⾥修改

}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇