JavaSE 1.4.1 数组与集合:
数组:
动态初始化指定长度,静态初始化指定内容。数组一旦创建,长度无法改变。
int[] arrayDynamic = new int[100]; //动态初始化
int[] arrayA = {10,20,30}; //静态省略,不能拆分
int[] arrayA1 = new int[]{10,20,30}; //静态初始化
//静态初始化拆分
int[] arrayA2;
arrayA2 = new int[]{10,20,30};
动态初始化数组时,整数类型初始化为0,浮点0.0,字符\u0000,布尔False,引用null。(静态初始化时也有默认值过程,但是马上就赋值了)
- 数组索引越界异常: array index out of bounds exception
- 空指针异常: 没有new创建。数组是引用类型。null pointer exception
对象数组:
Person[] array = new Person[3];
array[0] = new Person("lvlvsun",10);
array[1] = new Person("zly",20);
array[2] = new Person("leakyRelu",30);
System.out.println(array[0].getName());
缺点:一旦创建,程序运行期间长度无法改变,所以可以采用ArrayList集合。
数组的元素反转:
双指针
for (int min = 0, max = array.length - 1 ; min < max; min++, max--) {
int temp = array[max];
array[max] = array[min];
array[min] = temp;
}
数组的元素遍历:
fori和foreach(迭代器iterator,稍后会有)
int[] array = new int[]{...};
for (int i = 0; i < array.length; i++) {
}
for (int i : array) {
}
二维数组:
各行长度不同,叫锯齿数组
int[][] arr = {{1,2,3},{4,5,6},{7,8,9}};
arr.length();//获取数组x长度
arr[0].length...//数组y方向长度,可以用嵌套for循环处理二维数组
Arrays类:
Arrays.sort();
Arrays.parallelsort();
:多处理器排序
Arrays.binarySearch(array,number);
二分查找
Arrays.copyOf(array,len)
:
sort(String)会按照字母升序。但如果sort自定义类,那么这个自定义类需要实现Comparable接口或者Comparator接口的支持。
方法使用
public static String toString(array);
: 将参数数组转换成默认格式的字符串,如例
public static void sort(array);
: 升序,无返回值,别的类型也可以排序。
int[] intArray = {10, 20, 30};
// 将int[]数组按照默认格式变成字符串
String intStr = Arrays.toString(intArray);
System.out.println(intStr); // [10, 20, 30]
int[] array1 = {2, 1, 3, 10, 6};
Arrays.sort(array1);
System.out.println(Arrays.toString(array1)); // [1, 2, 3, 6, 10]
String[] array2 = {"bbb", "aaa", "ccc"};
Arrays.sort(array2);
System.out.println(Arrays.toString(array2)); // [aaa, bbb, ccc]
字符串倒序打印
String str = "asv76agfqwdfvasdfvjh";
// 必须是一个数组,才能用Arrays.sort方法
// String --> 数组,用toCharArray
char[] chars = str.toCharArray();
Arrays.sort(chars);
// 需要倒序遍历
for (int i = chars.length - 1; i >= 0; i--) {
System.out.println(chars[i]);
}
集合:推荐学习数据结构
Collection接口:
public interface Collection<E> extends Iterable<E>
数组的长度是固定的。集合的长度是可变的。
集合按照其存储结构可以分为两大类,分别是单列集合java.util.Collection
和双列集合java.util.Map
List
的特点是元素有序、元素可重复。Set
的特点是元素无序,而且不可重复。
针对Collection集合我们到底使用谁呢?
唯一吗?
-
是:Set
排序吗?
- 是:TreeSet
- 否:HashSet
如果你知道是Set,但是不知道是哪个Set,就用HashSet。
-
否:List
要安全吗?
- 是:Vector
- 否:ArrayList或者LinkedList
查询多:ArrayList
增删多:LinkedList
如果你知道是List,但是不知道是哪个List,就用ArrayList。
Collection常用功能:
public boolean add(E e)
: 把给定的对象添加到当前集合中 。public void clear()
:清空集合中所有的元素。public boolean remove(E e)
: 把给定的对象在当前集合中删除。public boolean contains(E e)
: 判断当前集合中是否包含给定的对象。public boolean isEmpty()
: 判断当前集合是否为空。public int size()
: 返回集合中元素的个数。public Object[] toArray()
: 把集合中的元素,存储到数组中。
Iterator迭代器
public interface Iterable<T>
public interface Iterator<E>
迭代:即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。
Iterator<String> itera = coll.iterator();
// 泛型指的是 迭代出 元素的数据类型
while(itera.hasNext()){ //判断是否有迭代元素
String str = itera.next();//获取迭代出的元素
System.out.println(str);
}
迭代器原理:
获取实现类对象时,指针指向集合的-1索引,迭代器的next取出元素并操作指针向后移动一位。
增强for循环:
for(元素的数据类型 变量 : Collection集合or数组){ }
用于遍历元素,不能增删操作。会抛出并发修改异常。ConcurrentModificationException
泛型:可以在类或方法中使用未知的类型。类型参数化
协变:
数组的协变,内部协变。
子类的数组对象可以使用父类的引用数组取引用。
集合泛型就没有协变功能。
泛型的使用
在JDK5之后,新增的泛型(Generic)语法,让你在设计API时可以指定类或方法支持泛型,这样使用API的时候也变得更为简洁,并得到了编译时期的语法检查。
泛型不能应用在基本类型,需要使用包装类
在类中使用泛型
public class GenericClass<T,E> {
public void doing(T person){
}
public T read(E element){
return null;
}
}
在方法中使用泛型
public <T> T test(T t){
return null;
}
public static <T> void sort(T[] a, Comparator<? super T> c) {
}
当没有指定泛型时,默认类型为Object类型。
- 避免了类型强转的麻烦。
- 将运行时期的ClassCastException,转移到了编译时期变成了编译失败。
泛型没有继承多态关系
Collection<Object> list = new ArrayList<String>();
这种是错误的。
在Java的泛型中可以指定一个泛型的上限和下限。
泛型的上限:
- 格式:
类型名称 <? extends 类 > 对象名称
- 意义:
只能接收该类型及其子类
- 泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类
public static void getElement1(Collection<? extends Number> coll){}
泛型的下限:
- 格式:
类型名称 <? super 类 > 对象名称
- 意义:
只能接收该类型及其父类型
- 泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类
public static void getElement2(Collection<? super Number> coll){}
习惯上选择以下字母代表某种类型:
泛型类型不确定,可以通过通配符<?>表示。
- T 意味某种类型。
- E 意味 链表、数组里的元素,如List list 表示 list 里的元素。
- K意味map(k,v) 里的键值 Key
- V 意味 返回或映射的值。
然而,泛型的运用要受到如下限制 :
- 不能使用基本类型的类型参数,可以使用其包装类型代替。
- 静态成员无法使用类型参数。
- 不能使用泛型类异常
- 不能实例化泛型对象或数组,如:
T t = new T(); T[] a=new T5;
- 不能使用泛型数组。
Collections类:
Collections是为集合框架提供服务的工具类,里面的所有方法都是静态方法,功能包括对集合排序、折半查找、拷贝、随机、交换、同步等。
java.utils.Collections
用来对集合进行操作。部分方法如下:
public static <T> boolean addAll(Collection<T> c, T... elements)
:往集合中添加一些元素。public static void shuffle(List<?> list)
:打乱集合顺序。public static <T> void sort(List<T> list)
:将集合中元素按照默认规则排序。public static <T> void sort(List<T> list,Comparator<? super T> )
:将集合中元素按照指定规则排序。
Comparator比较器
Collections中sort重载的规则是怎么来的呢
我们若需要控制某个类的次序,而该类本身不支持排序(即没有实现java.lang.Comparable
接口);那么,我们可以建立一个“该类的比较器”来进行排序。这个“比较器”只需要实现java.util.Comparator
接口即可。
想要字符串按照第一个字符降序排列,那么这样就要修改String的源代码,这是不可能的了,那么这个时候我们可以使用public static <T> void sort(List<T> list,Comparator<? super T> )
方法灵活的完成,
Collections.reverseOrder();
: 将比较器反转,快速实现倒序。
也就是说,我们可以通过“实现Comparator类来新建一个比较器”,然后通过该比较器对类进行排序。之后可以使用lambda表达式简化。
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.indexOf(1)-o1.indexOf(1);
}
});
Collections.sort(list, (o1, o2) -> o2.indexOf(1)-o1.indexOf(1));
Comparable 是排序接口
若一个类实现了Comparable接口,就意味着“该类支持排序”。 即然实现Comparable接口的类支持排序,假设现在存在“实现Comparable接口的类的对象的List列表(或数组)”,则该List列表(或数组)可以通过Collections.sort(或 Arrays.sort)(C调用A调用Timsort)来进行排序。
此外,“实现Comparable接口的类的对象”可以用作“有序映射(如TreeMap)”中的键或“有序集合(TreeSet)”中的元素,而不需要指定比较器。
Collections.sort(list);
重写compareTo()方法。
那么我们采用的public static <T> void sort(List<T> list)
这个方法完成的排序,实际上要求了被排序的类型需要实现Comparable接口完成比较的功能,在String类型上如下:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {}
String类实现了这个接口,并完成了比较规则的定义,无法改变。
public static <T> void sort(List<T> list,Comparator<? super T> )
方法灵活的完成,这个里面就涉及到了Comparator这个接口,位于java.util包下,排序是comparator能实现的功能之一:
-
public int compare(String o1, String o2)
:比较其两个参数的顺序。两个对象比较的结果有三种:大于,等于,小于。
如果要按照升序排序,
则o1 小于o2,返回(负数),相等返回0,01大于02返回(正数)
如果要按照降序排序
则o1 小于o2,返回(正数),相等返回0,01大于02返回(负数)
简述Comparable和Comparator两个接口的区别。
Comparable:强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的compareTo方法被称为它的自然比较方法。只能在类中实现compareTo()一次。实现此接口的对象列表(和数组)可以通过Collections.sort(和Arrays.sort)进行自动排序,对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。
Comparator强行对某个对象进行整体排序。可以将Comparator 传递给sort方法(如Collections.sort或 Arrays.sort),从而允许在排序顺序上实现精确控制。还可以使用Comparator来控制某些数据结构(如有序set或有序映射)的顺序,或者为那些没有自然顺序的对象collection提供排序。
Collectionの具体实现类
ArrayList:动态数组
使用泛型:实例化后全部是统一的类型,且泛型只能是引用类型。
ArrayList<String> list = new ArrayList<>(); //从JDK1.7开始,右侧尖括号内可以不写内容,但得有<>。
从JDK 1.5开始支持自动装箱、自动拆箱。即只需要在< E >中使用包装,输入返回都可以直接用基本类型,详见包装类。
ArrayList的常用方法:
ArrayList集合重写了toString。
public boolean add(E e);
public E get(int index); //从0开始,返回泛型E的对应值
public E remove(int index);//删除并返回该索引的元素
public int size();//无参,返回集合的长度
add的返回值对于ArrayList来说一定是true的,所以没什么用,但对于其他集合,add方法不一定成功。
Example:
创建一个Student类的ArrayList:
ArrayList<Student> info = new ArrayList<>();
info.add(new Student("zly", 10));
info.add(new Student("lvlvsun", 15));
info.add(new Student("leaky", 20));
info.add(new Student("Relu", 30));
for (int i = 0; i < info.size(); i++) {
System.out.println(info.get(i).getName());
System.out.println(info.get(i).getAge());
创建20个数,取其中偶数:
public static void main(String[] args) {
int[] list = new int[20];
Random r = new Random();
for (int i = 0; i < 20; i++) {
list[i] = r.nextInt(100) + 1;
}
System.out.println(getEven(list));
}
public static ArrayList<Integer> getEven(int[] list) {
ArrayList<Integer> listA = new ArrayList<>();
for (int i = 0; i < list.length; i++) {
if (list[i] % 2 == 0) {
listA.add(list[i]);
}
}
return listA;
}
List的子类
List接口:
java.util.List
是单列集合的一个重要分支,习惯性地会将实现了List接口的对象称为List集合。在List集合中允许出现重复的元素,所有的元素是以一种线性方式进行存储的,在程序中可以通过索引来访问集合中的指定元素。另外,List集合还有一个特点就是元素有序,即元素的存入顺序和取出顺序一致。
元素有索引,equals方法确定是否为重复元素,存储元素和取出元素的顺序是一致的(存储123 取出123)
常用方法:
继承了Collection接口中的全部方法,还增加了一些根据元素索引来操作集合的特有方法,如下:
public void add(int index, E element)
: 将指定的元素,添加到该集合中的指定位置上。
public E get(int index)
:返回集合中指定位置的元素。
public E remove(int index)
: 移除元素, 返回的是被移除的元素。
public E set(int index, E element)
:替换元素,返回值为更新前的元素
// 跟size() 方法一起用 来 遍历的
for(int i = 0;i<list.size();i++){
System.out.println(list.get(i));
}
//使用迭代器
Iterator<String> it = list.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
//还可以使用增强for
for (String string : list) {
System.out.println(string);
}
ArrayList集合
java.util.ArrayList
集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList
是最常用的集合。
许多程序员开发时非常随意地使用ArrayList完成任何需求,并不严谨,这种用法是不提倡的。
LinkedList集合
java.util.LinkedList
集合数据存储的结构是链表结构。方便元素添加、删除的集合。
LinkedList方法,了解即可
public void addFirst(E e)
:将指定元素插入此列表的开头。public void addLast(E e)
:将指定元素添加到此列表的结尾。public E getFirst()
:返回此列表的第一个元素。public E getLast()
:返回此列表的最后一个元素。public E removeFirst()
:移除并返回此列表的第一个元素。public E removeLast()
:移除并返回此列表的最后一个元素。public E pop()
:从此列表所表示的堆栈处弹出一个元素。public void push(E e)
:将元素推入此列表所表示的堆栈。public boolean isEmpty()
:如果列表不包含元素,则返回true。
BitSet
独立的数据储存结构
继承状态implements Cloneable, java.io.Serializable
储存一位判断符号,可以大量节省空间。
插入此列表的开头。
public void addLast(E e)
:将指定元素添加到此列表的结尾。public E getFirst()
:返回此列表的第一个元素。public E getLast()
:返回此列表的最后一个元素。public E removeFirst()
:移除并返回此列表的第一个元素。public E removeLast()
:移除并返回此列表的最后一个元素。public E pop()
:从此列表所表示的堆栈处弹出一个元素。public void push(E e)
:将元素推入此列表所表示的堆栈。public boolean isEmpty()
:如果列表不包含元素,则返回true。