JavaSE学习笔记 Day19

JavaSE学习笔记 Day19

个人整理非商业用途,欢迎探讨与指正!!
« 上一篇


文章目录

  • JavaSE学习笔记 Day19
    • ···
        • 16.3.9HashSet去重原理
        • 16.3.10LinkedHashSet
        • 16.3.11Set集合的遍历
        • 16.3.12TreeSet
        • 16.3.13Comparable接口
        • 16.3.14Collections工具类
      • 16.4双列集合
        • 16.4.1Map接口
      • 16.5常见的双列集合实现类
        • 16.5.1HashMap
        • 16.5.2HashMap实际应用
        • 16.5.3HashMap练习
        • 16.5.4Hashtable
      • 16.6泛型的使用
        • 16.6.1泛型类
        • 16.6.2泛型接口
        • 16.6.3泛型方法
        • 16.6.4泛型上下边界


···

16.3.9HashSet去重原理

Set集合是如何判断数据不能重复?
 先判断hashCode再判断equals方法
首先比较两个对象的hashCode值,若值不一样则是两个不同的对象;若hashCode值一样,那么就会去比较equals方法,若equals方法false,则表示两个不同的对象,在Set集合中就不算重复了
 若只重写一个,可能导致数据添加的准确
 只重写hashCode,没有重写equals,对象的内容相同了,hashCode就一样了,但没有重写equals数据也添加了
 只重写了equals,若hashCode不一致,则直接判断为两个不同的对象

package com.qf.test01;

import java.util.HashSet;
import java.util.Set;

public class Demo11 {
//	首先比较两个对象的hashCode值,若值不一样则是两个不同的对象;
//	若hashCode值一样,那么就会去比较equals方法,
//	若equals方法false,则表示两个不同的对象,在Set集合中就不算重复了
	public static void main(String[] args) {
		Set<Dog> set = new HashSet<>();
//		1.Dog类中没有重写hashCode和equals方法时,
//		两个对象的内容完全一样但是没有重写,被判断为两个对象,
//		能看见重复的数据添加到Set中
		/*set.add(new Dog(1,"大黄",2,"玩"));
		set.add(new Dog(1,"大黄",2,"玩"));
		
		System.out.println(set);*/
//		2.Dog类中重写hashCode和equals方法
//		重写时:hashCode返回一个固定的 equals返回true
//		添加两个内容相同的对象,被判断为同一个对象
		/*set.add(new Dog(1,"大黄",2,"玩"));
		set.add(new Dog(1,"大黄",2,"玩"));
		set.add(new Dog(1,"大黄",2,"玩"));
		
		System.out.println(set);*/
//		3.Dog类中重写hashCode和equals方法
//		重写时:hashCode返回一个固定的 equals返回false
		/*set.add(new Dog(1,"大黄",2,"玩"));
		set.add(new Dog(1,"大黄",2,"玩"));
		set.add(new Dog(1,"大黄",2,"玩"));
		set.add(new Dog(1,"大黄",2,"玩"));
		
		System.out.println(set);
		System.out.println("-----------------");*/
//		因为编码比较极端,hashCode是0 equals是true,
//		意味着Dog的所有对象,都一样
		/*set.add(new Dog());
		set.add(new Dog(2,"123",3,"嘿嘿"));
		set.add(new Dog());
		System.out.println(set);*/
		
//		4.只重写了equals方法,hashCode是第一被调用的方法
		set.add(new Dog(1,"大黄",2,"玩"));
		set.add(new Dog(1,"大黄",2,"玩"));
		set.add(new Dog(1,"大黄",2,"玩"));
		System.out.println(set);
	}
}

// 伪代码
class Dog{
	@Override
	public int hashCode() {
		System.out.println("hashCode被调用");
		return 0;
	}
	@Override
	public boolean equals(Object obj) {
		System.out.println("equals被调用");
		return true;
	}
}
16.3.10LinkedHashSet

