Java:集合、泛型、枚举、反射 学习笔记
集合、泛型、枚举、反射
一.集合
集合按照其存储结构可以分为两大类:
- java.util.Collection
- java.util.Map
其他的集合接口,都是由这俩个接口派生出来的
Collection
-
List
-
Set
SortedSet
-
Queue
Map
- StortedMap
一.Collection接口
Collection类型集合必须要有的基本的方法:
//向集合中添加元素
boolean add(E e)
//把一个指定集合中的所有数据,添加到当前集合中
boolean addAll(Collection<? extends E> c)
//清空集合中所有的元素。
void clear()
//判断当前集合中是否包含给定的对象。
boolean contains(Object o)
//判断当前集合中是否包含给定的集合的所有元素。
boolean containsAll(Collection<?> c)
//判断当前集合是否为空。
boolean isEmpty()
//返回遍历这个集合的迭代器对象
Iterator<E> iterator()
//把给定的对象,在当前集合中删除。
boolean remove(Object o)
//把给定的集合中的所有元素,在当前集合中删除。
boolean removeAll(Collection<?> c)
//判断俩个集合中是否有相同的元素,如果有当前集合只保留相同元素,如果没有当前集合元素清空
boolean retainAll(Collection<?> c)
//返回集合中元素的个数。
int size()
//把集合中的元素,存储到数组中。
Object[] toArray()
//把集合中的元素,存储到数组中,并指定数组的类型
<T> T[] toArray(T[] a)
迭代器
java.util.Iterator 接口中,主要定义俩个方法:
public interface Iterator {
boolean hasNext();//返回当前迭代器中是否还有下一个对象
Object next();//获取迭代器中的下一个对象
}
例如:
public static void main(String[] args) {
Collection c1 = new ArrayList();
c1.add("hello1");
c1.add("hello2");
c1.add("hello3");
//获取c1集合的迭代器对象
Iterator iterator = c1.iterator();
//判断迭代器中,是否还有下一个元素
while(iterator.hasNext()){
//如果有的话,就取出来
Object obj = iterator.next();
System.out.println(obj);
}
注意
这种迭代器方式获取集合中的每一个元素,是Collection集合及其子类型集合通用的方式
除了使用迭代器遍历集合之外,使用JDK1.5及以上提供的增强for循环,也可以遍历集合。
foreach循环的格式:
for(变量类型 变量名 : 集合){
//操作变量
}
例如:
public static void main(String[] args) {
Collection<String> c1 = new ArrayList<>();
c1.add("hello1");
c1.add("hello2");
c1.add("hello3");
for(Object o:c1){
System.out.println(o);
}
}
同时,使用foreach循环也可以遍历数组:
public static void main(String[] args) {
int[] arr = {1,3,5,7,9};
//每次循环,使用变量i接收数组中的一个数据
for(int i : arr){
System.out.println(i);
}
}
1.Collection:单列存放
1.List:有序可重复
1.1ArrayList
ArrayList 类中使用数组来实现数据的存储, 所以它的特点是就是:增删慢,查找快
1.2LinkedList:
增删快,查找慢
1.3Vector:
Vector 内部也是采用了数组来存储数据,但是 Vector 中的方法大多数都是线程安全的方法,所以在 多线并发访问的环境中,可以使用 Vector 来保证集合中元据操作的安全。
2.Set:无序不可重复
2.1HashSet:通过hash算法去重
java.util.HashSet 类的实现,主要依靠的是 HashMap
HashSet中元素不可重复,主要是靠对象的hashCode和equals方法来判断对象是否重复。
先比较hashCode值,如果值不同,则不是同一个对象,如果值相同,在进一 步通过equals进行比较
2.2TreeSet:按照指定的规则排序
2.2.1自然排序: 把放到TreeSet中的数据对应的类型实现一Comparable接口,那么这个类的俩个对象就是可以比较大小的
public interface Comparable<T> {
public int compareTo(T o);
}
compareTo方法使用说明: int result = o1.compareTo(o2);
result 0:相同
result 1:o2在前o1在后 交换
result -1:o1在前 o2在后 不交换
public static void main(String[] args) {
Set set = new TreeSet();
set.add(3);
set.add(5);
set.add(1);
set.add(7);
for(Object obj : set){
System.out.println(obj);
}
}
//输出结果:
1
3
5
7
2.2.2 客户端排序(比较器):在构建TreeSet的时候传递排序规则,java.util.Comparator 接口,是一个比较器接口,它的实现类可以对俩个对象作出大小的比较,即 使对象没有实现 Comparable 接口,也可以进行比较。compare(o1,o2)
public interface Comparator<T> {
int compare(T o1, T o2);
}
比较器的使用规则: int result = compare(o1, o2);
0: 相同
1: o2在前o1在后(交换位置)
-1: o1在前 o2在后
二.Map集合
Collection类型集合中,每次存一个数据。
Map类型集合中,每次需要存一对数据,key-value(键值对)
- key值必须是唯一的,value值允许重复
- 键(key)和值(value)一一映射,一个key对应一个value
- 在Map中,通过key值(唯一的),可以快速的找到对应的value值
1.Map实现类
代码中经常会用到的有: HashMap 、 HashTable 、 TreeMap LinkedHashMap
1.1 HashMap
存储数据采用的哈希表结构,元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。(重要,最常用)
1.2 HashTable
和之前List集合中的 Vector 的功能类似,可以在多线程环境中,保证集合中的数据的操作安全,类中的方法大多数使用了 synchronized 修饰符进行加锁。(线程安全)
1.3 TreeMap
该类是 Map 接口的子接口 SortedMap 下面的实现类,和 TreeSet 类似,它可以对key值进 行排序,同时构造器也可以接收一个比较器对象作为参数。支持key值的自然排序和比较器排序俩种方 式。(支持key排序)
TreeMap 的使用(自然排序):
public static void main(String[] args) {
Map map = new TreeMap();
map.put(4,"mary");
map.put(2,"jack");
map.put(1,"tom");
map.put(3,"lucy");
Set keys = map.keySet();
for(Object key : keys){
System.out.println(key+" : "+map.get(key));
}
}
//运行结果:
1 : tom
2 : jack
3 : lucy
4 : mary
TreeMap 的使用(比较器排序):
public static void main(String[] args) {
Comparator c = new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Integer k1 = (Integer) o1;
Integer k2 = (Integer) o2;
//注意,这里在默认的比较结果基础上加了一个符号,即原来返回的正数变负 数、返回的负数变正数
return -k1.compareTo(k2);//(倒序)
}
};
//构造器中传入比较器对象
Map map = new TreeMap(c);
map.put(4,"mary");
map.put(2,"jack");
map.put(1,"tom");
map.put(3,"lucy");
Set keys = map.keySet();
for(Object key : keys){
System.out.println(key+" : "+map.get(key));
}
}
//运行结果:
4 : mary
3 : lucy
2 : jack
1 : tom
1.4LinkedHashMap
该类是 HashMap 的子类,存储数据采用的哈希表结构+链表结构。通过链表结构可 以保证元素的存取顺序一致;(存入顺序就是取出顺序)
LinkedHashMap 的使用:
public static void main(String[] args) {
Map map = new LinkedHashMap();
map.put(4,"mary");
map.put(2,"jack");
map.put(1,"tom");
map.put(3,"lucy");
Set keys = map.keySet();
for(Object key : keys){
System.out.println(key+" : "+map.get(key));
}
}
//运行结果:
4 : mary
2 : jack
1 : tom
3 : lucy
2.Map的遍历
public static void main(String[] args) {
Map map = new LinkedHashMap();
map.put(4,"mary");
map.put(2,"jack");
map.put(1,"tom");
map.put(3,"lucy");
Set entrySet = map.entrySet();
for(Object obj : entrySet){
Map.Entry entry = (Map.Entry) obj;
System.out.println(entry.getKey()+" : "+entry.getValue());
}
}
//运行结果:
4 : mary
2 : jack
1 : tom
3 : lucy
三.集合工具类
Collections 中的常用方法:
-
fill方法,使用指定元素替换指定列表中的所有元素
List list = new ArrayList(); list.add(1); list.add(2); list.add(3); Collections.fill(list, 20); for(Object o:list){ System.out.println(o); }
-
max方法,根据元素的自然顺序,返回给定集合的最大元素
List list = new ArrayList(); list.add(1); list.add(9); list.add(3); System.out.println(Collections.max(list));
-
min方法,根据元素的自然顺序,返回给定集合的最小元素
-
reverse方法,反转集合中的元素
List list = new ArrayList(); list.add(1); list.add(9); list.add(3); Collections.reverse(list); for(Object o:list){ System.out.println(o); }
-
sort方法,根据元素的自然顺序,对指定列表按升序进行排序
List list = new ArrayList(); list.add(1); list.add(9); list.add(3); //如果需要,也可以在第二个参数位置传一个比较器对象 //Collections.sort(list,c); Collections.sort(list); for(Object o:list){ System.out.println(o); }
-
shuffle方法,使用默认随机源对指定列表进行置换
-
addAll方法,往集合中添加一些元素
二.范型
使用范型代表任意一种数据类型 范型声明后才能使用,声明几个范型,就是使用几个范型,要么一起用,要么不用
1.定义范型类
[修饰符] class Point<V1,V2>{
V1 value1;
V2 value2;
}
构建对象的时候,对象引用上添加范型
Point<Integer,String> p = new XX();
2.定义范型接口
[修饰符] interface Point<X,Y>{
public Y getX(X x);
}
-
给范型接口提供实现类或者自接口的时候给范型类型(不常用)
-
给范型提供自接口或者是实现类的时候不给定具体的类型,还是用范型表示,当我们构建接口的实现类对象的时候在给定具体的类型
3.定义范型方法
当你写一个方法的时候,类上没有声明范型,但是方法中还想要使用范型,这时我们可以把方法声明成一个范型方法:传递什么类型返回什么类型
class className{
[修饰符] <T> T 方法名(T t){}
}
-
范型的语法规则:
1.声明和构建的时候保持范型类型一致(必须保证范型一摸一样)
2.申明范型的时候前面的引用添加范型,构建对象的范型可以省略
(范型只在编译阶段起作用,运行时会被去除)
三.枚举
交通信号灯:
public class Led{
public static Led RED= new Led();
public static Led yellow=new Led();
Public static Led green = new Led();
String color;
private Led(){}
}
Test:
main(){
Led red =Led.red;
}
枚举类:会将这个类能够构建的对象在这个类的第一行声明出来 枚举类构造器 私有的
枚举类的声明语法
[修饰符] enum 类名{
//枚举类必须在【第一行】把这个类所有的对象生声明出来
//枚举类所有的构造器都是私有的
//定义属性
//定义方法
}
枚举类的实质:
一旦使用enum声明一个类,那么这个类会默认继承Enum类
public enum Color {
BLACK, WHITE
}
四.反射
1.Student类如何产生:
所有的学生共同拥有的特性使用Java语言表示称一个类 因此这个类就可以用来描 述Java中任何一个Student学生
由这个类产生的对象就是一个具体学生
2.Teacher类如何产生:
所有的老师共同拥有的特性使用Java语言表示称一个类
因此这个类就可以用来描述Java中任何一个老师特性
由这个类产生的对象就是一个具体老师
3.Student类 Teacher类
3.1共性:包 修饰符 类名 继承父类 实现接口 属性 方法 构造器
3.2Class :这个类是总结了Java所有的类/接口具备的特性,抽象而成的一个类,因此这 个类可以用来描述Java中任意一个类,Class类产生的对象就是Java中的某个具体类
使用Class类的对象来表示基本类型:
public static void main(String[] args)throws Exception {
//这个对象c就代表java中的int类型
Class c = int.class;
//判断对象c所代表的类型是否是基本类型
System.out.println(c.isPrimitive());
//获取对象c所代表的类型的名字
System.out.println(c.getName());
}
//运行结果:
true
int
使用Class类的对象来表示类类型:
public static void main(String[] args)throws Exception {
//这个对象c就代表Student类
Class c = Student.class;
System.out.println(c.getName());
}
//运行结果:
com.briup.demo.Student
使用Class类的对象来表示接口类型:
public static void main(String[] args)throws Exception {
//这个对象c就代表List接口类型
Class c = List.class;
System.out.println(c.isInterface());
System.out.println(c.getName());
}
//运行结果:
true
java.util.List
使用Class类的对象来表示数组类型:
public static void main(String[] args)throws Exception {
//这个对象c代表数组类型
Class c;
c = int[].class;
c = int[][].class;
c = Student[].class;
System.out.println(c.isArray());
System.out.println(c.getSimpleName());
//返回组成该数组具体类型是什么
System.out.println(c.getComponentType().getSimpleName());
}
//运行结果:
true
Student[]
Student
获取Class对象
java中的每种类型,都有且只有唯一的一个Class类型对象与之对应!并且在类加载的时候自动生成!
获取基本类型的Class对象:
只有一种方式: Class c = int.class;
获取接口类型的Class对象:
有俩种方式:
- Class c1 = Action.class;
- Class c2 = Class.forName(“com.briup.demo.Action”);
获取数组类型的Class对象:
有俩种方式:
- Class c1 = int[].class;
- int[] arr = new int[4]; Class c2 = arr.getClass();
获取类类型的Class对象:
有三种方式:
- Class c1 = Student.class;
- Class c2 = Class.forName(“com.briup.demo.Student”);
- Student stu = new Student(); Class c3 = stu.getClass();
3.3属性: 修饰符 数据类型 属性名 属性值
3.4Filed:这个类是总结了Java所有的属性共同具备的特性,所以这个类就是用来描述 Java中任意一个属性,产生的对象某个具体属性
3.5Method:修饰符 返回类型 方法名 参数列表 抛出异常 返回值
这个类是总结了Java所有的方法共同具备的特性,所以这个类就是用来描述Java中任意一个方法,产生的对象某个具体方法
3.6构造器: 修饰符 方法名 参数列表
3.7Constructor: 这个类是总结了Java所有的构造器共同具备的特性,所以这个类
就是用来描述Java中任意一个构造器,产生的对象某个具体构造器
4.反射调用方法
public static void main(String[] args)throws Exception {
Student stu = new Student();
Class c = stu.getClass();
//获取类中的toString方法,没有参数,这是从父类继承的方法
Method m1 = c.getMethod("toString", null);
//反射的方式,调用stu对象中的这个方法,没有参数,并接收执行结果
//相当于之前的:Object result = stu.toString();
Object result = m1.invoke(stu,null);
//输出执行结果
System.out.println(result);
System.out.println("-------------------");
//获取类中的sayHello方法,需要一个String类型的参数,这是自己定义的方法
Method m2 = c.getMethod("sayHello", String.class);
//反射的方式,调用stu对象中的这个方法,参数是"tom",并接收执行结果
//相当于之前的:Object result = stu.sayHello("tom");
result = m2.invoke(stu,"tom");
//输出执行结果
System.out.println(result);
}