软件构造学习笔记第四章——数据类型与类型检验

目录

1.java

1.1基本数据类型和对象数据类型的区别

1.2静态类型语言和动态类型语言(java是静态)

1.2.1概念

1.2.2静态类型检查的错误(可能会考)(关于类型的错误)

1.2.2动态类型检查的错误(可能会考)(关于值的错误)

1.2.3错误举例

2.可变和不可变数据类型

2.代码快照图(Snapshot diagram)

2.1什么是代码快照图

2.2为什么使用代码快照图

2.3怎么画代码快照图

2.3.1基本数据类型

 2.3.2对象数据类型

3.java的一些类型

3.1List\Array\Set\Map\Iterator

3.1.1List

3.1.2Array

3.1.3Set

3.1.4Map

3.1.5Iterator

3.1易错(注:iter是自定义的迭代器)

4.常用的不可变类型

4.1包装器


两个核心知识点:什么是可变/不可变类型,snapshot diagram大题出现。

1.java

1.1基本数据类型和对象数据类型的区别

1.2静态类型语言和动态类型语言(java是静态)

1.2.1概念

①静态类型语言:在编译阶段进行类型检查

②动态类型语言:在运行阶段进行类型检查

1.2.2静态类型检查的错误(可能会考)(关于类型的错误)

①语法错误

②函数名/类名错误

③参数数目错误

④参数类型错误

⑤返回值类型错误

1.2.2动态类型检查的错误(可能会考)(关于值的错误)

①非法的参数值,比如x/y时y取0。

②非法的返回值,(待举例)

③数组越界

④访问空指针

1.2.3错误举例

除了第一个之外,其余的都是动态错误,有的动态错误是不符合期望输出,有的是直接抛出异常。

对于第一个,注意,在java里面,if放的只有boolean型的数据,而非像C语言那样所有非0的则为真。

对于数据的计算,以第四个为例,在进行int average = sum/n计算时,首先先按照右边进行计算,也就是说此时sum和n是int类型,所以会按照int类型计算,由于int类型除零会抛出异常,因此直接抛出异常。如果此时是int sum = 0,double n = 0,double average = sum/n的话,由于n是double类型,所以会将sum也转为double类型进行计算,得出来的结果是Infinity也是double类型,然后再将double类型的数据赋给average。如果是int sum = 0,double n  = 0,int average = sum/n,那么直接就会在静态编译阶段报错。综上所述,进行数据计算时,首先是根据右边的数据类型进行计算,再赋值给左边的变量。

2.可变和不可变数据类型

java有两种赋值的方式。一种是改变变量,一种是改变变量的值。

改变变量:将该变量指向另一个值的存储空间。

改变一个变量的值:将该变量当前指向的值的存储空间种写入新的值。

不可变数据类型和可变数据类型(mutable &immutable)_mistical的博客-CSDN博客_不可变数据类型

以下所有的内容都是基于内存地址来说的。
不可变数据类型: 当该数据类型的对应变量的值发生了改变,那么它对应的内存地址也会发生改变,对于这种数据类型,就称不可变数据类型。
可变数据类型 :当该数据类型的对应变量的值发生了改变,那么它对应的内存地址不发生改变,对于这种数据类型,就称可变数据类型。
总结:不可变数据类型更改后地址发生改变,可变数据类型更改地址不发生改变
————————————————
版权声明:本文为CSDN博主「mistical」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/sup_chao/article/details/84848237

认识final:

在使用赋值语句时,通常通过两种形式完成赋值操作,引用和非引用形式,其中引用形式又可再分为可变引用和不可变引用。首先是非引用形式,例如int x=5;x=6;这样的赋值就是非引用形式,x存放在栈上,编译阶段就为x分配好了一个特定空间,改变值也是改变该空间的值。然后再说可变引用,如果引用的是不可变类型的话,那么它只能通过引用别的内存地址的变量来完成对值的改变,如果引用的是可变类型的话,那么它既可以通过改变可变类型的内容来完成对值的改变,也可以通过引用别的内存地址的变量来完成对值的改变。最后说不可变引用,它无法通过引用别的内存地址的变量来完成对值的改变,只能通过对可变类型变量内容的改变来完成对值的改变,如果它引用的是不可变类型变量,那么它就永远无法改变。final作用于非引用形式和引用形式,它对于非引用形式的作用是,如果final int x=5,那么是无法再度给x进行赋值的;它对引用形式的作用是,它可以把可变引用变成不可变引用。

final修饰的类不能派生子类;

final修饰的方法不能被重写;

final修饰的基本数据类型变量无法改变其值;

