数据类型

基本类型

基本类型

Java 语言提供了八种基本类型,用户无需定义也可以直接使用。其数据保存在相应的方法栈中。

基本数据类型 字节数 默认值 包装数据类型 取值范围
byte 1 0 Byte 负的2的7次方 ~ 2的7次方-1(-128~127)
short 2 0 Short 负的2的15次方 ~ 2的15次方-1(-32768~32767)
int 4 0 Integer 负的2的31次方 ~ 2的31次方-1
long 8 0 Long 负的2的63次方 ~ 2的63次方-1
float 4 0.0f Float 1.401298e-45 ~ 3.402823e+38
double 8 0.0 Double 4.9000000e-324 ~ 1.797693e+308
char 2 null Character 0-65535
boolean 1 false Boolean true,false
  • 布尔型

boolean 类型只含有两个值:true 和 false。字节存储为 11111111 和 00000000 。


boolean b = true;      
boolean b = false;   

  • 字符型

char 类型使用单引号来表示字符。因为 Java 统一采用 unicode 编码,2 字节可以表示一字符。char 类型同样可以用十六进制码保存汉字等特殊字符:'\u0000' - '\uffff'。


char ch = 'a';      
char ch = '中';
char ch = '/u3089';   

  • 整型和浮点型

Java 没有无符号类型,所有数据都有符号。

1. 整型(byte/short/int/long) 用来表示整型数据。

2. 浮点型(float/double) 用来表示浮点数据,实际以指数形式存储,所以和实际值之间有偏差

    * 为 float 类型赋值必须在数字后加 f,否则数字默认被识别为 double 类型,会导致赋值出错。

    * 数字基本类型都包含最大最小值常量,如 Integer.MAX_VALUE 和 Integer.MIN_VALUE .

    * 在浮点型有三个特殊数值表示溢出和出错:

      - POSITIVE_INFINITY :正无穷大,正数除以 0 可以得到。

      - NEGATIVE_INFINITY :负无穷大,负数除以 0 可以得到。

      - NaN :非数,零除以 0 可以得到。(两个 NAN 值也不相等)

int n = 0;
float f = 0.0f;
long l = Long.MAX_VALUE;               
double d = POSITIVE_INFINITY;

包装类型

均继承自 Number 抽象类,把基本类型数据封装成对象。基本类型和包装类型之间会自动进行转化。

基本类型(如int),是一个值。允许不赋初值,系统自动添加默认值。

包装类型(如Integer),是一个对象。实例化必须赋初值,且赋值后不能改变(final)。

* 自动装箱:基本类型的数据和变量可以直接赋值给包装类型的变量。

* 自动拆箱:包装类型的变量可以直接赋值给基本数据类型的变量。

* 包装类型主要用于集合框架中的元素。但阿里巴巴要求所有实体类(POJO) 属性、远程过程调用方法(RPC) 的返回值和参数都必须使用包装数据类型。以此来提醒使用者在需要使用时,必须显式地进行赋值。

* 基本类型的数据转换成字符串类型(用处不大),开发中通常用 String str = 23+””;(整形拼接一个空字符串得到)

* Integer.toString(基本类型的数据)  // 调用toString()方法得到字符串结果

* 字符串类型的数值转换成基本数据类型

  - 方式一:
      Integer.parseInt(“字符串类型的整数”)
      Double.parseDouble(“字符串类型的小数”)

  - 方式二:(开发中常用)
      Interger.valueOf()
      Double.valueOf()

类型转换

  • 自动类型转换
对于基础类型,按上图顺序可以自动进行类型转换。但整型转化为浮点型时,如果数据过大可能会导致数据丢失精度。

* 表达式的自动类型转换
  在表达式中,小范围类型的变量会自动转换成当前较大范围的类型再运算。

  注意事项:
    表达式的最终结果类型由表达式中的最高类型决定。
    在表达式中,byte、short、char 是直接转换成int类型参与运算的。
  • 强制类型转换
