深入探索Java开发世界:Java基础~类型分析大揭秘

在这里插入图片描述

Java基础知识,类型知识点梳理~

一、基本数据类型

Java的基本数据类型是语言的基础,它们直接存储在栈内存中,具有固定的大小和不变的行为。

八种基本数据类型的具体分析

  1. byte(字节型)

    • 大小: 8-bit == 1-byte
    • 取值范围: -128 ~ 127
    • 默认值: 0
    • 使用场景:
      • 节省内存: 在大数组中存储数据时,使用byte可以有效节省内存空间。例如,处理大型文件或图像数据。
      • 网络通信: 在网络传输协议中,通常以字节为单位进行数据传输。
  2. short(短整型)

    • 大小: 16-bit == 2-byte
    • 取值范围: -32,768 ~ 32,767
    • 默认值: 0
    • 使用场景:
      • 内存受限场景: 在需要存储大量小整数且内存受限的情况下,如游戏开发中存储地图坐标。
  3. int(整型)

    • 大小: 32-bit == 4-byte
    • 取值范围: -2^31 ~ 2^31-1
    • 默认值: 0
    • 使用场景:
      • 常规整数运算: 最常用的整数类型,适合绝大多数计算场景,如计数器、循环变量、数组索引等。
      • 位运算: 常用于位运算操作,如位掩码和位图。
  4. long(长整型)

    • 大小: 64-bit == 8-byte
    • 取值范围: -2^63 ~ 2^63-1
    • 默认值: 0L
    • 使用场景:
      • 大整数计算: 适用于需要存储大范围整数的场景,如时间戳(System.currentTimeMillis()返回的值)、大规模数据处理中的ID生成。
      • 金融计算: 存储货币金额(通常以分为单位),避免浮点数带来的精度问题。
  5. float(浮点型)

    • 大小: 32-bit == 4-byte
    • 取值范围: 约 ±3.40282347E+38F (6-7 个有效十进制数字)
    • 默认值: 0.0f
    • 使用场景:
      • 图形处理: 在计算机图形学、游戏开发中用于表示坐标、颜色值等。
      • 简单科学计算: 适用于对精度要求不高的科学计算。
  6. double(双精度浮点型)

    • 大小: 64-bit == 8-byte
    • 取值范围: 约 ±1.79769313486231570E+308 (15 个有效十进制数字)
    • 默认值: 0.0d
    • 使用场景:
      • 高精度科学计算: 适用于需要高精度的计算,如物理模拟、统计分析、机器学习算法等。
      • 金融计算: 如果不涉及严格的货币计算场景,可以用于财务分析、汇率转换等。
  7. char(字符型)

    • 大小: 16-bit == 2-byte
    • 取值范围: 0 ~ 65,535 (表示单个Unicode字符)
    • 默认值: ‘\u0000’
    • 使用场景:
      • 字符处理: 用于表示单个字符,如在字符串处理中对单个字符的操作。
      • 字符编码: 在处理字符编码转换时,暂存单个字符。
  8. boolean(布尔型)

    • 大小: 实际大小依赖于JVM实现(通常使用1-bit,但实际存储可能更大)
    • 取值范围: true 或 false
    • 默认值: false
    • 使用场景:
      • 逻辑判断: 用于条件控制,如if语句、循环控制、标志位等。
      • 状态表示: 表示对象的某种状态,如开关状态、运行状态等。

二、封装类型

封装类型为每种基本数据类型提供了一个对应的类,使得基本数据类型具有了对象的特性,可以调用对象方法和利用面向对象的特性。

Java的封装类型包括以下八种

  1. Byte --> byte
  2. Short --> short
  3. Integer --> int
  4. Long --> long
  5. Float --> float
  6. Double --> double
  7. Character --> char
  8. Boolean --> boolean

使用场景:

  1. 集合类的使用

Java集合框架(如ListSetMap等)只能存储对象,无法直接存储基本数据类型。因此,在需要将基本数据类型放入集合中时,需要使用对应的封装类型。

import java.util.ArrayList;
import java.util.List;

public class WrapperExample {
    public static void main(String[] args) {
        List<Integer> intList = new ArrayList<>();
        // 自动装箱:int -> Integer
        intList.add(10); 
        intList.add(20);
        
        for (Integer num : intList) {
            // 自动拆箱:Integer -> int
            // 输出:10 20
            System.out.println(num); 
        }
    }
}
  1. 泛型编程

泛型类和方法只能使用引用类型,从而在泛型参数中必须使用封装类型。

public class GenericContainer<T> {
    private T item;

    public void setItem(T item) {
        this.item = item;
    }

    public T getItem() {
        return item;
    }

    public static void main(String[] args) {
        GenericContainer<Integer> container = new GenericContainer<>();
        // 自动装箱:int -> Integer
        container.setItem(100); 
        // 自动拆箱:Integer -> int
        // 输出:100
        System.out.println(container.getItem()); 
    }
}
  1. 与API交互

一些API或第三方库要求使用对象而不是基本数据类型。封装类型满足这些要求。

import java.util.Optional;

