目录
一、集合
Collection接口:
List子接口:ArrayList实现类 Vector实现类 LinkedList实现类
Set子接口: HashSet实现类:LinkedHashSet子类
TreeSet实现类
Map接口:
HashMap实现类:LinkedHashMap子类
Hashtable实现类:Properties子类
TreeMap实现类
Collections工具类:
二、Collection接口
public interface Collection<E> extends Iterable<E>
Collection l = new ArrayList();
//添加元素,返回布尔值,对象名.add();
l.add(0);
l.add("a");
l.add(true);
//获取集合的元素个数,对象名.size();
l.size();
//删除某个元素,返回布尔值,对象名.remove(元素);如有多个目标值,删除前面的哪一个
l.remove("a");
//判断集合是否包含某个元素,返回布尔值,对象名.contains(元素);
l.contains("a");
//判断集合是否为空,返回布尔值,对象名.isEmpty();
l.isEmpty();
Collection list = new ArrayList();
//添加一个集合到另一个集合,返回布尔值,对象名.addAll(集合);
list.addAll(l);
//判断一个集合是否包含另一个集合的所有元素,返回布尔值,对象名.containsAll(集合);
l.containsAll(list);
//在一个集合中删除另一个集合中所包含的元素,返回布尔值,对象名.removeAll(集合);
l.removeAll(list);
//清空集合,对象名.clear();
l.clear();
1、Iterator迭代器
(1)主要用于遍历Collection集合中的元素
(2)所有实现了Collection接口的类都有一个iterator()方法,用于返回一个实现了Iterator接口的对象,即可以返回一个迭代器
Collection l = new ArrayList();
l.add(0);
l.add("a");
l.add(true);
Iterator i = l.iterator(); //此时i指向地址
while (i.hasNext()) { //hasNext():判断是否有下一个元素,返回布尔值
Object o = i.next(); //next():指针下移,返回下移以后位置上的元素
System.out.println(o);
}
i = l.iterator(); //重置迭代器
2、for each
for(元素类型 元素名:集合名或数组名){ } 底层仍然是迭代器
Collection l = new ArrayList();
l.add(0);
l.add("a");
l.add(true);
for (Object o :l) {
System.out.println(o);
}
3、for(编译类型需要时List,因为List支持索引)
List l = new ArrayList();
l.add(0);
l.add("a");
l.add(true);
for (int i = 0; i < l.size(); i++) {
System.out.println(l.get(i));
}
三、List子接口
(1)List集合中的元素有序,添加顺序和取出顺序一致
(2)List集合中的元素可重复
(3)List集合中的每个元素都有其对应的顺序索引,即支持索引,从0开始
List l = new ArrayList();
l.add("a");
l.add("b");
l.add("b");
//获取指定位置元素,对象名.get(索引);
l.get(0);
//添加指定位置元素,对象名.add(索引,元素);
l.add(2,"c");
//修改某个位置的元素,返回修改前的元素,对象名.set(索引,元素);
l.set(3, "d");
//删除指定位置的元素,返回被删除的元素,对象名.remove(索引);
l.remove(3);
//获取元素在集合中首次出现的位置,对象名.indexOf(元素);
l.indexOf("b");
//获取元素在集合中最后一次出现的位置,对象名.lastIndexOf(元素);
l.lastIndexOf("b");
//返回一个子集合,对象名.subList(a,b); [a,b)
l.subList(0,1);
List list = new ArrayList();
//在指定位置添加另一个集合中的所有元素,返回布尔值,对象名.addAll(索引,集合);
list.addAll(0, l);
1、ArrayList
(1)ArrayList线程不安全,执行效率高
(2)ArrayList中维护了一个Object类型的数组elementDate
transient Object[] elementDate;
(3)创建ArrayList对象时,如果使用的是无参构造器,则初始elementDate的容量为0,第一次添加,则扩容elementDate为10,再次扩容,则扩容为elementDate的1.5倍
(4)创建ArrayList对象时,如果使用的是有参构造器,则初始elementDate的容量为指定大小,再次扩容,则扩容为elementDate的1.5倍
2、Vector
(1)Vector线程安全,执行效率不高
(2)Vector中维护了一个Object类型的数组elementDate
protected Object[] elementDate;
(3)创建Vector对象时,如果使用的是无参构造器,则初始elementDate的容量为0,第一次添加,则扩容elementDate为10,再次扩容,则扩容为elementDate的2倍
(4)创建Vector对象时,如果使用的是有参构造器,则初始elementDate的容量为指定大小,再次扩容,则扩容为elementDate的2倍
3、LinkedList
(1)线程不安全
(2)底层实现了双向链表,LinkedList维护了first和last分别指向头节点和尾节点,每个节点又维护了prev,next,item三个属性
LinkedList l = new LinkedList();
四、Set子接口
(1)Set集合中的元素无序,添加顺序和取出顺序不一致,但取出的顺序是固定的
(2)Set集合中的元素不可重复,添加重复元素编译器不会报错,只是添加失败
(3)Set集合中的每个元素没有索引
1、HashSet
(1)HashSet底层是HashMap,HashMap底层是数组+链表,红黑树
(2)添加一个元素时,先得到这个元素的hash值(hashCode方法),hash值会转成索引值,找到存储数据表table,看这个索引位置是否已经存放元素,如果没有,直接加入,如果有,调用equals方法依次比较,如果相同,就放弃添加,如果不相同,则添加到最后,
(3)如果一条链表元素个数达到一个默认值,并且table大小达到一个默认值,就会进行红黑树化
2、LinkedHashSet
(1)LinkedHashSet底层是LinkedHashMap,LinkedHashMap底层是数组+双向链表
(2)同样根据元素的hash值决定元素的存储位置,同时使用双向链表维护元素的次序,使得元素看起来是以添加顺序保存的
3、TreeSet
用无参构造器,创建TreeSet时,输出仍然是无序的
可通过有参构造器,可以传入一个比较器(匿名内部类),然后指定输出的排序规则
TreeSet t = new TreeSet(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((String) o2).compareTo((String) o1);
}
});
t.add("d");
t.add("b");
t.add("a");
t.add("c");
五、Map接口
(1)用于保存具有映射关系的数据:Key-Value(双列元素)
(2)Key和Value可以是任何引用类型的数据
(3)常用String类作为Map的key
(4)Key和Value都可以为null,但key只能有一个null,value可以都多个null
(5)Key不允许重复,Value可以重复,如果Key重复,新的Key的Value会对先前Key的Value进行覆盖
(6)Key和Value之间存在单向一对一关系,即通过指定的key总能找到对应的value
(7)一对k-v是封装在一个HashMap$Node对象中的,因为Node实现了Entry接口
Map m = new HashMap();
//添加元素,返回布尔值,对象名.put(Key,Value);
m.put("1","a");
m.put("2","b");
m.put("3","b");
m.put("3","c");
//删除某个元素,返回布尔值,对象名.remove(Key);
m.remove("3");
//获取某个元素,对象名.get(Key);
m.get("3");
//获取集合的元素个数,对象名.size();
m.size();
//判断集合是否为空,返回布尔值,对象名.isEmpty();
m.isEmpty();
//判断一个key是否存在,返回布尔值,对象名.containsKey(key);
m.containsKey("3");
//获取所有key,返回Set类型,对象名.keySet();
m.keySet();
//获取所有Value,返回Collection类型,对象名.values();
m.values();
//获取所有k-v,返回Set类型,对象名.entrySet();
m.entrySet();
//清空集合,对象名.clear();
m.clear();
(8)Map遍历
Map m = new HashMap();
m.put("1", "a");
m.put("2", "b");
m.put("3", "c");
//通过得到存放Key值的Set对象
Set s = m.keySet();
Iterator i = s.iterator();
while (i.hasNext()) {
Object key = i.next();
System.out.println(key);
System.out.println(m.get(key));
}
for (Object key : s) {
System.out.println(key);
System.out.println(m.get(key));
}
Map m = new HashMap();
m.put("1", "a");
m.put("2", "b");
m.put("3", "c");
//通过得到存放Value值的Collection对象
Collection c = m.values();
Iterator i = c.iterator();
while (i.hasNext()) {
Object o = i.next();
System.out.println(o);
}
for (Object o :c) {
System.out.println(o);
}
Map m = new HashMap();
m.put("1", "a");
m.put("2", "b");
m.put("3", "c");
//通过得到存放K-V的Set对象
Set s = m.entrySet();
Iterator i = s.iterator();
while (i.hasNext()) {
Object o = i.next();
Map.Entry e = (Map.Entry) o;
System.out.println(e.getKey());
System.out.println(e.getValue());
}
for (Object o :s) {
Map.Entry e = (Map.Entry) o;
System.out.println(e.getKey());
System.out.println(e.getValue());
}
1、HashMap
(1)HashMap底层是数组+链表,红黑树
(2)线程不安全
(3)HashMap底层维护了Node类型的数组table,默认为null
(4)当创建对象时,将加载因子(loadfactor)初始化为0.75
(5)当添加key-val时,通过key的哈希值得到在table的索引。然后判断该索引处是否有元素,如果没有元素直接添加。如果该索引处有元素,继续判断该元素的key和准备加入的key是否相等,如果相等,则直接替换val,如果不相等需要判断是树结构还是链表结构,做出相应处理。如果添加时发现容量不够,则需要扩容
(6)第1次添加,则需要扩容table容量为16,临界值(threshold)为12(16*0.75)
(7)以后再扩容,则需要扩容table容量为原来的2倍(32),临界值为原来的2倍,即24,依次类推
(8)如果一条链表的元素个数超过TREEIFT_THRESHOLD(默认是8),并且table的大小>=MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树)
2、Hashtable
(1)线程安全
(2)Hashtable的key和value都不能为null,否则会抛出空指针异常
3、TreeMap:
用无参构造器,创建TreeMap时,输出仍然是无序的
可通过有参构造器,可以传入一个比较器(匿名内部类),然后指定输出的排序规则
TreeMap t = new TreeMap(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((String)o2).compareTo((String)o1);
}
});
t.put("d",2);
t.put("b",4);
t.put("a",6);
t.put("c",7);
六、Collections工具类
Collections是一个操作List、Set、Map等集合的工具类,提供一系列静态方法对集合元素进行操作
List l = new ArrayList();
l.add("a");
l.add("b");
l.add("c");
//反转list元素的顺序:reverse
Collections.reverse(l);
//对list元素进行随机排序:shuffle
Collections.shuffle(l);
//对list元素进行升序排序:sort
Collections.sort(l);
//对list元素按字符串长度大小排序:sort
Collections.sort(l, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((String)o1).length()-((String)o2).length();
}
});
//指定集合中i处和j处的元素交换:swap
Collections.swap(l,0,2);
//根据元素的自然排序,返回给定集合中的最大/最小元素:max min
Collections.max(l);
//返回给定集合中长度最大/最小的元素:max min
Collections.max(l, new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
return ((String)o1).length()-((String)o2).length();
}
});
//返回给定集合中某个元素出现的次数:frequency
Collections.frequency(l,"a");
//将一个集合复制到另一个集合中:copy
List t = new ArrayList();
for (int i = 0; i < l.size(); i++) {
t.add(""); //为了完成完整拷贝,需要给t赋值,大小和l一样
}
Collections.copy(t,l);
//使用新元素替换旧元素:replaceALL
Collections.replaceAll(l,"c","d");
七、泛型
(1)约束集合只存放某种引用类型,后面的 <引用类型> 可以不写
ArrayList<String> a = new ArrayList<String>();
ArrayList<String> a = new ArrayList<>();
ArrayList<String> a = new ArrayList();
(2)泛型没有继承性
ArrayList<Object> a = new ArrayList<String>(); //报错
(3)? extends super
public class Test {
public static void main(String[] args) {
List<Object> l1 = new ArrayList<>();
List<A> l2 = new ArrayList<>();
List<B> l3 = new ArrayList<>();
List<C> l4 = new ArrayList<>();
n1(l1);
n1(l2);
n1(l3);
n1(l4);
n2(l1); //报错
n2(l2);
n2(l3);
n2(l4);
n3(l1);
n3(l2);
n3(l3); //报错
n3(l4); //报错
}
//<?>接收任意类
public static void n1(List<?> l){
}
//<? extends A>接收A及A的子类
public static void n2(List<? extends A> l){
}
//<? super A>接收A及A的父类
public static void n3(List<? super A> l){
}
}
class A {
}
class B extends A {
}
class C extends B {
}
1、自定义泛型类
(1)在类声明时通过标识表示类中某个成员的引用类型,成员变量/成员方法可以使用泛型
(2)使用泛型的数组,不能初始化,不确定类型,内存不知道分配多少的空间
(3)静态成员中不能使用泛型
(4)创建对象时指定类型,没有指定类型,默认为Object
public class Test {
public static void main(String[] args) {
A<String,Integer> a = new A<>();
a.t = "String";
a.r = 1;
a.n("123");
}
}
class A<T,R> {
T t;
R r;
//非泛型方法,使用了类的泛型
public T n(T t,R r) {
return t;
}
//非泛型方法,使用了类的泛型
public A<T,R> m(T t,R r){
A<T,R> a = new A<>();
return a;
}
//无参构造器
public A() {
}
//有参构造器
public A(T t, R r) {
this.t = t;
this.r = r;
}
}
(5)给泛型指定具体类型后,可以传入该类型或其子类类型
public class Test {
public static void main(String[] args) {
A<B> a1 = new A<B>(new B());
A<B> a2 = new A<B>(new C());
}
}
class A<E> {
public A(E e) {
this.e = e;
}
}
class B {
}
class C extends B {
}
2、自定义泛型接口
(1)在接口声明时通过标识表示类中某个成员的引用类型,成员方法/默认方法可以使用泛型
(2)静态成员中不能使用泛型
(3)继承或实现接口时指定类型,没有指定类型,默认为Object
interface A<T, R> {
T n1(R r);
default T n2(R r) {
return null;
}
}
interface B extends A<String, Integer> {
}
class C implements B {
@Override
public String n1(Integer integer) {
return null;
}
}
class D implements A<String, Integer> {
@Override
public String n1(Integer integer) {
return null;
}
}
3、自定义泛型方法
(1)泛型方法可以定义在普通类中,也可以定义在泛型类中
(2)泛型方法被调用时确定类型
(3)泛型方法既可以使用自己声明的泛型,也可以使用类声明的泛型
public class Test {
public static void main(String[] args) {
new Test().run("String");
}
public <T> void run1(T t){
System.out.println(t);
}
public static <T> void run2(T t){
System.out.println(t);
}
}
class A<T> {
private T t;
//泛型类中的泛型方法的泛型T与类中的泛型T没有任何关系,可以是不同的类型
public <T> void a(T t) {
}
//泛型类中的静态泛型方法的泛型R与类中的泛型T没有任何关系,可以是不同的类型
public static <R> void b(R r) {
}
//泛型类中的静态方法如果想使用类中的泛型,需要将这个方法定义成泛型方法
public static <T> T c(T t) {
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
public A() {
}
public A(T t) {
this.t = t;
}
}
八、反射
1、反射机制
允许程序在执行期间借助于Reflection API取得任何类的内部信息并能操作对象的属性和方法
(1)可以判断任意一个对象所属的类
(2)可以构造任意一个类的对象
(3)可以得到任意一个类所具有的成员变量和方法
(4)可以调用任意一个对象的成员变量/方法
(5)生成动态代理
2、反射相关类
(1)java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象
(2)java.lang.reflect.Method:代表类的方法,Method对象表示某个类的方法
(3)java.lang.reflect.Field:代表类的成员变量,Field对象表示某个类的成员变量
(4)java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示某个类的构造器
(5)反射调用性能优化:Method,Field,Constructor对象都有setAccesssible()方法,作用是启动和禁用访问安全检查的开关,参数值为true时,反射的对象在使用时取消访问检查,提高反射的效率,反之
Properties p = new Properties();
p.load(new FileInputStream("D:\\code\\studyjava\\src\\set.properties"));
String classPath = p.getProperty("classPath");
String methodName = p.getProperty("methodName");
String fieldName = p.getProperty("fieldName");
//通过Class类的方法forName加载类,返回Class类的对象(一个类只有一个Class对象)
Class c = Class.forName(classPath);
//返回加载类的对象
Object o = c.newInstance();
//返回Method类的对象,通过Method类的对象调用
Method m = c.getMethod(methodName);
m.invoke(o);
//返回Field类的对象,通过Field类的对象调用(不能得到私有的属性)
Field f = c.getField(fieldName);
f.get(o);
//返回无参/有参构造器
Constructor c1 = c.getConstructor();
Constructor c2 = c.getConstructor(String.class);
//取消访问检查
m.setAccessible(true);
f.setAccessible(true);
c1.setAccessible(true);
c2.setAccessible(true);
3、Class类
(1)Class类对象不是new出来的,而是系统创建的
//用于配置文件:forName方法
Class c1 = Class.forName("com.javastudy.Cat");
//用于参数传递:类名.class
Class c2 = Cat.class;
//用于已有对象实例
Cat cat = new Cat();
Class c3 = cat.getClass();
//通过类加载器
ClassLoader classLoader = cat.getClass().getClassLoader();
Class c4 = classLoader.loadClass("com.javastudy.Cat");
//基本数据类型.class
Class c5 = int.class;
//基本数据类型对应的包装类.TYPE
Class c6 = Integer.TYPE;
System.out.println(c5==c6);
(2)对于某个类的Class类对象,因为类只加载一次,在内存中只有一份,存放在堆中
(3)每个类的实例都会记得自己由哪个Class的实例所生成
(4)通过Class可以完整地得到一个类的完整结构
//获取Cat类对应的Class对象
Class c = Class.forName("com.javastudy.Cat");
//输出c是哪个类的Class对象
System.out.println(c);
//输出c的运行类型
System.out.println(c.getClass());
//得到包名
c.getPackage().getName();
//得到全类名
c.getName();
//通过c创建对象实例
Object object = c.newInstance();
Cat cat = (Cat) c.newInstance();
//通过c获取成员变量
Field[] fields = c.getFields();
Field f = c.getField("name");
//通过c修改成员变量,cat对象的f属性设置成jack
f.set(cat,"Jack");
(5)外部类,内部类,接口,数组,二维数组,注解,枚举,基本数据类型,void,都有对应的class对象
4、类加载
(1)静态加载:编译时加载相关的类,
(2)动态加载:运行时加载相关的类
5、反射获取类的结构信息
Class c = Cat.class;
//获取全类名
c.getName();
//获取简单类名
c.getSimpleName();
//获取所有public修饰的属性,包含本类以及父类的
c.getFields();
//获取本类中所有属性
c.getDeclaredFields();
//获取所有public修饰的方法,包含本类以及父类的
c.getMethods();
//获取本类中所有方法
c.getDeclaredMethods();
//获取所有public修饰的构造器,包含本类不包含父类的
c.getConstructors();
//获取本类中所有构造器
c.getDeclaredConstructors();
//以Package形式返回包信息
c.getPackage();
//以Class形式返回父类信息
c.getSuperclass();
//以Class[]形式返回接口信息
c.getInterfaces();
//以Annotation[]形式返回注解信息
c.getAnnotations();
Class c = Cat.class;
Field f = c.getField("name");
//以int形式返回属性的修饰符,默认:0,public:1,private:2,protected:4
//static:8,final:16,多个修饰数值相加
System.out.println(f.getModifiers());
//以Class形式返回属性的类型
System.out.println(f.getType());
//返回属性名
System.out.println(f.getName());
Class c = Cat.class;
Method m = c.getMethod("run");
//以int形式返回方法的修饰符,默认:0,public:1,private:2,protected:4
//static:8,final:16,多个修饰数值相加
System.out.println(m.getModifiers());
//以Class形式返回方法的返回类型
System.out.println(m.getReturnType());
//返回方法名
System.out.println(m.getName());
//以Class[]返回方法的参数类型数组
m.getParameterTypes();
Class c = Cat.class;
Constructor cs = c.getConstructor();
//以int形式返回构造器的修饰符,默认:0,public:1,private:2,protected:4
//static:8,final:16,多个修饰数值相加
System.out.println(cs.getModifiers());
//返回构造器名
System.out.println(cs.getName());
//以Class[]返回构造器的参数类型数组
cs.getParameterTypes();
6、通过反射机制创建对象
public class TestA {
public static void main(String[] args) throws Exception {
Class c = Cat.class;
//通过public的无参构造器
Object o1 = c.newInstance();
//通过public的有参构造器
Constructor cs1 = c.getConstructor(String.class);
Object o2 = cs1.newInstance("Jack");
//通过非public的有参构造器
Constructor cs2 = c.getDeclaredConstructor(String.class,int.class);
cs2.setAccessible(true); //暴破:使用反射可以访问private构造器
Object o3 = cs2.newInstance("Bob",20);
}
}
class Cat {
private String name = "Tom";
private int age = 10;
public void run() {
System.out.println(1);
}
public Cat() {
}
public Cat(String name) {
this.name = name;
}
private Cat(String name, int age) {
this.name = name;
this.age = age;
}
}
public class TestA {
public static void main(String[] args) throws Exception {
Class c = Cat.class;
Object o = c.newInstance();
//通过反射得到age属性对象
Field f1 = c.getField("age");
f1.get(o);
//通过反射操作属性
f1.set(o,20);
//操作私有的属性,暴破
Field f2 = c.getDeclaredField("name");
f2.setAccessible(true);
f2.get(o);
f2.set(o,"Jack");
f2.set(null,"Bob"); //因为name是static属性,因此o也可以写成null
}
}
class Cat {
private static String name = "Tom";
public int age = 10;
public void run() {
System.out.println(1);
}
public Cat() {
}
public Cat(String name) {
this.name = name;
}
private Cat(String name, int age) {
this.name = name;
this.age = age;
}
}
public class TestA {
public static void main(String[] args) throws Exception {
Class c = Cat.class;
Object o = c.newInstance();
//通过反射得到方法run
Method m1 = c.getMethod("run");
//如果方法有返回值,统一返回Object
Object returenValue = m1.invoke(o);
System.out.println(returenValue);
//操作私有的方法,暴破
Method m2 = c.getDeclaredMethod("walk", int.class);
m2.setAccessible(true);
m2.invoke(null,2);
}
}
class Cat {
public int run() {
System.out.println(1);
return 1;
}
private static void walk(int n) {
System.out.println(n);
}
}