1.泛型
* <数据类型> --- 引用数据类型,可以是Integer,String,Student类等等
*泛型:将明确的集合类型的工作推迟到了创建对象或者调用方法的时候,属于一种参数化类型,可以作为参数传递. 泛型的引出可以提供程序的安全性!
*泛型的好处:
1)将运行时期异常提前到了编译时期
2)优化了设计,解决了黄色警告线问题
3)避免了强制类型转换
*泛型可以应用在接口中,类中,方法上,集合中
*泛型高级(通配符)
<?> :代表任意类型Object类型,或者任意的Java类
<? extendsE>:向下限定,E的子类或者E这个类型
<? super E>:向上限定,E及其他的父类
Arraylist:底层数据结构式数组结构,查询块,增删慢
从内存角度考虑:线程不安全的,不同步的,执行效率高
2.List集合的子实现类 LinkedList:底层是一种链表实现,查询慢,增删快
* 线程不安全的,不同步,执行效率高
Vector:底层是一种可增长对象数组,查询快,增删慢
线程安全,同步,执行效率高
针对数组操作的工具类:Arrays,提供了一个方法:
public static<T> List<T> asList(T... a) :将数组转换成固定大小的集合
注意:如果使用此方法,那么集合的长度不可变
//定义数组:
String[]str = {"hello","world","java"} ;
//将数组转换成固定大小的集合
List<String>list = Arrays.asList(str) ;
①ArrayList:
遍历功能:
1)Collection的iterator()
2)size()和get(int index)普通for循环
3) 增强for循环
//迭代器方式
Iterator it =array.iterator() ;
while(it.hasNext()) {
Student s =(Student)it.next() ;
System.out.println(s.getName()+"---"+s.getAge());
}
//size()和get(int index)普通for循环
for(int x = 0 ; x<array.size() ; x ++) {
Student s =(Student)array.get(x) ;
System.out.println(s.getName()+"----"+s.getAge());
}
}
② Vector
特有功能:
public void addElement(Objectobj)------->add(Object obj)
public Enumeration elements():返回此向量的枚举--->相当于:public Iterator iterator()
boolean hasMoreElements() --->boolean hasNext() ;
Object nextElement() --->Objectnext() ;
③LinkedList
特有功能:
添加功能
addFirst(Object e):将指定的元素插入到列表的开头
addLast(object e):将指定的元素添加到列表末尾
获取功能:
getFirst():获取列表第一个元素
getLast():获取列表第二个元素
删除功能
publicObject removeFirst()移除并返回此列表的第一个元素。
public Object removeLast()
需求:
模拟栈结构的特点,先进后出
//创建linkedList集合对象
LinkedList link = newLinkedList() ;
//添加元素
//符合栈结构的特点:先进后出
link.addFirst("hello"); hello,world,java依次添加,添加进去后为
link.addFirst("world"); link={java,world,hello}
link.addFirst("java"); 输出时为java,world,hello.符合先进后出
Iterator it = link.iterator();
while(it.hasNext()) {
String s =(String)it.next();
System.out.println("s:"+s);
}
注意:按照存储字符串(新建集合的思想)的形式来去存储自定义对象,发现自定义对象并没有去除重复,为什么?
contains方法底层依赖于equals方法
equals方法默认比较的是地址值,如果想让equals()方法比较他们的内容是否相同,需要重写equals(),也就意味着存储自定义类,必须重写 equals()方法,这样才能比较的是这些对象的内容是否相同
3.JDK5以后的新特性
* 可变参数:当一个方法的参数个数不确定的时候,要使用可变参数
格式:
修饰符 返回值类型 方法名(数据类型...变量名){...}
注意:
1)变量名:看成一个数组
2)使用的时候数据类型...
注意:根据具体的需求去完成,一般情况,知道有这个特性就可以了
*增强for循环
for(int n: a){ …}
n是变量,a是需要遍历的,可以是数组,集合
增强for循环的弊端:如果集合的对象是null,如果再次对集合操作,就会出现异常
要对集合进行判断,非空判断解决
注意:遍历list集合,判断如果有"world"元素,给集合添加一个元素(javaee)
for(String s: list){
//java.util.ConcurrentModificationException:并发修改异常
//增强for的出现就是用来替代迭代器的!
if("world".equals(s)){
list.add("javaee");
}
}
*静态导入:
特点:
1)前提是该方法必须是静态的
2)导入到的一个方法的级别
静态导入的格式:
importstatic 包名.类名.方法名;
importstatic java.util.ArrayList.add; 方法必须是静态方法
之前导包:java.util.Scanner; 导入到类的级别
import static java.lang.Math.abs; //导入到方法的级别
import static java.lang.Math.pow;
注意:本身当前的某个类中的方法名和需要被静态导入的方法名一样,必须加上前缀
4.集合的嵌套遍历:大集合里存一些小集合,每个小集合相当于之前的Student类对象
代码示例
public class ArrayListTest{
public static void main(String[] args){
//创建一个大的集合
ArrayList<ArrayList<Student>>bigArrayList = new ArrayList<ArrayList<Student>>() ;
//创建第一个班的集合对象
ArrayList<Student>firstArray = new ArrayList<Student>() ;
//创建学生对象
Student s1 = newStudent("曹操",35) ;//后知后觉
Student s2 = newStudent("诸葛亮", 29);//先知先觉
Student s3 = newStudent("蒋干", 30) ;//不知不觉
//给第一个班添加元素
firstArray.add(s1) ;
firstArray.add(s2) ;
firstArray.add(s3) ;
//将第一个集合添加到大集合中
bigArrayList.add(firstArray);
//创建第二个班集合对象
ArrayList<Student>secondArray = new ArrayList<Student>() ;
Student s11 = newStudent("宋江",38) ;
Student s22 = newStudent("鲁智深", 29);
Student s33 = newStudent("武松", 30) ;
secondArray.add(s11) ;
secondArray.add(s22) ;
secondArray.add(s33) ;
//添加到大集合
bigArrayList.add(secondArray);
//创建第三个集合对象
ArrayList<Student>thirdArray = new ArrayList<Student>() ;
Student s111 = newStudent("高圆圆",38) ;
Student s222 = newStudent("唐嫣", 29);
Students333 = new Student("刘若英", 30) ;
thirdArray.add(s111) ;
thirdArray.add(s222) ;
thirdArray.add(s333) ;
//添加到集合
bigArrayList.add(thirdArray);
//增强for遍历:大集合
for(ArrayList<Student>array: bigArrayList) {
for(Student s:array){
System.out.println(s.getName()+"---"+s.getAge());
}
}
}
}
5. Map集合
需求:有很多学生,学生有姓名,有学号,根据学生的学号查找学生?
之前学习的集合,可以将姓名,学号作为学生类的中两个成员变量,创建集合的时候存储这个类型,可以的
关键只知道学生学号,通过学号找姓名
Key Value
学号1 姓名1
学号2 姓名2
学号3 姓名3
学号1(重复的键) 姓名4
Java针对这种技术----->Map集合 ,键值的映射关系的一种集合(接口)
将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
Map<K,V> ,在Map集合中,只针对键有效,跟值无关
HashMap
Map接口的子实现类:
TreeMap
* 面试题:
Map集合和Collection的区别?
Map集合:是一种键和值的映射关系(双列集合) 当作为:夫妻对
Collection集合:单列集合,只能存储一种类型的元素 当作为:光棍
间接关系:HashSet依赖于Map接口的子实现类HashMap
TreeSet依赖于Map接口的子实现类TreeMap
Map接口的功能:
添加功能:
V put(K key,V value) :将指定的值和键关联起来
如果当前的这个键是一次存储,则返回值null
如果不是第一次存储,返回值是第一次对应的值,当前的值就把之前的键对应的值替换掉!
获取功能
Set<Map.Entry<K,V>>entrySet() :和Map集合的遍历有关系(键值对对象)
Set<K>keySet():获取映射关系中所有的键的集合
intsize()返回此映射中的键-值映射关系数
删除功能
voidclear():删除所有映射关系
Vremove(Objectkey)如果存在一个键的映射关系,则将其从此映射中移除
判断功能:
booleancontainsKey(Object key)如果此映射包含指定键的映射关系,则返回 true
booleancontainsValue(Object value):映射关系中是否包含指定的值
booleanisEmpty():判断映射关系是否为空
代码示例
//添加元素
/*map.put("高圆圆","赵又廷") ;
map.put("周杰伦","昆凌") ;
map.put("黄晓明","babay") ;
map.put("文章","马伊琍") ;*/
//void clear():删除所有映射关系
// map.clear();
//V remove(Object key)如果存在一个键的映射关系,则将其从此映射中移除,返回的是该对应的值
// System.out.println("remove():"+map.remove("黄晓明"));
//boolean containsKey(Objectkey)如果此映射包含指定键的映射关系,则返回 true
/*System.out.println("containsKey():"+map.containsKey("杨过"));
System.out.println("containsKey():"+map.containsKey("高圆圆"));*/
//booleancontainsValue(Object value):映射关系中是否包含指定的值
// System.out.println("containsValue():"+map.containsValue("昆凌"));
Map集合的俩种遍历
(1)
这种遍历方式实际开发中经常用的...
Set<K> keySet():获取映射关系中所有的键的集合
V get(Object key):通过键找值
转换法:
1)将所有的丈夫集中起来
2)让丈夫它对应的妻子
3)将他们遍历出来
思路:
1)获取所有的键的集合
2)通过键找它对应的值
3)遍历即可
public classMapDemo2 {
public static void main(String[] args){
//创建Map集合
Map<String,String>map = new HashMap<String,String>() ;
//添加元素
map.put("杨过","小龙女") ;
map.put("郭靖","黄蓉") ;
map.put("陈旋风","梅超风") ;
map.put("高圆圆","赵又廷") ;
//遍历
//先获取所有的键的集合
Set<String>set = map.keySet() ;
//遍历素有的键,获取每一个键
for(String key :set) {
//通过键找值
String value = map.get(key) ;
System.out.println(key+"="+value);
}
}
}
(2)
Map集合的另一种方式的遍历Set<Map.Entry<K,V>> entrySet() :和Map集合的遍历有关系(键值对对象)
转换法: 1)获取所有的结婚证 2)通过结婚证分别找对应的丈夫和妻子 3)遍历输出
思路: 1)获取所有的键值对象entrySet()
2) K getKey() 和 v getValue(),获取键值对对象中的每个键和每个值
3)遍历
public classMapDemo3 {
public static void main(String[] args){
// 创建Map集合对象
Map<String,String> map = new HashMap<String, String>();
// 添加元素
map.put("杨过","小龙女");
map.put("郭靖","黄蓉");
map.put("陈旋风","梅超风");
map.put("高圆圆","赵又廷");
//获取所有的键值对对象
Set<Map.Entry<String,String>> entrySet = map.entrySet() ;
//增强for
for(Map.Entry<String,String> entry :entrySet) {
//获取到每一个键值对对象
//通过键值对对象找键和值
String key = entry.getKey() ;
String value =entry.getValue() ;
System.out.println(key+"="+value);
}
}
}
6.Set集合
Set集合和List集合的区别?
Set集合:不允许元素重复,唯一的(元素可以为null) ,不能保证迭代的顺序恒久不变(底层哈希表和hascode),无序(存储和取出不一致)
List:允许元素重复,并且存储特点:有序性(存储和取出一致)
LinkedHashSet集合:
底层是一种链接列表和哈希表组成
可以保证元素的唯一性,是由哈希表决定的(hashCode()和equals())
可以保证元素的迭代顺序一致(有序),存储和取出一致,是由链表决定
问题:创建学生对象时,Set集合用add()方法添加了学生对象,但是有重复学生,本来set集合是不能重复的,出现这种现象是什么原因?
答:String类型重写了equals()方法,但是在Student类中并没有写,所以需要在Student类中重新写这俩个方法
如下:
public classStudent {
private String name ;
private int age ;
public Student() {
super();
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
publicint hashCode() {
final int prime = 31;
int result = 1;
result = prime * result +age;
result = prime * result +((name == null) ? 0 : name.hashCode());
return result;
}
@Override
publicboolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() !=obj.getClass())
return false;
Student other = (Student)obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name !=null)
returnfalse;
} else if(!name.equals(other.name))
return false;
return true;
}
}
7.TreeSet集合
可以保证元素唯一并且元素排序(自然升序),add()基于TreeMap,TreeMap又是红黑树结构(自平衡的二叉树结构)
第一个元素添加到root节点,如果比根节点大,存在右孩子,反之存在左孩子,相等
root 搭理
自然排序:自定义的类实现Compareable接口,然后创建TreeSet对象,通过无参构造形式创建对象
比较器排序 :public TreeSet(Comparator<E> comparator)
自然排序:
使用TreeSet集合的自然排序进行操作,如果是自定义类,该那么集合的数据类型要实现Comparable接口,重写CompareTo()方法;Integer、String中已经实现过了
比较器排序
1)//直接使用匿名内部类的方式实现
//创建TreeSet对象,
TreeSet<Student2>ts = new TreeSet<Student2>(new Comparator<Student2>() {
@Override
public int compare(Student2s1, Student2 s2) {
int num=(int)(s1.getChinese()+s1.getMath()+s1.getEnglish()-s2.getChinese()
-s2.getMath()-s2.getEnglish());
//次要条件:名字是否一样
int num2=num==0?s1.getName().compareTo(s2.getName()) :num;
return num2;
}
2)创建一个类MyCompare来实现接口Comparator,重写Compare()方法