是HashSet的子类
特点:
 有序,无下标,不重复,去重复原理和父类一样

public class Demo12 {

	public static void main(String[] args) {
		LinkedHashSet<String> set = new LinkedHashSet<>();
		set.add("张三");
		set.add("李四");
		set.add("王五");
		set.add("赵六");
		set.add("赵六");
//		添加和存放顺序是一样的Set集合
		System.out.println(set);
	}
	
}
16.3.11Set集合的遍历

1.迭代器
2.foreach循环

public class Demo13 {

	public static void main(String[] args) {
		HashSet<String> set = new HashSet<>();
		set.add("zs");
		set.add("ls");
		set.add("ww");
		set.add("zl");
		
//		使用迭代器 jdk1.5之前
		Iterator<String> it = set.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
		System.out.println("-------------------------");
//		foreach jdk1.5之后
		for (String string : set) {
			System.out.println(string);
		}
	}
}
16.3.12TreeSet

底层使用红黑树实现的
特点:
 无序(有字典顺序),无下标,不可重复
使用TreeSet存储的对象必须实现Comparable接口
Comparable接口:用于定义排序方法和去重
 接口中方法:compareTo方法
  返回值是大于0的数升序的,返回值是小于0的数降序的,若等于0被认为是同一个对象

public class Demo14 {

	public static void main(String[] args) {
		TreeSet<Integer> set = new TreeSet<>();
		
		set.add(1);
		set.add(8);
		set.add(20);
		set.add(3);
		set.add(7);
		set.add(5);
//		重复的值是不能添加进入TreeSet集合
		set.add(5);
//		不能添加空值
//		set.add(null);
//		排序之后进行存放(字典顺序)
		System.out.println(set);
	}
}
16.3.13Comparable接口

可以添加到TreeSet集合中元素,必须实现Comparable接口
TreeSet集合在去重时,会调用compareTo方法
作用:
 1.排序:大于0升序(向当前位置的元素之后添加新的元素),小于0降序(向当前位置元素之前添加新的元素)
 2.去重:等于0时,当前位置的元素和新的元素比较的没结果,将无法加入到当前集合中

public class Pig implements Comparable<Pig>{
	
	String name;
	int age;
	public Pig(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public Pig() {
		super();
		// TODO Auto-generated constructor stub
	}
	
	@Override
	public String toString() {
		return "Pig [name=" + name + ", age=" + age + "]";
	}
	
	//	自定义去重规则
	@Override
	public int compareTo(Pig o) {
		System.out.println("compareTo()");
		return -1;
	}
}
public class Demo15 {

	public static void main(String[] args) {
		TreeSet<Pig> set = new TreeSet<>();
//		1.添加的对象没有实现Comparable接口,可以添加但是无法运行成功
		/*set.add(new Pig("佩奇",10));
		set.add(new Pig("乔治",9));
		
		System.out.println(set);*/
//		2.Pig实现了Comparable接口
//		compareTo方法返回值为0,当前方法是比较时才会调用
//		结果为0时,认定为重复数据
//		返回值为1(大于0) 是新数据比当前数据位置要靠后
//		返回值为-1(小于0) 是新数据比当前数据位置靠前
//		compareTo决定了TreeSet集合中数据存放的位置
		set.add(new Pig("佩奇",10));
		System.out.println("---");
		set.add(new Pig("乔治",9));//和已经存在的第一个元素进行了比较
		System.out.println("---");
		set.add(new Pig("乔治",10));//和之前的两个数据进行比较
		System.out.println("---");
		
		System.out.println(set);
	}
}
public class Animal implements Comparable<Animal>{
	
	String name;
	int age;
	
	@Override
	public String toString() {
		return "Animal [name=" + name + ", age=" + age + "]";
	}

