4 Data Type and Type Checking笔记

本文探讨了Java中的数据类型,包括基本数据类型与对象数据类型的区别,以及它们的内存分配方式。此外还讨论了静态类型检查的重要性,并对比了可变对象与不可变对象的特点及其在编程中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

4 Data Type and Type Checking

1.编程语言的数据类型
​ 在Java中,数据类型分为基本数据类型(int、boolean、char等)和对象数据类型(String、Integer等)。
🔺基本数据类型(int, long, byte, short, char, float, double, boolean)都是Immutable的;栈(局部变量;成员变量在堆中)中分配内存,且仅在使用时存在;没有统一的表达;代价比较低。
🔺对象数据类型(类、接口、数组、枚举、注释)有的是
Immutable
的,有的是Mutable的;分配的内存都在中(局部变量对象引用存在栈中,对象存在堆中;成员变量在堆中),自动垃圾回收;可用泛型统一表达;代价相对昂贵。
因此在能使用基本类型的情况下尽量使用基本数据类型,降低代价。

对象数据类型是OOP的核心,由于对象数据类型存在继承(extends)机制,因此在OOP中可以更好的复用代码。

基本类型被包装为对象类型,通常只有在定义集合的时候使用,其他情况下尽量避免使用。基本类型和对象类型之间一般可以自动转换

2.静态类型检查——重在类型
静态类型语言,如Java,可在编译阶段进行类型检查,发现语法错误、函数名/类名错误、返回值类型错误等错误。
例如:

int n = 1;
if (n) {
 n = n + 1;
}

错误提示: Type mismatch: cannot convert from int to boolean;

3.动态类型检查——重在数值
动态类型语言,如Python,只有动态类型检查,在运行阶段才进行类型检查,发现如非法参数值、非法返回值、越界、除0、空指针等错误。

静态类型检查 >> 动态 >> 无检查

4.Mutability and Immutability

改变一个变量: 将该变量指向另一个值的存储空间———改变引用
改变一个变量的值: 将该变量当前指向的值的存储空间中写入一个新的值———改变值

Notefinal类无法无法被继承;final变量无法改变/引用(注意区别);final方法无法被子类重写;

final修饰的变量表示赋值之后不能再进行更改;
final修饰的成员变量需要在定义时就初始化或在构造方法中初始化

对于基本类型,final使数值恒定不变
而对于对象引用,final使引用恒定不变。一旦引用被初始化指向一个对象,就无法再把它改为指向另一个对象。

不变对象 Immutable types: 一旦被创建,始终指向同一个值/引用,更安全。若要改变内部值,需要构造新的对象
缺点: 使用不可变类型,对其频繁修改会产生大量的临时拷贝(需要垃圾回收)。

可变对象: 拥有方法可以修改自己的值/引用,更灵活。如StringBuilder
但是在质量指标中,性能的优先级较低。

区别:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

例子: mutable潜在的风险,这种情况非常难以跟踪发现,也难以被其他开发者理解

/* @return the sum of the numbers in the list */
	public static int sum (List<Integer> list) {
	    int sum =0;
	    for (int x: list) sum += x;
	    return sum;
	}

	/* @return the sum of the absolute values of the numbers in the list */
	public static int sumAbsolute (List<Integer> list) {
	    // let's reuse sumo), because DRY, so first we take absolute values
	    for (int i =0; i<list.size(); i++)
	         list.set(i, Math.abs(list.get(i)));//改变了list内容
	    return sum(list);
	}

	//client
	public static void main(String[] args) {
	    List<Integer> myData=new ArrayList<Integer>();
	    myData.add(-5);
	    myData.add(-3);
	    myData.add(-2);
	    System.out.println(sumAbsolute(myData)); //期望值10,实际值10
	    System.out.println(sum(myData)); //期望值-10,实际值10

解决的办法: 通过防御式拷贝——给客户端传送一个全新的Date对象(除地址外一样),客户端即使对数据做了更改,也不会影响到自己。我们解决了外部对内部的无意改动,但为此付出的代价就是空间的浪费。
而如果使用immutale类型的数据,就不存在这种风险

同时,我们编程的时候也要注意避免出现一个对象的多个引用,也就是说尽量不要让一个对象出现别名

5.代码快照(Snapshot diagram)

Primitive values 基本类型的值:
基本类型的值由常数表示。 传入箭头是对变量或对象字段中的值的引用
在这里插入图片描述
Object values 对象类型的值:
对象类型的值是一个按其类型标记的圆。当我们想要显示更多的细节时,我们在里面写字段名,用箭头指向它们的值。对于更详细的信息,字段可以包括其声明的类型。
在这里插入图片描述
注意:
不可变对象: 用双线椭圆
不可变的引用(final声明): 用双线箭头

引用是不可变的,但指向的对象却可以是可变的——final StringBuilder sb
可变的引用,也可指向不可变的对象——String s

集合类型:
List:
在这里插入图片描述
Set:
在这里插入图片描述

Map:
在这里插入图片描述

注意: 遍历集合类中的元素并对集合做修改时,要使用Iterator来做迭代器,避免bug。

上述的这些集合类型被传到其他地方时有可能会被更改,于是可用Collections.unmodifiabbleList()Collections.unmodifiabbleSet()Collections.unmodifiabbleMap()做一次封装,这样给外界的时候就是一个不可更改的类型了;
而且如果封装前的类型的对象做了增删改,那么封装后的也会表现出增删改后的状态,因为实际上这两个指向的是同一块内存区域。如下,list有改动,listCopy也会被改动

List<String> list = new ArrayList<>();
List<String> listCopy = Collections.unmodifiableList(list);
list.add("a"); //list中有一个元素a,listCopy中也有了一个元素a
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值