* 可以强行将类型范围大的变量、数据赋值给类型范围小的变量。

* 类型范围大的数据或者变量,不能直接赋值给类型范围小的变量,会报错。

  注意事项:
    强制类型转换可能造成数据(丢失)溢出,如下图所示;
    浮点型强转成整型,直接丢掉小数部分,保留整数部分返回。

数组

Array 类

数据的集合。本质是一个对象,数据存储在堆区,由引用指向数组首个元素的地址。

  • 创建数组

创建数组时,必须确定数组长度和类型。但如果储存的是基本类型,允许不赋初值(使用默认值)。


int[] arr = {1,2,3,4};                     // 方法一,静态初始数组(简化版格式)    数据类型[] 数组名 = {元素1,元素2,...};
int[] arr = new int[]{1,2,3,4};            // 方法二,静态初始数组(完整版格式)    数据类型[] 数组名 = new 数据类型[]{元素1,元素2,...};
int[] arr = new int[4];                    // 方法三,动态初始化格式             数据类型[] 数组名 = new 数据类型[数组长度];

数组长度:在数组对象中,定义了 length 属性记录了数组长度。


int len = arr.length;                      // 返回数组长度  

Arrays 类

数组操作工具类,专门用于操作数组元素的。

  • 打印数组元素

Arrays.toString(arr);    // 返回数组的内容(字符串形式)

  • 数组排序
Arrays.sort(arr);                 // 数组排序,默认数组数值从小到大排列

Arrays.binarySearch(arr, key);    // 二分搜索数组中的数据,存在返回索引,不存在返回-1(前提数组必须排好序才支持,否则出bug)

Integer[] arr = {1, 2, 6, 8};
Arrays.sort(arr, new Comparator<Integer>() {    // 自定义数组的排序规则:Comparator比较器对象,只能支持引用类型的排序!!
    @Override
    public int compare(Integer o1, Integer o2) {
        return o1 - o2; // 默认升序
        // return o2 - o1; //  降序
        // return Double.compare(o2.getHeight(), o1.getHeight()); // 比较浮点型可以这样写  降序
    }
});

  • 数组拷贝和修改
int[] arr2 = Arrays.copyOfRange(arr, 1, 4); // (类型[] arr, 起始索引, 结束索引) :拷贝数组(指定范围,包前不包后)

int[] arr3 = Arrays.copyOf(arr, 10);        // (类型[] arr, int newLength):拷贝数组,可以指定新数组的长度。


// public static setAll(double[] array, IntToDoubleFunction generator):把数组中的原数据改为新数据又存进去。
double[] prices = {99.8, 128, 100};
//                  0     1    2
// 把所有的价格都打八折,然后又存进去。
Arrays.setAll(prices, new IntToDoubleFunction() {
    @Override
    public double applyAsDouble(int value) {
        // value = 0  1  2
        return prices[value] * 0.8;
    }
});
System.out.println(Arrays.toString(prices));

字符串

String 类

保存字符串。String 类本质是一个 final 对象,由引用指向存储字符串对象的地址。引用虽然可变,但内存数据不能被更改。
image-20210814174242688

  • 创建字符串
String 对象创建后一经赋值不再改变,有以下两种创建方式:

    * 直接赋值:如果常量池没有,则在常量池新建对象。否则直接使用常量池中已有对象,引用指向常量池。
    * 构造方法:如果常量池没有,则在常量池新建对象。无论如何一定会在堆区创建对象,引用指向堆区。
String str1 = "string";                       // 引用指向常量池
String str2 = "str" + "ing";                  // 引用指向常量池(指向 str1 的字符串对象)

String str3 = new String("string");           // 引用指向堆区(在堆区新建字符串对象)
String str4 = str1 + str2;                    // 引用指向堆区

String newStr = new String(str.getBytes("ISO-8859-1"), "GBK");          // 获取指定类型编码对象,按指定类型编码(构造器创建对象)
String str1 = "goodbye";                      // str1 指向新的字符串对象
  • 常用方法