public class ApiExample {
    public static void main(String[] args) {
        // 自动装箱:int -> Integer
        Optional<Integer> optionalInt = Optional.of(30); 
        // 自动拆箱:Integer -> int
        // 输出:30
        optionalInt.ifPresent(System.out::println); 
    }
}
  1. 空值处理

封装类型可以表示null,而基本数据类型不能。有些场景需要处理空值,例如数据库查询结果。

public class NullHandlingExample {
    public static void main(String[] args) {
        // 封装类型可以为null
        Integer possibleNullInt = null; 
        if (possibleNullInt == null) {
            System.out.println("The value is null");
        } else {
            System.out.println(possibleNullInt);
        }
    }
}
  1. 反射操作

反射机制通常基于对象,而封装类型使得反射操作更加方便。

import java.lang.reflect.Method;

public class ReflectionExample {
    public static void main(String[] args) throws Exception {
        Method parseIntMethod = Integer.class.getMethod("parseInt", String.class);
        // 使用Integer类的静态方法
        Object result = parseIntMethod.invoke(null, "123"); 
        // 输出:123
        System.out.println(result); 
    }
}

三、类型转换

数据类型转换可以分为隐式转换(也称为自动类型转换)和显式转换(也称为强制类型转换)

  1. 隐式转换(自动类型转换)

隐式转换是指Java编译器自动完成的类型转换。这种转换通常发生在将一种较小范围的数据类型赋值给较大范围的数据类型时。

例如:将int类型的变量赋值给long类型的变量。隐式转换是安全的,因为不会造成数据丢失。

public class ImplicitConversion {
    public static void main(String[] args) {
        int intVal = 100;
        // 自动将 int 转换为 long
        long longVal = intVal; 
        // 自动将 long 转换为 float
        float floatVal = longVal; 

        System.out.println("intVal: " + intVal);
        System.out.println("longVal: " + longVal);
        System.out.println("floatVal: " + floatVal);
    }
}
  1. 显式转换(强制类型转换)

显式转换需要开发者手动进行类型转换,通过在要转换的值前面加上目标数据类型的括号,这种转换通常用于将较大范围的类型转换为较小范围的类型。

例如:将double类型转换为int类型。显式转换可能会导致数据丢失或精度降低,因此要谨慎使用。

public class ExplicitConversion {
    public static void main(String[] args) {
        double doubleVal = 100.99;

        // 强制将 double 转换为 int
        int intVal = (int) doubleVal; 

        System.out.println("doubleVal: " + doubleVal);
        // 可能会丢失小数部分
        System.out.println("intVal: " + intVal); 
    }
}
  1. 字符与数值类型之间的转换

字符类型char可以与数值类型进行相互转换,char实际上是一个无符号的16位Unicode字符,可以存储0到65535之间的整数值。

public class CharConversion {
    public static void main(String[] args) {
        char charVal = 'A';
        // char 自动转换为 int
        int intVal = charVal; 

        System.out.println("charVal: " + charVal);
        // 输出65,'A'对应的ASCII码
        System.out.println("intVal: " + intVal); 

        intVal = 66;
        // 强制将 int 转换为 char
        charVal = (char) intVal; 
        System.out.println("intVal: " + intVal);
        // 输出'B'
        System.out.println("charVal: " + charVal); 
    }
}

四、集合类型

Java集合框架提供了一系列用来存储和操作数据的类和接口,不同的集合类型适用于不同的场景。

主要集合类型具体分析

  1. ArrayList
    • 实现:基于动态数组。
    • 查找效率:随机访问元素效率高,时间复杂度为O(1)。
    • 插入和删除效率:在尾部进行插入和删除操作效率高,但在中间和头部插入和删除时需要移动元素,时间复杂度为O(n)。
    • 线程安全:非线程安全,需要外部同步。
    • 适用场景
      • 频繁的读取操作,如需要快速随机访问元素的场景。
      • 插入和删除操作相对较少的场景。
      • 数据量可预测且变化不频繁。
List<String> arrayList = new ArrayList<>();
arrayList.add("Apple");
arrayList.add("Banana");
// 输出:Banana
System.out.println(arrayList.get(1)); 
  1. LinkedList
    • 实现:基于双向链表。
    • 查找效率:随机访问效率较低,时间复杂度为O(n)。
    • 插入和删除效率:插入和删除操作效率高,时间复杂度为O(1)。
    • 线程安全:非线程安全,需要外部同步。
    • 适用场景
      • 频繁的插入和删除操作。
      • 不常进行随机访问的场景。
      • 需要实现队列或栈结构时。
List<String> linkedList = new LinkedList<>();
linkedList.add("Apple");
linkedList.addFirst("Banana");
// 输出:Banana
System.out.println(linkedList.get(0)); 
  1. HashSet
    • 实现:基于哈希表。
    • 查找效率:查找、插入和删除操作的平均时间复杂度为O(1)。
    • 重复元素:不允许存储重复元素。
    • 线程安全:非线程安全,需要外部同步。
    • 适用场景:
      • 需要快速查找元素是否存在。
      • 需要保持数据的唯一性,不关心元素的顺序。