	public Animal(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public Animal() {
		super();
		// TODO Auto-generated constructor stub
	}

//	自定义排序方式 当前对象的age属性和参数的age属性进行比较,若差值大于0升序 否则降序 为0是无法加入
	@Override
	public int compareTo(Animal o) {
		System.out.println("compareTo:"+o);
//		使用年龄定义的方案
		return age - o.age;
	}

	public static void main(String[] args) {
		TreeSet<Animal> set = new TreeSet<>();
//		使用年龄进行计算
		set.add(new Animal("AA", 10));
		System.out.println("--------------");
		set.add(new Animal("BB", 9));
		System.out.println("--------------");
		set.add(new Animal("CC", 11));
		System.out.println("--------------");
		set.add(new Animal("DD", 12));
		System.out.println("--------------");
		
		System.out.println(set);
	}
}
16.3.14Collections工具类

单列集合的工具类,都是静态方法

public class Demo16 {

	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("2");
		list.add("1");
		list.add("4");
		list.add("3");
		list.add("5");
		System.out.println(list);
//		进行排序
		Collections.sort(list);
		System.out.println(list);
//		反转集合
		Collections.reverse(list);
		System.out.println(list);
//		随机打乱
		Collections.shuffle(list);
		System.out.println(list);
	}
}

16.4双列集合

16.4.1Map接口

特点:
 双泛型接口
  Map
 Map使用键(Key)和值(Value)组成的键值对
 Key:无序的,不重复,无下标(Set集合实现的)
 Value:无序,可重复,无下标(Collection集合实现的)

public class Demo01 {

	public static void main(String[] args) {
//		在后续的编程中,KV结构是非常多的
		Map<String,Object> map = new HashMap<>();
//		添加集合方法
		map.put("A", 10);//Integer
		map.put("B", "BaiBai");
		map.put("C", 100.02);//Double
		map.put("D", false);//Boolean
		System.out.println(map);
//		获取 通过K或者V
		System.out.println(map.get("A"));
		System.out.println(map.get("E"));//null
//		清空
		/*map.clear();
		System.out.println(map);*/
//		判断是否有内容
		System.out.println(map.isEmpty());
//		Key是否存在
		System.out.println(map.containsKey("A"));
//		Value是否存在
		System.out.println(map.containsValue(10));
//		获取所有的Key的Set集合
		System.out.println(map.keySet());
//		获取所有的Value的Collecion集合
		System.out.println(map.values());
//		Map的有效数据个数
		System.out.println(map.size());
//		通过Key移除K-V数据
		map.remove("A");
		System.out.println(map);
	}
}

16.5常见的双列集合实现类

16.5.1HashMap

常用方法:略
使用红黑树+链表的数据结构

16.5.2HashMap实际应用

可以使用Map 来表示一个对象的实体
可以使用List> 来表示一个对象实例的集合

//	封装一个商品实体:商品编号,名称,价格,产地,上架时间...
public class Goods {

	private int id;
	private String name;
	private double price;
	public Goods(int id, String name, double price) {
		super();
		this.id = id;
		this.name = name;
		this.price = price;
	}
	@Override
	public String toString() {
		return "Goods [id=" + id + ", name=" + name + ", price=" + price + "]";
	}
    