boolean b = str.equals(Object anObject)                    // 将此字符串与指定对象进行比较,只关心字符内容是否一致
boolean b = str.equalsIgnoreCase(String anotherString)     // 将此字符串与指定对象进行比较,忽略大小写比较字符串,只关心字符内容是否一致


int len = str.length();                   // 返回字符串长度
char ch = str.charAt(int index)           // 获取某个索引位置处的字符
char[] arr = str.toCharArray()            // 将当前字符串转换成字符数组返回

String[] strs = str.split(",");           // 按分隔符分解字符串,返回字符串数组

boolean c = str.contains(str2);           // 判断是否包含xxx字符串
boolean c = str.startsWiths(str2);        // 判断是否以xxx字符串开头
int index = str.indexOf(str2);            // 查找子字符串出现的第一个位置,没有返回-1
int index = str.lastIndexOf(str2);        // 查找子字符串出现的最后一个位置,没有返回-1

String str2 = str.trim();                 // 去除字符串左右空格  
String str2 = str.substring(0,3);         // 截取指定位置(0-2)的子字符串,得到新的字符串(包前不包后)
String str2 = str.substring(1);           // 从当前索引为1的位置一直截取到末尾
String str2 = str.replace("a", "b");      // 新字符 a 替换旧字符 b

  • 类型转换
// Number > String

String s1 = data.toString();              // data 必须为包装数据类型
String s2 = Integer.toString(data);       // data 可以为基础数据类型,包括字符数组 char[]
String s3 = String.valueOf(data);         // data 可以为基础数据类型,包括字符数组 char[]

// String > char

char c = str.charAt(0);
char[] ch = str.toCharArray();

// String > int

int n1 = Integer.parseInt(str);          
int n2 = Integer.valueOf(str);

StringBuilder / StringBuffer 类

由于 String 类不可变性,对其频繁更改往往会产生较多临时变量类,占用大量内存。对此我们通常使用 StringBuilder/StringBuffer 来避免,这两个类允许在原有内存地址对字符串进行操作。其中 StringBuilder 类性能更好,StringBuffer 类线程安全。
image-20210814174242688

  • 创建字符串

必须通过构造方法创建,不可以直接赋值的形式创建:StringBuffer str = "hello";。

字符串默认长度为16,超出后会进行自动扩容。

StringBuffer str = new StringBuffer();           // 创建一个空白可变字符串对象,不含有任何内容
StringBuffer str = new StringBuffer("hello");    // 创建一个指定字符串内容的可变字符串对象

String str2 = str.toString();                    // 将 StringBuilder / StringBuffer 类转化为 String 
  • 专用方法

StringBuilder / StringBuffer 类可以使用 String 类的全部方法,还新增了以下方法直接对字符串进行修改。

str.append("add");                 // 末尾添加字符串数据并返回StringBuilder对象本身,可以是任意类型
str.insert(0,"insert");            // 指定位置插入字符串,也可以是其他基础类型
str.deleteCharAt(6);               // 删除指定位置(6)的字符
str.delete(6,8);                   // 删除指定位置(6和7)的字符串
str.reverse(str2);                 // 翻转字符串
str.length();                      // 返回对象内容长度

大数

在 Java 程序中,我们可能会用到一些数值特别巨大、或者小数特别精确的数值,这些数值无法用基础类型表示。因此我们定义了 BigInteger/BigDecimal 类来保存这类数据,实际是以字符串形式在堆区存储。

BigInteger 类

主要用来操作比 long 类型更大的整型数字。

BigDecimal 类

基于 BigInteger 类实现。由于基本浮点数类型(float/double) 会产生精度丢失问题,因此常使用 BigDecimal 类代替。涉及金额必须使用该类。

  • BigInteger 和 BigDecimal 类常用方法
// 包装浮点型数据成为大数据对象 BigDecimal
BigDecimal a = BigDecimal.valueOf(0.1);
BigDecimal b = BigDecimal.valueOf(0.2);

