本篇将介绍数组的一些特殊的特性,跟C语言的数组相比,java赋予了数组新的面向对象的性质,比如数组即对象,数组的序列化,数组的拷贝,这也为数组的拷贝提供了新的优雅的方案。
package com.zd.test.java.ds;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class ArrayTest {
public static void main(String[] args) throws Exception {
// 1.数组和泛型
int[] data = new int[] { 1, 2, 3 };
/*
List<int[]> asList = Arrays.asList(data); for (int is[] : asList) {
System.out.println(is); }
*/
asList(data);
System.out.println("-----------------------");
asList(new String[] { "A", "B", "C" });
System.out.println("-----------------------");
test("zhangsan", data);
System.out.println("-----------------------");
// 此时new char[]{'A','B','C'}为一个char[]数组对象,可以看一下类型
char[] cdata = new char[] { 'A', 'B', 'C' };
asList(cdata);
System.out.println("类名:" + cdata.getClass().getCanonicalName());
System.out.println("父类:"
+ cdata.getClass().getSuperclass().getCanonicalName());
Class<?>[] interfaces = cdata.getClass().getInterfaces();
System.out.println("实现的接口:");
for (Class<?> class1 : interfaces) {
System.out.println(class1.getCanonicalName());
}
/**
* 类名:char[] 父类:java.lang.Object 实现的接口: java.lang.Cloneable
* java.io.Serializable
* 可以看出其父类是java.lang.Object,实现了Cloneable和Serializable接口,数组是可复制和可序列化的。
*/
// 2.数组的拷贝
Person[] ps = new Person[] { new Person("1", 1), new Person("2", 2) };
Person[] persons = ps.clone();
persons[0].name = "3";// 改变拷贝对象的属性值
// 结果是原来对象的属性值也被改变了,数组的拷贝是浅拷贝,它拷贝的元素的地址,如果是对象元素,只拷贝对象地址,是浅拷贝
System.out.println("before:" + ps[0].name);
// 深拷贝的例子,Man对象,需要实现Cloneable接口
Man m = new Man("1", 1);
Man m1 = (Man) m.clone();
m1.name = "3";// 改变拷贝对象的属性值
System.out.println("before : " + m.name); // 对象的每一个值都改变了
// 对象的序列化
Dog dog = new Dog("旺旺", 2);
Dog dog2 = dog.deepCopy();
System.out.println("dog : " + dog + ", name : " + dog.name + ", age : "
+ dog.age);
System.out.println("dog2 : " + dog2 + ", name : " + dog2.name
+ ", age : " + dog2.age);
// dog : com.zd.test.java.ds.ArrayTest$Dog@29ba92bb, name : 旺旺, age : 2
// dog2 : com.zd.test.java.ds.ArrayTest$Dog@343abc87, name : 旺旺, age : 2
// 从上面的实例化的例子可以看出来,其实可以利用序列化来实现对象的深拷贝
Cat cat = new Cat("喵喵", 1);
Cat cat2 = cat.clone();
System.out.println("cat : " + cat + ", name : " + cat.name + ", age : "
+ cat.age);
System.out.println("cat2 : " + cat2 + ", name : " + cat2.name
+ ", age : " + cat2.age);
///至此数组的性质分析完毕
//下面说一下序列化的一些知识
}
// 普通类
static class Person {
String name;
Integer age;
public Person(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
}
// 测试深克隆实体类
static class Man implements Cloneable {
String name;
Integer age;
public Man(String name, Integer age) {
this.name = name;
this.age = age;
}
public Object clone() {
Man man = new Man(name, age);
return man;
}
}
// 测试序列化实体类
static class Dog implements Serializable {
private static final long serialVersionUID = -7836461280716041801L;
String name;
Integer age;
public Dog(String name, Integer age) {
this.name = name;
this.age = age;
}
// 深拷贝
public Dog deepCopy() throws IOException, ClassNotFoundException {
// 先写进流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(
outputStream);
objectOutputStream.writeObject(this);
// 再写出流
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
outputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(
byteArrayInputStream);
Dog dog = (Dog) objectInputStream.readObject();
objectInputStream.close();
objectOutputStream.close();
return dog;
}
}
// 使用序列化来实现深拷贝
static class Cat implements Serializable, Cloneable {
private static final long serialVersionUID = 3530119431127324235L;
String name;
Integer age;
public Cat(String name, Integer age) {
this.name = name;
this.age = age;
}
// 深拷贝
public Cat clone() {
Cat cat = null;
cat = deepCopy(this);
return cat;
}
}
public static final void test(String name, int... params) {
System.out.println(name);
for (int i : params) {
System.out.println(i);
}
}
// 简单类型
public static void asList(int... a) {
for (int t : a) {
System.out.println(t);
}
}
// 普通对象
public static void asList(String... a) {
for (String t : a) {
System.out.println(t);
}
}
// Object对象,与泛型一致,是二维数组,原因为a其实是一个数组其实就是一个对象,
// 看作为一个对象,然后java可变参数再次封装这个数组,成为二维数组
public static void asList(Object... a) {
for (Object t : a) {
System.out.println(t.getClass().getName());
}
}
/*
* //泛型 public static <T> void asList(T... ts){ for (T t : ts) {
* System.out.println(t); } }
*/
@SuppressWarnings("unchecked")
public static <T extends Serializable & Cloneable> T deepCopy(T t) {
T newInstance = null;
// 先写进流
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(
outputStream);
objectOutputStream.writeObject(t);
// 再写出流
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
outputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(
byteArrayInputStream);
newInstance = (T) objectInputStream.readObject();
objectInputStream.close();
objectOutputStream.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return newInstance;
}
}
案例输出结果如下:
1
2
3
-----------------------
A
B
C
-----------------------
zhangsan
1
2
3
-----------------------
[C
类名:char[]
父类:java.lang.Object
实现的接口:
java.lang.Cloneable
java.io.Serializable
before:3
before : 1
dog : com.zd.test.java.ds.ArrayTest$Dog@4ef53d61, name : 旺旺, age : 2
dog2 : com.zd.test.java.ds.ArrayTest$Dog@3fd23632, name : 旺旺, age : 2
cat : com.zd.test.java.ds.ArrayTest$Cat@770fba26, name : 喵喵, age : 1
cat2 : com.zd.test.java.ds.ArrayTest$Cat@2886f716, name : 喵喵, age : 1
总结如下:
1.泛型和可变参数相遇,我们传过去的数组被包装成了二维数组,因为泛型在java以前的版本中是用Object来代替的,而恰巧的是数组在java中也是一个对象,它是java.lang.Object的子类,可以尝试重载一下,上面的例子我们已经有示范。
2.数组实现了Cloneable和Serializable接口,即数组是可复制和可序列化的。
3.数组的拷贝是浅拷贝,即只拷贝数组中元素的地址,即只拷贝对象的引用。
4.结合Cloneable和Serializable两个接口,可以优雅的实现对象的拷贝和序列化,关于二者的结合使用,上面的范例中已经有解释。之后,我会针对序列化和拷贝再做深入的说明。
个人见解,欢迎指教批评。