一、自动转换
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。
- 自动装箱和拆箱时需要牢记以下几点
- 数组永远不会autobox或auto-unbox,例如,如果您有一个整数数组int[] x,并尝试将其地址放入Integer[]类型的变量中,则编译器将不允许您的程序进行编译。
- 自动装箱和拆箱也会对性能产生可观的影响。也就是说,依赖自动装箱和拆箱的代码将比避免此类自动转换的代码慢。
- 另外,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,那么子类写一个同名的方法的话就不受影响 因为这不算重写 ,子类访问不到这个方法。
- 将引用声明为final不会使引用指向的对象不可变!例如,考虑以下代码片段: