【JAVA学习笔记】16 ArrayList集合 、HashCode和equals判断对象相同、linklist、list接口

2018.4.18

 ---| Collection 集合的总接口

------| List 接口 有序 可重复

---------| ArrayList [重点]

ArrayList 是底层维护了一个Object类型的数组,这样的话这个ArrayList既可以保持任意类型
			的数据
				特征:
					当调用无参构造方法ArrayList,这里创建的底层Object类型的数组元素个数默认为10
					DEFAULT-CAPACITY 10
					
					查询快(有了下标基本确定找到元素),增删慢。
				开发中使用ArrayList比较多的情景:
					图书馆,人员管理

------| Set 接口 无序 不可重复

ArrayList特有方法:
 	//确定容量
 	ensureCapacity(int minCapacity); 不常用 返回值是boolean
 	判断当前ArrayList里面保存元素内容Object数组,元素个数是否大于minCapacity
 	
 	//截断底层维护的Object类型的数组,让数组的容量变成当前ArrayList的size值【有效元素个数】
 	trimToSize(); 不太常用  eg:扩容时右移一位10W->15W,只增加一个元素。
 	Size();//拿出有效元素个数
 
 	【查询快,增删慢的原理】
 		查询快:
 			ArrayList底层维护的是一个Object类型的数组,可以完全使用数组的下标机制来访问数据,
 			这种访问形式是非常快的。
 		增加慢:
 			是因为在添加数据的时候,有可能导致ArrayList底层的Object的元素个数不会用,那么会调用数组
 			的扩容方法grow,而扩容方法是创建了一个新的数组,数组的元素个数大约是老数组的1.5倍,这里会
 			利用一些方法,把老数组里面的元素完完整整的拷贝到新数组,这个拷贝过程很占时间和内存。
 		删除慢:
 			因为删除某一个元素,会导致数组中该元素之后的数据,做一个整体的左移,这里也是一个数组的拷贝
 			过程,整个过程非常
 	
面试题:
	1.如果调用了ArrayList的无参构造方法,那么请问底层维护的Object数组默认的元素个数是多少?
	如果是调用这个方法呢 new ArrayList(8);
	答:默认元素个数为10,另一个为8.
	
	2.ArrayList是一个可以自增长的空间,请问,增长的原理是什么?增长的长度是多少?
		ArrayList底层维护的是一个Object数组,默认元素为10,如果添加元素时,当前需求的元素空间
		超出了Object数组的元素个数,会调用底层的grow,进行数组元素的扩容和拷贝,扩容量是大约1.5倍
		扩容是:
			新元素个数 = 老元素个数 + (老元素个数 >> 1);
			newCapacity = oldCapacity + (oldCapacity >> 1);
			

        public class Demo1 {
        	public static void main(String[] args) {
        		ArrayList list = new ArrayList();
        	}
        }

HashCode 和 equals 判断对象是否相同。

contains, containsAll, equals方法

发现:
  	java语言中,默认判断两个对象是否相同的方式是,判断这两个对象的首地址是否相同,
  	在这里stu1和new Student(1,"梅西");是两个完全不同的对象,
  	
 问题:
 	但是Stu1和new Student(1,"梅西")里面保存的数据是一样的,也是符合业务逻辑
 	或者说生活逻辑的判断。
 	
 	让判断符合语法的前提下也符合生活逻辑。
 
 重写:
 	equals和hashCode方法。
 	
 	默认情况下:
 		hashCode方法在系统默认的情况下,是当前类对象在内存地址的十进制数
 		equals方法是两个对象相互比较的法则。

    class Student {
    	private int id;
    	private String name;
    	public Student() {}
    	
    	public Student(int id,String name) {
    		this.id = id;
    		this.name = name;
    	}
    	
    	public void setId(int id) {
    		this.id = id;
    	}
    	
    	public int getId() {
    		return id;
    	}
    	
    	public void setName(String name) {
    		this.name = name;
    	}
    	
    	public String getName() {
    		return name;
    	}

@Override
//描述当前类对象,当通过打印方法,打印该类对象的时候会自动调用。
public String toString() {
	return "[ID:"+id+"name:"+name+"]";
}
/**
 * equals和hashCode重写时一起重写。
 */
@Override
public boolean equals(Object obj) {
	//这里equals方法是Student类重写的方法,当集合调用contains,containsAll和equals方法的时候
	//都会来调用Student类里面的equals方法,进行比较,比较的的对象是Student对象。
	System.out.println("equals方法");
	
	//原本的比较方式是不符合生活逻辑的,只是判断两个对象的地址是否相同,不判断里面的内容是否一致
	//期望,判断的是对象里面的数据是否一致。
	
	//1.强制类型转换。
	Student stu = (Student) obj;
	System.out.println(this.name+"和"+stu.name+"进行比较");
	
	//this.name.equals(stu.name);这里的equals方法是调用的String类型的equals方法,和重写的equals没关系。
	return this.id == stu.id && this.name.equals(stu.name);
}
@Override
public int hashCode() {
	System.out.println("hashCode方法");
	//重写了equals方法,同时也要重写hashCode方法。
	//hashCode值要确定【唯一性】,只要满足你自己的逻辑就可以了。
	//这里认为Id是唯一的。
	return this.id;
	}
	
	
    }   
    public class Demo1 {
    	public static void main(String[] args) {
    		Collection c = new ArrayList();
    		
    		Student stu1 = new Student(1,"梅西");
    		Student stu2 = new Student(2,"C罗");
    		Student stu3 = new Student(3,"内马尔");
    		
    		c.add(stu1);
    		c.add(stu2);
    		c.add(stu3);
    		
    		boolean ret = c.contains(new Student(1,"伊布"));
    				
    		System.out.println(c);
    		
    		System.out.println("ret:"+ret);
    	}
    }

结果:
    equals方法
    伊布和梅西进行比较
    equals方法
    伊布和C罗进行比较
    equals方法
    伊布和内马尔进行比较
    [[ID:1name:梅西], [ID:2name:C罗], [ID:3name:内马尔]]
    ret:false

iterator迭代器

iterator();迭代器

循环,作用是循环遍历整个集合,

public class Demo2 {
	public static void main(String[] args) {
			Collection c = new ArrayList();
			
			c.add("栈桥");
			c.add("八大关");
			c.add("情人坝");
			c.add("中山公园");
			
			//第一种遍历方式:将集合转换成数组进行遍历
		/*Object[] array = c.toArray();
			
			for (int i = 0; i < array.length; i++) {
				System.out.println(array[i]);
			}
		*/
			/*
			 LOW 
			 会导致内存资源的浪费,会拷贝一份完整的集合数据,如果集合数据过大,甚至于会超过内存的最大致
			 
			 Iterator 迭代器的方法
			 boolean hasNext();判断当前迭代器是否有下一个元素
			 Object next();获取当前迭代器指向的元素,并且获取之后,指向下一个元素。  object为迭代器对象。
			 void remove();删除当前迭代器通过的next获取到的对象。
			 	[要求]:
			 	在通过迭代器调用remove方法的时候,之前必须调用过next()方法。
			 		否则报异常:		java.lang.IllegalStateException
			*/
			
			Iterator it = c.iterator();//返回当前集合的一个迭代器
		/*
			System.out.println("当前元素中有没有下一个元素:"+it.hasNext());
			System.out.println("当前迭代器指向的元素:"+it.next());
			System.out.println("当前迭代器指向的元素:"+it.next());
			System.out.println("调用了删除的方法");
			
			it.remove();
			*/
			//利用迭代器,借助于hasNext和next方法,完成对整个集合的遍历。
			
			while(it.hasNext()) {
				System.out.println("迭代器操作:"+it.next());
				//it.remove();这里可以调用remove方法,用来清空集合。
				
				//it.next();(获取当前元素,并指向下一个元素)
				
			}
			System.out.println(c);
	}
}
结果:
    迭代器操作:栈桥
    迭代器操作:八大关
    迭代器操作:情人坝
    迭代器操作:中山公园
    [栈桥, 八大关, 情人坝, 中山公园]

LinkedList

LinkedList 底层维护的是一个链表。	
	 		特征:
	 			增删快,查找慢。

LinkedList特有方法:

addFirst(Object o);
addLast(Object o)
getFirst();
getLast();

removeFist();
removeLast();

*/
public class Demo1 {
	public static void main(String[] args) {
		LinkedList list = new LinkedList();
		
		
	}
}

List接口

List接口中【特有的方法】:

  • 添加:

  • add(index,Object o);在指定位置上放入元素
    addAll(int index, Collection c);在指定位置上添加一个集合
  • 获取:

  • object get(int index);获取指定下标的元素 obejct---list
    int indexOf(Object o);获取某个元素的下表位置
    int lastIndex(Object o);找出指定元素最后一次出现在集合中的位置。(在元素相同时)
    List sublist(int fromIndex,int toIndex);获取一个子List集合
  • 修改:

  • set(int index, Object o);设置指定下标上的元素
    get(int in)
  • 迭代:

    扫描二维码关注公众号,回复: 1085437 查看本文章
  • ListItrator();
    
    
      public class Demo1 {
      	public static void main(String[] args) {
      		List list = new ArrayList();
      		
    	list.add("鱼辣子");
    	list.add("沙蟹汁");
    	list.add("鲱鱼罐头");
    	list.add("活蛆奶酪");
    	
    	System.out.println(list);
    	
    	list.add(1,"变蛋");
    	System.out.println(list);
    	
    	List list2 = new ArrayList();
    	list2.add("麻辣小龙虾");
    	list2.add("湖南红烧肉");
    	list2.add("麻辣小龙虾");
    	
    	list.addAll(2,list2);
    	System.out.println(list);
    	
    	System.out.println(list.get(5));
    	
    	System.out.println(list.indexOf("沙蟹汁"));
    	
    	System.out.println(list.lastIndexOf("麻辣小龙虾"));
    	
    	//subList(int fromIndex,int toIndex);

在JAVA中所有用到区间范围的操作 都是要头不要尾。

List subList = list.subList(0, 5);
	System.out.println(subList);
	
	list.set(list.indexOf("鲱鱼罐头"),"长沙臭豆腐");
	System.out.println(list);
	
结果:
    [鱼辣子, 沙蟹汁, 鲱鱼罐头, 活蛆奶酪]
    [鱼辣子, 变蛋, 沙蟹汁, 鲱鱼罐头, 活蛆奶酪]
    [鱼辣子, 变蛋, 麻辣小龙虾, 湖南红烧肉, 麻辣小龙虾, 沙蟹汁, 鲱鱼罐头, 活蛆奶酪]
    沙蟹汁
    5
    4
    [鱼辣子, 变蛋, 麻辣小龙虾, 湖南红烧肉, 麻辣小龙虾]
    [鱼辣子, 变蛋, 麻辣小龙虾, 湖南红烧肉, 麻辣小龙虾, 沙蟹汁, 长沙臭豆腐, 活蛆奶酪]

猜你喜欢

转载自blog.csdn.net/u013182992/article/details/80453197