Week 5.1 | Lecture 13 | 一些其他Java特性:自动转换和不变性 | CS61B-Spring-2018

一、自动转换

1. Autoboxing and Unboxing

  • 原始类型对应的引用类型

Java有8种原始类型,所有其他类型都是引用类型。Java的一个特殊功能是我们不能提供原始类型作为泛型的实际类型参数,例如ArrayDeque<int>语法错误。相反,我们使用ArrayDeque<Integer>。对于每种基本类型,我们使用相应的引用类型,如下表所示。这些引用类型称为“wrapper(包装) classes”。
在这里插入图片描述
wrapper class是这么定义的:
在这里插入图片描述
所以一个Integer需要64 bits存一些乱七八糟的信息如动态类型之类的内容和32 bits存int值。

  • box and unbox

Java可以在原始类型和包装类型之间进行隐式转换,Java将在原始类型及其对应的引用类型之间自动“box”和“unbox”values。也就是说,如果Java需要wrapper class(例如Integer),并且您提供了原始类型(例如int),它将“autobox” the integer。

同样,如果Java需要原始类型(例如int),但您给它一个对应的wrapper类型的值(例如Integer),它将automatically unbox the integer。

  • 自动装箱和拆箱时需要牢记以下几点
  1. 数组永远不会autobox或auto-unbox,例如,如果您有一个整数数组int[] x,并尝试将其地址放入Integer[]类型的变量中,则编译器将不允许您的程序进行编译。
  2. 自动装箱和拆箱也会对性能产生可观的影响。也就是说,依赖自动装箱和拆箱的代码将比避免此类自动转换的代码慢。
  3. 另外,wrapper类型比原始类型使用更多的内存。在大多数现代计算机上,不仅您的代码必须拥有对对象的64位引用,而且每个对象还需要64位的开销来存储诸如对象的动态类型之类的内容。

2. Widening

Java也会自动扩展原始类型。具体来说,如果程序期望使用类型T2的原始类型(如double)并被赋予类型T1(如int)的变量,并且类型T2可以具有比T1更大的值范围,则该变量将隐式转换为类型T2。
例如,Java中的double范围大于ints。
int x = 20;
double y = x;
没问题。x被自动扩展为double。

如果要从较宽的类型过渡到较窄的类型,则必须手动强制转换。
例如:
double x = 20;
int y = (int) x;

二、不变性

不变数据类型是实例在实例化后不能以任何可观察的方式更改的数据类型。

例如,StringJava中的对象是不可变的。无论如何,如果您具有一个实例String,则可以在这个String上调用任何方法,但是它将完全保持不变。这意味着在String对象被联接(concatenated)的时候,不会修改原始的String,而是返回一个全新的String对象。

可变数据类型包括ArrayDeque和Planet这样的对象。我们可以从ArrayDeque中添加或删除items。同样,Planet的速度和位置可能会随时间变化。

任何non-private的数据都是可变的(因为外部方法可以访问到这些数据并对其进行更改),除非这些数据被声明为final。以final关键字声明的数据,在第一次被赋值之后,就不可以改变了。

final在Java中意思类似于“不可修改的”,可以在声明类、变量或者方法的时候使用。
如果一个类被声明为final,则这个类将不会有子类,也就是说这个类不能被别的类继承
如果一个方法被声明为final,则这个方法不能被重载也不能被重写,也就是第一次定义的时候设定了哪些参数,用的时候就必须传入对应的参数;
如果一个变量被声明为final,则这个变量在使用中不能被改变,且必须在声明的时候赋予初值,后续的使用中只能读取不能修改。

public class Date {
    public final int month;
    public final int day;
    public final int year;
    private boolean contrived = true;
    public Date(int m, int d, int y) {
        month = m; day = d; year = y;
    }
}
  • 不变数据类型的优点:
    • 防止错误并简化调试,因为属性永远不会改变
    • 您可以指望对象具有某种行为/特征
  • 缺点:
    • 您需要创建一个新对象以更改属性
  • 注意事项:
    • 将引用声明为final不会使引用指向的对象不可变!例如,考虑以下代码片段:
      public final ArrayDeque<String>() d = new ArrayDeque<String>();
      该d变量是final变量,永远不能重新赋值,也就是说d永远不能指向其他的deque,但是其指向的数组双端队列对象可以更改!ArrayDeques总是可变的,可以往里面插入或删除。
    • 使用Reflection API,甚至可以更改私有变量。不变性的概念假设我们没有使用该库的任何特殊功能。
    • 如果一个类的函数添加了final方法 那么子类继承这个类 该方法不可以被重写 但是如果修饰符为private,那么子类写一个同名的方法的话就不受影响 因为这不算重写 ,子类访问不到这个方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值