final修饰的对象类型变量无法改变其指向;

  如果编译器无法确定final变量不会改变,就提示错误,属于静态类型检查。


这两种类型的用途

开始t和s指向同一个串,后面t发生改变了,由于是不可变类型,因此s不会发生改变,t是指向了一个新的串。tb和sb也是指向同一个串,由于是可变数据类型,tb改变了,sb也会改变。


两种类型的优缺点

①不可变类型:使用不可变类型,安全,但是对其频繁修改会产生大量的临时拷贝(需要垃圾回收)。

②可变类型:可变类型最少化拷贝以提高效率,可以获得更好的性能,也适用于多个模块共享数据。


两种类型的运用场景

①不可变类型:当用户需要频繁改动数据且改动该数据可能会带来错误时,使用不可变类型,增加安全性。

②可变类型:当用户不会频繁改动数据且改动该数据不会带来错误时,使用可变类型。但是当可变类型变量只在一个方法中使用,只涉及一个引用,不参与共享的也可以使用可变类型。 


String. trim()方法是把字符串中收尾的空格去掉,返回一个新的字符串。

注:当用户想改变类内部的值只能通过类内部的方法进行改变时,这才叫安全。

不安全例子①:

/**@return the sum of the numbers in the lists*/
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 numbers in the list*/
public static int sumAbsolute(List<Integer> list)
{
    for(int i = 0;i < list.size() ; i++)
    {
        list.set(i,Math.abs(list.get(i)));
    }
    return sum(list);
}

public static void main(String[] args)
{
    List<Integer> myData = Arrays.asList(-5,-3,-2);
    System.out.println(sumAbsolute(myData));//result = 10
    System.out.println(sum(myData));//result = 10
}

因为List是可变类型,当作为参数传入sumAbsolute,这个方法改变了List中的值。

解决方法:在sumAbsolute时重新new一个List类型的值进行计算或者传入不可变类型,则节省了复制的代价。

注意事项:方法不能改变传入参数的值。

不安全例子②:当在Period外部定义的end改变时,会导致p中的end也发生改变。返回指针为类中变量的指针,同样会导致外部修改而使内部也发生改变。

原因有三个:①end是可变类型②在Period的构造器中没有重新申请一个位置给p中的end③返回时直接把类内部的指针返回出去了。

解决方法:重新申请一个位置给p中的end。不直接返回类内部变量的指针。

 

在使用可变类型时,一定要注意有几个引用指向它。 

2.代码快照图(Snapshot diagram)

2.1什么是代码快照图

代码快照图是用于描述程序在运行时的某一个时刻代码中变量在内存中的情况的图。

2.2为什么使用代码快照图

①便于程序员之间的交流

②便于刻画各类变量随时间变化

③便于解释设计思路

2.3怎么画代码快照图

2.3.1基本数据类型

(没有圆框框)

 2.3.2对象数据类型

(有圆框框,可变对象用单圆)(对象内部的所有属性都是存在堆里的,哪怕是基本数据类型也是存在堆里,但指向对象的变量是存放在栈里面的,对象的内容是存放在堆里面的)

(不可变对象用双圆)

 (final表示不可变的引用,用双线箭头)

 

3.java的一些类型

3.1List\Array\Set\Map\Iterator

3.1.1List

List是接口,所有放在List容器中的都是对象类型(不是基本数据类型),它的长度是可变的。基本操作:

3.1.2Array

Array是数组,长度不可变,可放基本数据类型。基本操作:

3.1.3Set

Set是接口,是一个无序存放不重复对象的集合,基本操作:

3.1.4Map

Map是接口,存放键值。基本操作:

  

3.1.5Iterator

迭代器是一个可变类型,常用于遍历某个集合或容器。

3.1易错(注:iter是自定义的迭代器)

期望值是空,实际输出非空。注意iter里面的index是不会因为移除容器中的元素而减的,而移除容器中的元素时元素又会重新排序。

(当使用java的迭代器时,在遍历操作时是不允许使用remove的。)

4.常用的不可变类型

4.1包装器

        即对原来可变类型加上一层包装,把可变类型的类中可能改变属性的操作给去掉,形成“不可变”类型参考包装函数。 但是这种不可变是在运行阶段获得的,在静态无法检测出来,即假如pad是经过包装形成的不可变类,pad.add在编译阶段是可以通过的,但是在运行时会抛出异常。而且此时的不可变并非真的不可变,如果在包装之前有一个引用指向该类型,在包装之后该引用还存在,那么还可以通过该引用来改变它内部的值。如下图,不能通过listcopy来改变它的值,但是能通过list改变它的值。

(java提供了一系列可变类型转化成不可变类型的操作)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值