    public static void main(String[] args) {
//		单个商品:创建商品对象
		Goods g1 = new Goods(1, "黑人牙膏", 10.8);
		Goods g2 = new Goods(1, "黑人牙膏", 10.8);
		Goods g3 = new Goods(1, "黑人牙膏", 10.8);
		Goods g4 = new Goods(1, "黑人牙膏", 10.8);
		
//		多件商品:多个对象同时携带,将上述的四件商品添加到集合中
		ArrayList<Goods> gs = new ArrayList<>();
		gs.add(g1);
		gs.add(g2);
		gs.add(g3);
		gs.add(g4);
	}
}
// 使用map封装实体数据
//		使用map集合和完成和实例类相似的功能
//		单个商品:和实例类中的数据显示是一样的
HashMap<String,Object> goods1 = new HashMap<>();
goods1.put("id", 1);
goods1.put("name", "黑人药膏");
goods1.put("price", 10.8);
System.out.println(goods1);

HashMap<String,Object> goods2 = new HashMap<>();
goods2.put("id", 2);
goods2.put("name", "白人药膏");
goods2.put("price", 10.8);
System.out.println(goods2);

//		多个商品:使用List集合存放Map
ArrayList<HashMap<String,Object>> ggs = new ArrayList<>();
ggs.add(goods1);
ggs.add(goods2);
System.out.println(ggs);
16.5.3HashMap练习
public class Test01 {

//	使用集合存放省市数据
//	["辽宁":{"沈阳","大连","鞍山"},"吉林":{"四平","长春"}]
	public static void main(String[] args) {
//		K为String V为List集合
		HashMap<String,List<String>> map = new HashMap<>();
		
		List<String> city1 = new ArrayList<>();
		city1.add("沈阳");
		city1.add("大连");
		city1.add("鞍山");
		
//		添加到map中
		map.put("辽宁", city1);
		
		List<String> city2 = new ArrayList<>();
		city2.add("四平");
		city2.add("长春");
		
		map.put("吉林", city2);
		
		System.out.println(map);
	}
}
16.5.4Hashtable

常用方法和HashMap一致
Hashtable是线程安全的,HashMap是线程不安全的
Hashtable不允许存储null作为K和V的,HashMap可以

public class Demo04 {

	public static void main(String[] args) {
		Hashtable<String,Object> map = new Hashtable<>();
		
		map.put("A", "A");
		map.put("B", "B");
		map.put("C", "C");
		map.put("D", "D");
		
//		为同一个key赋值 k是可重复的
		map.put("A", "AA");
		
//		Hashtable中是不能存在null值的
//		map.put(null, "EE");
//		map.put("E", null);
		
		System.out.println(map);
	}
}

16.6泛型的使用

16.6.1泛型类

语法:
类名

public class Box<T> {//T:表示任意的java类型 E,K,V...
	
	private T data;//可以作为引用存在 但是不能使用T创建对象
	
//	为T进行初始化
	public void setData(T data) {
		this.data = data;
	}
//	返回T的实例/对象
	public T getData() {
		return data;
	}
	
	public static void main(String[] args) {
		Box<String> box = new Box<>();
		box.setData("hello");
		System.out.println(box.getData());
		
		Box<Integer> b1 = new Box<>();
		b1.setData(10);
		System.out.println(b1.getData());
	}
}
16.6.2泛型接口

语法:
接口名

public interface MyInterface<T> {

	void show(T t);
}

class My implements MyInterface<String> {

	@Override
	public void show(String t) {
//		对t进行操作
	}	
}
16.6.3泛型方法

语法:
public T 方法名(T t,…){}

public class Store {

//	泛型可以作为参数,必须在当前方法中先定义 
	public <E> void m1(E e) {
		
	}
	
	public <V> V get(V v) {
		return v;
	}
}
16.6.4泛型上下边界
public class Demo01 {

//	泛型上下边界 
/**	
 * 不能确定好泛型的类型时,可以使用?
 * @param list
 */
	public static void test01(List<?> list) {}
	
/**	
 * 定义上边界
 *  
 *  	传递泛型时,可以是类型及其子类
 * @param args
 */
	public static void test02(List<? extends Number> list) {}
	
/**	
 * 定义下边界
 *  
 *  	传递泛型时,可以是类型及其父类
 * @param args
 */
	public static void test03(List<? super Number> list) {}
		
	public static void main(String[] args) {
		test01(new ArrayList<Integer>());
		test01(new ArrayList<String>());
		
		test02(new ArrayList<Number>());
		test02(new ArrayList<Integer>());
		test02(new ArrayList<Double>());
//		test02(new ArrayList());
		
		test03(new ArrayList<Number>());
//		test03(new ArrayList());
		test03(new ArrayList<Object>());
	}
}
 
  

                            
                        
                    
                    
                    

你可能感兴趣的:(JavaSE,笔记,java)