java学习笔记-数组和集合
拆箱装箱
在使用集合(如List, Set等)和泛型时,集合和泛型在Java中通常使用包装类而不是基本数据类型。
1.使用集合时:当你需要将基本数据类型存储在集合(如ArrayList, HashSet等)中时,由于集合是泛型的,它们只接受对象作为元素。因此,你需要将基本数据类型转换为对应的包装类。Java编译器会自动为你进行这种转换,即装箱。
从集合中检索值:当你从集合中检索一个包装类类型的值时,并尝试将其赋值给一个基本数据类型的变量时,会发生拆箱。
List<Integer> list = new ArrayList<>(); list.add(5); // 这里的5被自动装箱为Integer.valueOf(5) int num = list.get(0); // 这里的list.get(0)被自动拆箱为int值5
2.方法参数:当方法参数是包装类类型,而你传递了一个基本数据类型值时,会发生装箱。
方法返回值:当方法返回的是包装类类型,而你尝试将其赋值给一个基本数据类型的变量时,会发生拆箱。
//装箱 public void printInteger(Integer i) { System.out.println(i); } printInteger(10); // 这里的10被自动装箱为Integer.valueOf(10) //拆箱 public Integer getNumber() { return 10; } int num = getNumber(); // 这里的getNumber()返回值被自动拆箱为int值10
3.赋值给包装类类型的变量:当你将一个基本数据类型的值赋给一个包装类类型的变量时,会发生装箱。
进行算术运算:当你尝试对包装类类型的值进行算术运算时,它们会被自动拆箱为基本数据类型,以执行运算,然后再根据需要重新装箱。
Integer i = 10; // 这里的10被自动装箱为Integer.valueOf(10) //自动装箱拆箱原理:基本数据类型和类类型数据之间的自动转化 int a = 2; Integer b = a; //基本类型->类类型:装箱 int c = b; //类类型->基本类型:拆箱 Integer a = 10; Integer b = 5; int sum = a + b; // 这里的a和b被自动拆箱为int值,执行加法运算后再赋值给sum
集合和数组的区别
区别
1.数组必须指定长度,集合是动态长度
2.数组两种类型都可以存储(Integer\int),集合只能存储类类型(Integer)
3.数组中的元素可以通过索引来访问和修改,索引从0开始。
集合中的元素可以通过迭代器(Iterator)或增强的for循环(也称为"foreach"循环)来访问。修改集合中的元素则取决于集合的具体类型和实现。
4.数组在内存中分配的是一块连续的空间,这使得数组在访问元素时具有较高的效率。但是,这也使得在数组中间插入或删除元素时效率较低,因为可能需要移动其他元素以保持连续性。
集合在内存中的存储方式可能因实现而异。例如,ArrayList在内存中也是分配一块连续的空间,但LinkedList则使用链表结构,每个元素都保存了指向下一个元素的引用。这使得LinkedList在插入和删除元素时具有较高的效率,但在访问元素时效率较低。
int[] intarray = new int[]{1,2,3,4}; Integer[] array = new Integer[]{1,2,3,4}; System.out.println(Arrays.toString(array)); //[1, 2, 3, 4] List<Integer> list = Arrays.asList(array); //将数组转为集合 System.out.println(list); //[1, 2, 3, 4]
Arrays.asList()与List的区别
1.Arrays.asList()返回的List是一个固定长度的List,其底层数据结构是数组。而普通的List实现类(如ArrayList)底层通常采用数组或链表等数据结构。
2.Arrays.asList()返回的List是不可变的,即无法改变其长度。而普通的List实现类通常是可变的,可以根据需要动态改变长度。
3.由于Arrays.asList()返回的List是不可变的,因此对其进行增删操作会受到限制。而普通的List实现类提供了更多的操作方法,如add()、remove()、clear()等。
数组转为集合
什么情况下需要转?
你有一个数组,但你希望使用集合的特定方法(如排序、查找、去重等)。如果你有一个基本数据类型的数组,并且你想将其存储在一个泛型集合中(如List<Integer>),你需要将数组转换为包装类类型的集合。
Arrays.asList()方法是Java中Arrays类提供的一个静态方法,用于将数组转换为List集合。它接收一个数组作为参数,并返回一个包含数组元素的List集合。
Integer[] array = new Integer[]{1,2,3,4}; System.out.println(Arrays.toString(array)); //[1, 2, 3, 4] //当我们需要创建一个不需要改变大小或者内容的 List 集合时,我们可以使用 Arrays.asList() 来快速地初始化一些元素 List<Integer> list = Arrays.asList(array); //将数组转为集合 //list.add(2); 直接对list进行编辑会抛出异常UnsupportedOperationException System.out.println(list); //[1, 2, 3, 4]
使用Arrays.asList()方法转换的List是一个固定长度的List,它的长度与原始数组的长度相同。这意味着我们无法通过添加或删除元素来改变List的长度,否则会抛出UnsupportedOperationException异常。如果需要对List进行增删操作,可以考虑创建一个新的ArrayList并将转换后的List作为构造函数的参数。
String[] array1 = {"apple", "banana", "orange"}; List<String> stringList = new ArrayList<>(Arrays.asList(array1)); stringList.add("grape"); // 可以对新创建的ArrayList进行增删操作
通过stream()方法将基本类型的数组转为集合
//stream Integer[] array2 ={11,22,33}; List list1 = Arrays.stream(array2).collect(Collectors.toList()); System.out.println(list1); //基本数据类型也可以实现转换(依赖boxed装箱操作) int[] array3 = {44,55,66}; List list2 = Arrays.stream(array3).boxed().collect(Collectors.toList()); System.out.println(list2);
set,list,map
//list是有序可重复的 List<String> users = new LinkedList<String>(); users.add("zhangsan"); users.add("zhangsan"); users.add("lisi"); users.add("wangwu"); System.out.println(users); //[zhangsan, zhangsan, lisi, wangwu] for (String user : users) { System.out.println(user); //zhangsan zhangsan lisi wangwu } //set是无序不重复的 Set<String> set = new HashSet<String>(); set.add("zhangsan"); set.add("zhangsan"); set.add("zhangsan"); set.add("李四"); set.add("李四"); for (String s:set ) { System.out.println(s); //李四 zhangsan } Map<String,String> map = new HashMap<String,String>(); map.put("1","zhangsan"); map.put("2","lisi"); map.put("3","wangwu"); System.out.println(map); //{1=zhangsan, 2=lisi, 3=wangwu} for (String m: map.keySet() ) { System.out.println(m); //1 2 3 //System.out.println(map.get(m)); //zhangsan lisi wangwu }
ArrayList和LinkedList
//ArrayList底层是数组,遍历快,添加删除慢 //LinkedList底层是链表,遍历慢,添加删除快 List<String> list3 = new LinkedList<>(); list3.add("abc"); list3.add("efg"); for (String s:list3 ) { System.out.println(s); }
TreeSet和HashSet
package com.training; import java.util.HashSet; import java.util.Set; import java.util.TreeSet; public class SetTraining { public static void main(String[] args) { //HashSet和TreeSet区别 //两者都遵循 Set 接口的规范,即它们都不允许存储重复的元素。这是通过元素的 equals() 方法来确定的。 //TreeSet不重复,排序,底层数据结构式一个二叉树,TreeSet 由于需要维护元素的排序,因此在插入、删除和查找元素时通常比 HashSet 慢 Set<String> set = new TreeSet<String>(); set.add("4"); set.add("3"); set.add("2"); set.add("4"); System.out.println(set.add("3"));//false 添加失败 for (String s:set ) { System.out.println(s); //2 3 4 System.out.println(s.hashCode()); } System.out.println("-------------------------"); //HashSet不重复,底层数据结构是哈希表,它在插入、删除和查找元素时通常比 TreeSet 更快 Set<String> set1 = new HashSet<>(); set1.add("4"); set1.add("3"); set1.add("2"); set1.add("4"); set1.add("3"); System.out.println(set1.add("3"));//false 添加失败 for (String s:set1 ) { System.out.println(s); //2 3 4 } } }
HashMap、TreeMap、Hashtable
package com.training; import java.util.HashMap; import java.util.Map.Entry; import java.util.TreeMap; public class MapTraining { public static void main(String[] args) { // HashMap键值对实现,线程不安全 HashMap<Integer, String> Sites = new HashMap<Integer, String>(); // 添加键值对 Sites.put(1, "Google"); Sites.put(2, "Runoob"); Sites.put(3, "Taobao"); Sites.put(4, "null"); Sites.put(null, "Zhihu"); // 输出 key 和 value for (Integer i : Sites.keySet()) { System.out.println("key: " + i + " value: " + Sites.get(i));//key: 1 value: Google } System.out.println("---------------------------"); // 返回所有 value 值 for(String value: Sites.values()) { // 输出每一个value System.out.print(value + ", ");//Zhihu, Google, Runoob, Taobao, null, } System.out.println("\n"+"---------------------------"); System.out.print("set view:"+ Sites.entrySet());//set view:[null=Zhihu, 1=Google, 2=Runoob, 3=Taobao, 4=null] System.out.println("\n"+"---------------------------"); for (Entry<Integer, String> entry: Sites.entrySet() ) { System.out.print(entry+ ", "); } System.out.println("\n"+"---------------------------"); //TreeMap按照key进行排序,不允许使用null键,但允许使用null值。 TreeMap<Integer, String> users = new TreeMap<>(); users.put(1,"张三"); users.put(3,"王五"); users.put(2,null); //users.put(null,"翠花");不允许使用null键 for (Entry e:users.entrySet() ) { System.out.print(e+ ", ");//1=张三, 2=null, 3=王五, } //Hashtable键值对实现,线程安全,Hashtable不允许使用null键和null值。 } }