// 运算方法
BigDecimal x = a.add(b);                  // 加
BigDecimal x = a.subtract(b);             // 减
BigDecimal x = a.multiply(b);             // 乘
BigDecimal x = a.divide(b);               // 除    除不尽的情况需要设置参数(参数一:除数 参数二:保留小数位数  参数三:舍入模式)                              
BigDecimal x = a.abs();                   // 绝对值
a.compareTo(b);                           // 比较大小

// BigDecimal 类专用
BigDecimal x = y.setScale(3, rules);      // 设置精度和保留规则
// 舍入模式:四舍五入(RoundingMode.HALF_UP)、进一法(RoundingMode.HALF_UP)、去尾法(RoundingMode.FLOOR)

Double c = x.doubleValue();               // 将BigDecimal对象类型转换为double类型

常量

1.常量是使用了public static final修饰的成员变量,必须有初始化值,而且执行的过程中其值不能被改变。
2.常量的作用和好处:可以用于做系统的配置信息,方便程序的维护,同时也能提高可读性。
3.常量命名规范:英文单词全部大写,多个单词下划线连接起来。

常量的执行原理
1.在编译阶段会进行“宏替换”,把使用常量的地方全部替换成真实的字面量。
2.这样做的好处是让使用常量的程序的执行性能与直接使用字面量是一样的。

枚举

Enum 类

(JDK 1.5 新增)比 Class 类多了部分特殊约束的特殊类型,能更加简洁地定义常量。

使代码更具可读性,允许进行编译时检查,预先记录可接受值的列表,并避免由于传入无效值而引起的意外行为。

自定义枚举类实际是继承 Enum 类的 final 类,在类中将自定义该类型的 public static final 属性,并引入了相关方法

javac 编译 javap 反编译

// 定义枚举类
public enum Day {
    MONDAY, TUESDAY, WEDNESDAY,
    THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

// 使用枚举类
public class Demo {
    public boolean test(Day today){
        if(today == Day.MONDAY) return true;
        else return false;
    }
}

/*
枚举的特征:

枚举类都是继承了枚举类型:java.lang.Enum
枚举都是最终类,不可以被继承。
构造器都是私有的,枚举对外不能创建对象。
枚举类的第一行默认都是罗列枚举对象的名称的
枚举类相当于是多例模式。
*/

泛型

泛型定义

定义类时并不固定数据类型,等到创建对象或调用方法时再明确数据类型。(泛型只能支持引用数据类型)

编译过程中,由编译器检查类型安全,自动隐性地对类的数据类型进行强制转换(Object -> 指定数据类型)。编译后生成的 字节码文件(.class) 将不再含有泛型。

泛型使用

可使用 A-Z 之间的任何一个字母,常用:

T (type): 表示具体的一个 java 类型
K V (key value): 分别代表 java 键值中的 Key Value
E (element): 代表 java 集合框架元素
?:表示不确定的 java 类

泛的原理:把出现泛型变量的地方全部替换成传输的真实数据类型,此处泛型变量T可以随便写为任意标识,常见的如E、T、K、V等。

// 自定义泛型类(编译阶段可以指定数据类型,类似于集合的作用。)
public class MyArrayList<T> {} 

// 自定义泛型方法(方法中可以使用泛型接收一切实际类型的参数,方法更具备通用性。)
public <T> void show(T t) {} 

// 自定义泛型接口(泛型接口可以让实现类选择当前功能需要操作的数据类型,这样重写的方法都将是针对于该类型的操作。)
public interface Date<E>{}

泛型通配符、上下限

通配符:?

? 可以在“使用泛型”的时候代表一切类型。
E T K V 是在定义泛型的时候使用的。

泛型的上下限:

public static void go(ArrayList<? extends Car> cars){}
? extends Car: ?必须是Car类或者其子类 泛型上限
? super Car : ?必须是Car类或者其父类 泛型下限
posted @ 2023-03-16 09:55  晚点心动。  阅读(81)  评论(0)    收藏  举报