15、泛型。
泛型是Java SE 1.5之后的特性, 《Java 核心技术》中对泛型的定义是:
“泛型” 意味着编写的代码可以被不同类型的对象所重用。
“泛型”,顾名思义,“泛指的类型”。我们提供了泛指的概念,但具体执行的时候却可以有具体的规则
来约束,比如我们用的非常多的ArrayList就是个泛型类,ArrayList作为集合可以存放各种元素,如
Integer, String,自定义的各种类型等,但在我们使用的时候通过具体的规则来约束,如我们可以约
束集合中只存放Integer类型的元素,如
List<Integer> iniData = new ArrayList<>()
使用泛型的好处?
以集合来举例,使用泛型的好处是我们不必因为添加元素类型的不同而定义不同类型的集合,如整
型集合类,浮点型集合类,字符串集合类,我们可以定义一个集合来存放整型、浮点型,字符串型
数据,而这并不是最重要的,因为我们只要把底层存储设置了Object即可,添加的数据全部都可向
上转型为Object。 更重要的是我们可以通过规则按照自己的想法控制存储的数据类型。
16、Java创建对象有几种方式?
new关键字
ArrayList<Object> objects = new ArrayList<>();
通过反射机制
Student classStudent = (Student) Class.forName("com.dimple.NewObject.Student").newInstance();//需要无参构造器,使用Class的
classStudent.sayHello();
clone机制
Student clone = (Student) constructorStudent.clone();
clone.sayHello();
序列化机制
public class Student implements Cloneable
{
//实现 Cloneable 接口
private String Name; //学生名字
private int age; //学生年龄
public Student(String name,int age)
{ //构造方法
this.Name=name;
this.age=age;
}
public Student()
{
this.Name="name";
this.age=0;
}
public String toString()
{
return"学生名字:"+Name+",年龄:"+age;
}
public static void main(String[] args)throws Exception
{
System.out.println("---------使用 new 关键字创建对象---------");
//使用new关键字创建对象
Student student1=new Student("小刘",22);
System.out.println(student1);
System.out.println("-----------调用 java.lang.Class 的 newInstance() 方法创建对象-----------");
//调用 java.lang.Class 的 newInstance() 方法创建对象
Class cl=Class.forName("Student");
Student student2=(Student)cl.newInstance();
System.out.println(student2);
System.out.println("-------------------调用对象的 clone() 方法创建对象----------");
//调用对象的 clone() 方法创建对象
Student student3=(Student)student2.clone();
System.out.println(student3);
}
}
17、有没有可能两个不相等的对象有相同的hashcode?
有可能.在产生hash冲突时,两个不相等的对象就会有相同的 hashcode 值.当hash冲突产生时,一般
有以下几种方式来处理:
拉链法:每个哈希表节点都有一个next指针,多个哈希表节点可以用next指针构成一个单向链表,被分配到同一个索引上的多个节点可以用这个单向链表进行存储.
开放定址法:一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总 能找到,并将记录存入
再哈希:又叫双哈希法,有多个不同的Hash函数.当发生冲突时,使用第二个,第三个….等哈希函数 计算地址,直到无冲突.
System.out.println("轷龚".hashCode());
System.out.println("轸齻".hashCode());
18、深拷贝和浅拷贝的区别是什么?
浅拷贝:对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,并不会影响另一个对象拷贝得到的数据。
对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。
int[] ints = {1,2,3,4,5};
int[] newInts=ints;
System.out.println(ints);//[I@69d9c55
System.out.println(newInts);//[I@69d9c55
for (int anInt : ints) {
System.out.print(anInt+" ");//1,2,3,,4,5
}
System.out.println();
for (int anInt : newInts) {
System.out.print(anInt+" ");//1,2,3,4,5
}
ints[2]=66;
System.out.println(ints);//[I@69d9c55
System.out.println(newInts);//[I@69d9c55
for (int anInt : ints) {
System.out.print(anInt+" ");//1 2 66 4 5
}
System.out.println();
for (int anInt : newInts) {
System.out.print(anInt+" ");//1 2 66 4 5
}
浅拷贝的问题
1.如果类的成员变量包含或者全部是基本数据类型,拷贝时直接传递值,那么没有任何问题。
2.如果类的成员变量引用类型的数据,如上述中的Age对象,那么对这个类的对象使用时就要注意了,浅拷贝只会拷贝引用本身,而不会拷贝引用所指向的对象,这样就会导致多个对象同时持有指向某个对象的指引用,容易引发数据修改的混乱。
@Test
public void test01() {
String str1="hello";
String str2="hello";
String str3=new String("hello");
System.out.println(str1==str2);//true
System.out.println(str3==str2);//false
System.out.println(str3==str1);//false
}
jdk1.7之后,上述的str1和str2都是会在创建hello时,在String池中判断是否存在hello,存在,则将str1指向hello,不存在则在池中创建一个hello,将str1指向hello。
而str3在创建时,是使用new关键字创建对象,无论如何都会创建一个对象。所以输出结果如上所示。
深拷贝:
@Test
public void test03(){
String str1="hello";
String str2="hel";
String str3=new String("hello");
String str4=str1;
String str5=new String(str1);
str1="hello hello";
System.out.println(str1);//hello hello
System.out.println(str2);//hel
System.out.println(str3);//hello
System.out.println(str4);//hello
System.out.println(str5);//hello
}
String类型的拷贝是深拷贝。复制的对象不会随着被复制的对象的改变而改变。
public class YuelyLog implements Serializable,Cloneable {
private Attachment attachment;
private String name;
private String date;
@Override
protected YuelyLog clone() throws CloneNotSupportedException {
return (YuelyLog)super.clone();
}
public Attachment getAttachment() {
return attachment;
}
public void setAttachment(Attachment attachment) {
this.attachment = attachment;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
/**
* 使用序列化技术实现深拷贝
* @return
*/
public YuelyLog deepClone() throws IOException,ClassNotFoundException{
//将对象写入流中
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(this);
//从流中取出
ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
return (YuelyLog)objectInputStream.readObject();
}
}