深入学习java源码之Arrays.asList()与Arrays.stream()
RandomAccess标记接口
标记接口,Marker interface,它们是一类没有定义任何接口方法的接口,表现为一个空接口
没有接口方法意味着实现该接口的类无需实现任何接口方法,仅仅作为一种标记,以供其他方法判断
作用就是当某个类实现这个接口后即拥有了这个接口的功能,Java 虚拟机在运行时会识别到它
标记接口是Java的语言特性
在计算机科学中,随机访问(RandomAccess)是从大量的可寻址元素的数据中访问任何元素大致和访问其他元素一样简洁有效,不管多少元素在这个集合中。与随机访问相反的是顺序访问(SequenceAccess)
RandomAccess 就是一个标记接口,用于标明实现该接口的List支持快速随机访问,主要目的是使算法能够在随机和顺序访问的List中性能更加高效(在Collections二分查找时)。
JDK中说的很清楚,在对List特别是Huge size的List的遍历算法中,要尽量来判断是属于RandomAccess(如:ArrayList)还是SequenceAccess(如:LinkedList)
RandomAccess是一个空接口,而空接口的作用一般是起到一个标识的作用。
通俗点讲,就是判断一个list是否实现了RandomAcess接口,如果实现了,采用简单的for循环进行访问速度比较快。
如果未实现RandomAcess接口,则采用iterator循环访问速度比较快。
判断使用instanceof
Collections的binarySearch方法:
public static
在进行二分查找时,首先判断list是否实现了RandomAccess,然后选择执行最优算法。
如果集合类是RandomAccess的实现,则尽量用for(int i = 0; i
迭代器来进行迭代。
Serialization序列化
序列化 (Serialization)将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
三种情况:
1. 将对象存储再硬盘上。
2. 将对象通过网络传输。
3. 通过RMI远程调用等方式传输对象的时候。
在这三种情况下,是需要进行序列化然后传输的。
对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过程,只要这个类实现了Serilizable接口,这个类的所有属性和方法都会自动序列化。
然而在实际开发过程中,我们常常会遇到这样的问题,这个类的有些属性需要序列化,而其他属性不需要被序列化,打个比方,如果一个用户有一些敏感信息(如密码,银行卡号等),为了安全起见,不希望在网络操作(主要涉及到序列化操作,本地序列化缓存也适用)中被传输,这些信息对应的变量就可以加上transient关键字。换句话说,这个字段的生命周期仅存于调用者的内存中而不会写到磁盘里持久化。
总之,java 的transient关键字为我们提供了便利,你只需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;/*** @description 使用transient关键字不序列化某个变量* 注意读取的时候,读取数据的顺序一定要和存放数据的顺序保持一致* * @author Alexia* @date 2013-10-15*/
public class TransientTest {public static void main(String[] args) {User user = new User();user.setUsername("Alexia");user.setPasswd("123456");System.out.println("read before Serializable: ");System.out.println("username: " + user.getUsername());System.err.println("password: " + user.getPasswd());try {ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("C:/user.txt"));os.writeObject(user); // 将User对象写进文件os.flush();os.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}try {ObjectInputStream is = new ObjectInputStream(new FileInputStream("C:/user.txt"));user = (User) is.readObject(); // 从流中读取User的数据is.close();System.out.println("\nread after Serializable: ");System.out.println("username: " + user.getUsername());System.err.println("password: " + user.getPasswd());} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}}
}class User implements Serializable {private static final long serialVersiOnUID= 8294180014912103005L; private String username;private transient String passwd;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPasswd() {return passwd;}public void setPasswd(String passwd) {this.passwd = passwd;}}
输出为:
read before Serializable:
username: Alexia
password: 123456read after Serializable:
username: Alexia
password: null
密码字段为null,说明反序列化时根本没有从文件中获取到信息。
transient使用小结
1)一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。
2)transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。
3)被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。
第三点可能有些人很迷惑,因为发现在User类中的username字段前加上static关键字后,程序运行结果依然不变,即static类型的username也读出来为“Alexia”了,这不与第三点说的矛盾吗?实际上是这样的:第三点确实没错(一个静态变量不管是否被transient修饰,均不能被序列化),反序列化后类中static型变量username的值为当前JVM中对应static变量的值,这个值是JVM中的不是反序列化得出的
我们知道在Java中,对象的序列化可以通过实现两种接口来实现,若实现的是Serializable接口,则所有的序列化将会自动进行,若实现的是Externalizable接口,则没有任何东西可以自动序列化,需要在writeExternal方法中进行手工指定所要序列化的变量,这与是否被transient修饰无关。因此第二个例子输出的是变量content初始化的内容,而不是null。
public class ExternalizableTest implements Externalizable {private transient String cOntent= "是的,我将会被序列化,不管我是否被transient关键字修饰";@Overridepublic void writeExternal(ObjectOutput out) throws IOException {out.writeObject(content);}@Overridepublic void readExternal(ObjectInput in) throws IOException,ClassNotFoundException {cOntent= (String) in.readObject();}public static void main(String[] args) throws Exception {ExternalizableTest et = new ExternalizableTest();ObjectOutput out = new ObjectOutputStream(new FileOutputStream(new File("test")));out.writeObject(et);ObjectInput in = new ObjectInputStream(new FileInputStream(new File("test")));et = (ExternalizableTest) in.readObject();System.out.println(et.content);out.close();in.close();}
}
Modifier and Type | Method and Description |
---|---|
static | asList(T... a) 返回由指定数组支持的固定大小的列表。 |
static boolean | deepEquals(Object[] a1, Object[] a2) 如果两个指定的数组彼此 深度相等 ,则返回 true 。 |
static int | deepHashCode(Object[] a) 根据指定数组的“深度内容”返回哈希码。 |
static String | deepToString(Object[] a) 返回指定数组的“深度内容”的字符串表示形式。 |
static boolean | equals(boolean[] a, boolean[] a2) 如果两个指定的布尔数组彼此 相等 ,则返回 true 。 |
static boolean | equals(byte[] a, byte[] a2) 如果两个指定的字节数组彼此 相等 ,则返回 true 。 |
static boolean | equals(char[] a, char[] a2) 如果两个指定的字符数组彼此 相等 ,则返回 true 。 |
static boolean | equals(double[] a, double[] a2) 如果两个指定的双精度数组彼此 相等 ,则返回 true 。 |
static boolean | equals(float[] a, float[] a2) 如果两个指定的浮动数组彼此 相等 ,则返回 true 。 |
static boolean | equals(int[] a, int[] a2) 如果两个指定的int数组彼此 相等 ,则返回 true 。 |
static boolean | equals(long[] a, long[] a2) 如果两个指定的longs数组彼此 相等 ,则返回 true 。 |
static boolean | equals(Object[] a, Object[] a2) 如果两个指定的对象数组彼此 相等 ,则返回 true 。 |
static boolean | equals(short[] a, short[] a2) 如果两个指定的短裤阵列彼此 相等 ,则返回 true 。 |
static int | hashCode(boolean[] a) 根据指定数组的内容返回哈希码。 |
static int | hashCode(byte[] a) 根据指定数组的内容返回哈希码。 |
static int | hashCode(char[] a) 根据指定数组的内容返回哈希码。 |
static int | hashCode(double[] a) 根据指定数组的内容返回哈希码。 |
static int | hashCode(float[] a) 根据指定数组的内容返回哈希码。 |
static int | hashCode(int[] a) 根据指定数组的内容返回哈希码。 |
static int | hashCode(long[] a) 根据指定数组的内容返回哈希码。 |
static int | hashCode(Object[] a) 根据指定数组的内容返回哈希码。 |
static int | hashCode(short[] a) 根据指定数组的内容返回哈希码。 |
static void | parallelSetAll(double[] array, IntToDoubleFunction generator) 使用提供的生成函数来并行设置指定数组的所有元素来计算每个元素。 |
static void | parallelSetAll(int[] array, IntUnaryOperator generator) 使用提供的生成函数来并行设置指定数组的所有元素来计算每个元素。 |
static void | parallelSetAll(long[] array, IntToLongFunction generator) 使用提供的生成函数来并行设置指定数组的所有元素来计算每个元素。 |
static | parallelSetAll(T[] array, IntFunction extends T> generator) 使用提供的生成函数来并行设置指定数组的所有元素来计算每个元素。 |
static void | setAll(double[] array, IntToDoubleFunction generator) 使用提供的生成函数来计算每个元素,设置指定数组的所有元素。 |
static void | setAll(int[] array, IntUnaryOperator generator) 使用提供的生成函数来计算每个元素,设置指定数组的所有元素。 |
static void | setAll(long[] array, IntToLongFunction generator) 使用提供的生成函数来计算每个元素,设置指定数组的所有元素。 |
static | setAll(T[] array, IntFunction extends T> generator) 使用提供的生成函数来计算每个元素,设置指定数组的所有元素。 |
static Spliterator.OfDouble | spliterator(double[] array) 返回 |
static Spliterator.OfDouble | spliterator(double[] array, int startInclusive, int endExclusive) 返回 |
static Spliterator.OfInt | spliterator(int[] array) 返回 |
static Spliterator.OfInt | spliterator(int[] array, int startInclusive, int endExclusive) 返回 |
static Spliterator.OfLong | spliterator(long[] array) 返回 |
static Spliterator.OfLong | spliterator(long[] array, int startInclusive, int endExclusive) 返回 |
static | spliterator(T[] array) 返回 |
static | spliterator(T[] array, int startInclusive, int endExclusive) 返回 |
static DoubleStream | stream(double[] array) 返回顺序 |
static DoubleStream | stream(double[] array, int startInclusive, int endExclusive) 返回顺序 |
static IntStream | stream(int[] array) 返回顺序 |
static IntStream | stream(int[] array, int startInclusive, int endExclusive) 返回顺序 |
static LongStream | stream(long[] array) 返回顺序 |
static LongStream | stream(long[] array, int startInclusive, int endExclusive) 返回顺序 |
static | stream(T[] array) 返回顺序 |
static | stream(T[] array, int startInclusive, int endExclusive) 返回顺序 |
static String | toString(boolean[] a) 返回指定数组的内容的字符串表示形式。 |
static String | toString(byte[] a) 返回指定数组的内容的字符串表示形式。 |
static String | toString(char[] a) 返回指定数组的内容的字符串表示形式。 |
static String | toString(double[] a) 返回指定数组的内容的字符串表示形式。 |
static String | toString(float[] a) 返回指定数组的内容的字符串表示形式。 |
static String | toString(int[] a) 返回指定数组的内容的字符串表示形式。 |
static String | toString(long[] a) 返回指定数组的内容的字符串表示形式。 |
static String | toString(Object[] a) 返回指定数组的内容的字符串表示形式。 |
static String | toString(short[] a) 返回指定数组的内容的字符串表示形式。 |
java源码
package java.util;import java.lang.reflect.Array;
import java.util.concurrent.ForkJoinPool;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.DoubleBinaryOperator;
import java.util.function.IntBinaryOperator;
import java.util.function.IntFunction;
import java.util.function.IntToDoubleFunction;
import java.util.function.IntToLongFunction;
import java.util.function.IntUnaryOperator;
import java.util.function.LongBinaryOperator;
import java.util.function.UnaryOperator;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;public class Arrays {private static final int MIN_ARRAY_SORT_GRAN = 1 <<13;// Suppresses default constructor, ensuring non-instantiability.private Arrays() {}static final class NaturalOrder implements Comparator {@SuppressWarnings("unchecked")public int compare(Object first, Object second) {return ((Comparable)first).compareTo(second);}static final NaturalOrder INSTANCE = new NaturalOrder();}private static void rangeCheck(int arrayLength, int fromIndex, int toIndex) {if (fromIndex > toIndex) {throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");}if (fromIndex <0) {throw new ArrayIndexOutOfBoundsException(fromIndex);}if (toIndex > arrayLength) {throw new ArrayIndexOutOfBoundsException(toIndex);}}@SafeVarargs@SuppressWarnings("varargs")public static
}
package java.util;public interface RandomAccess {
}