Set<String> hashSet = new HashSet<>();
hashSet.add("Apple");
hashSet.add("Banana");
// 重复元素不会被添加
hashSet.add("Apple"); 
System.out.println(hashSet.size()); // 输出:2
  1. HashMap
    • 实现:基于哈希表。
    • 查找效率:查找、插入和删除操作的平均时间复杂度为O(1)。
    • 键值对:允许存储null值和null键。
    • 线程安全:非线程安全,需要外部同步。
    • 适用场景
      • 需要根据键快速查找对应的值。
      • 无需关心键值对的顺序。
Map<String, Integer> hashMap = new HashMap<>();
hashMap.put("Apple", 3);
hashMap.put("Banana", 2);
// 输出:3
System.out.println(hashMap.get("Apple")); 
  1. LinkedHashMap
    • 实现:基于哈希表和双向链表。
    • 查找效率:查找、插入和删除操作的平均时间复杂度为O(1)。
    • 键值对顺序:维护插入顺序或访问顺序。
    • 线程安全:非线程安全,需要外部同步。
    • 适用场景:
      • 需要按插入顺序或访问顺序迭代键值对。
      • 需要关联的最近使用(LRU)缓存实现。
Map<String, Integer> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("Apple", 3);
linkedHashMap.put("Banana", 2);
for (Map.Entry<String, Integer> entry : linkedHashMap.entrySet()) {
    System.out.println(entry.getKey() + ": " + entry.getValue());
}

// 输出:
Apple: 3
Banana: 2
  1. TreeMap
    • 实现:基于红黑树。
    • 查找效率:查找、插入和删除操作的时间复杂度为O(log n)。
    • 键值对顺序:按自然顺序或指定的比较器顺序排序。
    • 线程安全:非线程安全,需要外部同步。
    • 适用场景:
      • 需要按键的自然顺序或自定义顺序迭代键值对。
      • 需要实现有序映射,比如按字母顺序存储单词。
Map<String, Integer> treeMap = new TreeMap<>();
treeMap.put("Banana", 2);
treeMap.put("Apple", 3);
for (Map.Entry<String, Integer> entry : treeMap.entrySet()) {
    System.out.println(entry.getKey() + ": " + entry.getValue());
}

// 输出:
Apple: 3
Banana: 2

五、并发类型

Java的并发类型提供了一系列用来处理多线程并发操作的类和接口,能够帮助开发者编写线程安全的程序。

并发类型的具体分析:

  1. synchronized
    • 实现:通过关键字synchronized实现同步。
    • 线程安全:确保代码块或方法在同一时刻只能被一个线程执行,从而避免多线程并发访问时的数据竞争问题。
    • 适用场景
      • 适用于对特定代码块或方法进行简单的同步控制。
public synchronized void synchronizedMethod() {
    // 同步的方法体
}
  1. ReentrantLock
    • 实现:基于显示锁的机制。
    • 功能:提供了比synchronized更灵活的锁机制,支持公平性选择和可中断性。
    • 适用场景
      • 适用于需要更高级的锁功能,比如公平锁、可重入锁等。
ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
    // 需要同步的代码块
} finally {
    lock.unlock();
}
  1. Semaphore
    • 实现:基于计数信号量的机制。
    • 功能:用来控制同时访问特定资源的线程数量,限流的作用。
    • 适用场景
      • 适用于控制对某些资源的并发访问权限,比如数据库连接池、线程池等。
// 允许10个线程同时访问
Semaphore semaphore = new Semaphore(10); 
semaphore.acquire();
try {
    // 资源访问操作
} finally {
    semaphore.release();
}
  1. CountDownLatch
    • 实现:基于计数器的机制。
    • 功能:允许一个或多个线程等待其他线程完成操作后再继续执行。
    • 适用场景
      • 适用于等待其他线程完成某项任务后再进行后续操作的场景。
// 初始计数为1
CountDownLatch latch = new CountDownLatch(1);
// 线程1
// 完成操作
latch.countDown(); 
// 线程2
// 等待操作完成
latch.await();
  1. CyclicBarrier
    • 实现:基于栅栏的机制。
    • 功能:让一组线程相互等待,直到所有线程都到达栅栏位置后再继续执行。
    • 适用场景
      • 适用于多个线程之间相互等待,然后同时开始执行下一阶段任务的场景。
// 等待3个线程到达
CyclicBarrier barrier = new CyclicBarrier(3); 
// 线程1
barrier.await();
// 线程2
barrier.await();
// 线程3
barrier.await();
// 所有线程都到达后继续执行
  1. ConcurrentHashMap
    • 实现:基于哈希表的并发HashMap实现。
    • 线程安全:内部实现了分段锁机制,提供了比Hashtable更高效的并发性能。
    • 适用场景:适用于多线程并发访问的场景,比如作为缓存或全局共享的数据结构。
ConcurrentMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
concurrentMap.put("key", 1);

每一天都是起跑线,勇敢迈出第一步

  • 129
    点赞
  • 119
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 240
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

忆~遂愿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值