集合
集合的好处
数组
1、长度开始时必须指定,而且一旦指定,不能更改
2、保存的必须为同一类型的元素
3、使用数组进行增加元素的
Person数组扩容示意代码
Person[] pers = new Person[1];
per[0] = new Person();
重新创建数组
collection
1、可以动态保存任意多个对象,使用比较方便
2、提供了一系列方便的操作对象的方法: add,remove,set,get等
3、使用集合添加,删除新原色的示意代码- 简洁
集合框架图
1、集合主要分两种(单列集合、双列集合)
2、collection 接口有两个重要的子接口 List Set 他们的实现子类都是单列集合
3、Map 接口实现的子类 是双列集合 存放的K-V
collection接口和常用方法
public interface Collection<E> extends Iterable<E>
1、collection实现子类可以存放多个元素,每个元素可以是Object
2、有些collection的实现类,可以存放重复的元素,有些不可以
3、有些Collection的实现类,有些是有序(list) 有些不是有序(Set)
4、Collection接口没有直接的实现子类,是通过他的子接口Set和List来实现的
方法:
remove 删除指定元素
contains 查询元素是否存在
size 获取元素个数
isEmpty 判断是否为空
clear 清空
addAll 添加多个元素
containsAll 查询多个元素是否存在
removeAll 删除多个元素
collection遍历元素的方式
1、Iterator对象称为迭代器,主要用于遍历Collection集合中的元素
2、所有实现了Collection接口的集合类都有一个iterator()的方法,用于返回一个实现Iterator接口的对象,即可以返回一个迭代器
3、Iterator的结构(看一张图)
4、Iterator仅用于遍历集合,Iterator本身并不存放对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a9HSccZM-1644162092695)(D:\web\git\document\assets\image-20211228162935270.png)]
增强for循环
底层 还是迭代器
增强for 也是就简化版的迭代器
for(Object book:col){
System.out.println()
}
List
List接口基本介绍
1、List集合类中元素有序(即添加顺序和取出顺序一致)、且可重复
2、List集合中的每个元素都有其对应的顺序索引,即支持索引
3、List容器中的元素都对应一个整数型的序号记载骑在容器中的位置,可以根据序号存取容器中的元素
方法:
void add(int index,Object ele) 在index位置插入ele
void addAll(int index,Object eles) 在index位置插入eles的所有元素
Object get(int index) 获取指定位置的元素
int indexOf(Object obj) 返回obj在集合中首次出现的位置
int lastIndexOf(Object obj) 返回指定元素最后一次出现的位置
Object remove(int index) 移除此元素,并返回此元素
ArrayList
标记接口(注解也可以实现):空接口
RandomAccess:说明该类支持随机访问,大部分是基于数组实现
遍历方式:for 迭代器
Cloneable:说明该类支持拷贝
深拷贝:
浅拷贝:直接使用Object中的clone方法,拷贝出来的对象不是一个独立对象
传值方式:1、基本类型和String变量是值传递
2、引用类型是引用传递
java.io.Serializable:将对象存入网络传输、写磁盘。
反序列化:从磁盘或者网络读取对象
serialVersionUID:类文件的指纹(签名) md5 写死就不会重新签名
transient Object[] elementData; 实际存储元素的地方
数组长度:长度不可变,内存是连续的,只能存储相同类型的元素
(数组中的元素占用的内存空间是相同的,对象时存的内存地址
DEFAULTCAPACITY_EMPTY_ELEMENTDATA:节省空间 说明调的是无参构造器,默认容量是10(第一次添加元素时初始化容量是10)
elementData:实际存储元素的地方
calculateCapacity(elementData, minCapacity):确定需要多少容量
ArrayList 线程安全
iterator:
扩容:生成一个新数组,赋值给elementData 解决数组长度不可变的问题
cursor:游标
游标:保存了一个下标值
modCount != expectedModCount
说明list发生了变化,导致脏读 fail-fast机制
spliterator
modCount:操作数
SubList
n
Vecator
Set
HashSet
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-okXF3jTG-1644162092697)(D:\web\git\document\assets\image-20220101231920952.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AwaIfVhH-1644162092698)(D:\web\git\document\assets\image-20220101232238769.png)]
1、HashSet 实现Set类
2、HashSet实际上是HashMap
3、可以存放null值,但是只有一个null
4、HashSet不保证元素有序的,取决于hash后,再确定索引的结果
5、不能有重复元素/对象
说明:底层是hashMap,HashMap底层是(数组+链表+红黑树)
HashSet源码解读
1、执行 HashSet()
public HashSet() {
map = new HashMap<>();
}
2、执行 add()
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
3、执行 put() 该方法会执行hash(key) 得到key对应 的hash值 算法h = key.hashCode()) ^ (h >>> 16);
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
4、执行 putVal
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab;
Node<K,V> p;
int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e;
K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1)
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) {
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
LinkedHashSet
1、LinkedHashSet是HashSet的子类
2、LinkedHashSet底层是一个LinkedHashMap,底层维护了一个数组+双向链表
3、LinkedHashSet根据元素的HashCode值决定元素的存储位置,同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的
4、LinkedHashSet不允许添重复元素
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TSAw0JWY-1644162092700)(D:\web\git\document\assets\image-20220102110811939.png)]
Map
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KENl181n-1644162092702)(D:\web\git\document\assets\image-20220102121404974.png)]
1、双列元素(K-V)
2、
注解和反射
注解可以被其他程序读取
常用的注解
@Override 重写超类中的另一个方法声明
@Deprecated 不鼓励使用
@SuppressWarnings 抑制编译时的警告信息 参数(“all”,“unchecked”,"")
元注解
元注解的作用就是负责注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型作说明
@Target 用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
@Retention 表示需要在什么级别保存改注释信息,用于描述注解的生命周期(source<class<runtime)
@Document 说明改注解将被包含在javadoc中
@Inherited 说明子类可以继承父类中的该注解
自定义注解
使用@Interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
1、@Interface用来声明一个注解,格式:pubic @Interface 注解名(定义内容)
2、其中的每个方法实际上是声明了一个配置参数
3、方法的名称就是参数的名称
4、返回值类型就是参数的类型(返回值只能是基本类型:class,String,enum)
5、可以通过default来声明参数的默认值
6、如果只有一个参数成员,一般参数名为value
7、注解元素必须要写值,我们定义注解元素是,经常使用空字符串,0作为默认值
public class annocation {
@SecAnnotation("默认")
@MyAnnotation(age = 12)
public void test(){
}
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.CLASS)
@interface MyAnnotation{
String name() default "小米";
int age();
String[] schools() default {"第一","第二"};
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.CLASS)
@interface SecAnnotation{
String value();
}
反射机制
动态语言
javaScript
静态语言
Java不是动态语言,但可以称之为"准动态语言"
Java Reflection
Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
Class c = class.forName("java.lang.String")
加载完类之后,在堆内存的方法中就产生了一个Class类型的对象(一个类只要有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们称之为:反射
反射方式:
实例化对象————》getClass()方法——————》得到完整的“包类”名称
Java反射机制提供的功能
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时获取泛型信息
- 在运行时调用任意一个对象的成员变量和方法
- 在运行时处理注解
- 生成动态代理
优缺点
缺点:
- 对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于 直接执行相同的操作。
主要API
- java.lang.Class 代表一个类
- java.lang.reflect.Method 代表类的方法
- java.lang.reflect.Field 代表类的成员变量
- java.lang.reflect.Constructor 代表类的构造器
Class类
在Object类中定义了一下的方法,此方法将被所有子类继承
public final Class getClass()
对象照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现类哪些接口。对于每个类而言,JRE都为其保留一个不变的Class类型的对象。一个Class对象包含了特定某个结构
- Class本身也是一个类
- Class对象只能由系统建立对象
- 一个加载的类在JVM中只会有一个Class实例
- 一个Class对象对应的是一个加载到JVM中的一个class文件
- 每个类的实例都会记得自己是由哪个Class实例所生成
- 通过Class可以完整地得到一个类中的所有被加载的结构
- class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获取相应的Class对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yxIG0tNQ-1644162092705)(D:\web\git\document\assets\image-20220120162801518.png)]
获取Class类的实例
- 若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高
Class clazz = Person.class
- 已知某个类的实例,调用该实例的getClass()方法获取Class对象
Class clazz = person.getClass();
- 已知一个类的全类目,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
Class clazz = Class.forName("demo1.student")
- 内置基本数据类型可以直接用类名.Type
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException {
Class c1 = Class.forName("com.test.study.reflect.User");
System.out.println(c1);
Class c2= Class.forName("com.test.study.reflect.User");
Class c3 = Class.forName("com.test.study.reflect.User");
Class c4 = Class.forName("com.test.study.reflect.User");
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
System.out.println(c4.hashCode());
User user = new User();
Class d1 = user.getClass();
System.out.println(d1.hashCode());
Class d2 = Class.forName("com.test.study.reflect.User");
System.out.println(d2.hashCode());
Class userClass = User.class;
System.out.println(userClass.hashCode());
Class<Integer> type = Integer.TYPE;
System.out.println(type);
Class d5 = d1.getSuperclass();
System.out.println(d5);
}
}
class User extends Object{}
哪些类型可以有Class对象?
- Class:外部类,成员(成员内部类、静态内部类),局部内部类,匿名内部类
- interface:接口
- [] 数组
- enum : 枚举
- annotation: 注解@interface
- primitive type: 基本数据类型
- void
Class c1 = Object.class;
Class c2 = Comparable.class;
Class c3 = String[].class;
Class c4 = int[][].class;
Class c5 = Override.class;
Class c6 = ElementType.class;
Class c7 = Integer.class;
Class c8 = void.class;
Class c9 = Class.class;
========================
class java.lang.Object
interface java.lang.Comparable
class [Ljava.lang.String;
class [[I
interface java.lang.Override
class java.lang.annotation.ElementType
class java.lang.Integer
void
class java.lang.Class
Java内存
堆
- 存放new的对象和数组
- 可以被所有的线程共享,不会存放别的对象引用
栈
- 存放基本变量类型(会包含这个基本类型的具体数值)
- 引用对象的变量(会存放这个引用在堆里面的具体地址)
方法区
- 可以被所有的线程共享
- 包含了所有的class和static变量
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xeC04CDb-1644162092706)(D:\web\git\document\assets\image-20220120192018210.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N6ZAzvad-1644162092706)(D:\web\git\document\assets\image-20220120233339652.png)]
public class Test05 {
public static void main(String[] args) {
A a = new A();
System.out.println(a);
}
}
class A{
static {
System.out.println("A类静态代码块");
m = 300;
}
static int m = 100;
public A(){
System.out.println("A类的无参构造初始化");
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pBqBJGOV-1644162092707)(D:\web\git\document\assets\image-20220121001355404.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yWjiYGDk-1644162092708)(D:\web\git\document\assets\image-20220121001421379.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zVX6iPSB-1644162092710)(D:\web\git\document\assets\image-20220121001804204.png)]
// 通过反射获取类的Class对象
Class c1 = Class.forName("com.test.study.reflect.User");
// 获得类的名字
System.out.println(c1.getName()); // 获得包名 + 类名
System.out.println(c1.getSimpleName()); // 获得类名
// 获得类的属性
Field[] fields = c1.getFields(); // 只能找到public属性
fields = c1.getDeclaredFields(); // 找全部的属性
for(Field field:fields){
System.out.println(field);
}
// 获得指定属性的值
Field name = c1.getDeclaredField("name");
System.out.println(name);
// 获得类的方法
Method[] methods = c1.getMethods(); // 获得本类及其父类的全部public方法
for (Method method: methods) {
System.out.println("正常的"+method);
}
methods = c1.getDeclaredMethods(); // 获得本类的所有方法
for (Method method: methods) {
System.out.println("getDeclaredMethods"+method);
}
// 获得指定方法
Method getName = c1.getMethod("getName", null);
Method setName = c1.getMethod("setName", String.class);
System.out.println(getName);
System.out.println(setName);
// 获得指定的构造器
System.out.println("======================");
Constructor[] constructor = c1.getConstructors();
for (Constructor constructor1 : constructor) {
System.out.println(constructor);
}
Constructor[] declaredConstructors = c1.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println("###"+declaredConstructor);
}
// 获得指定构造器
c1.getDeclaredConstructor(String.class,int.class);
System.out.println("指定构造器");
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FCugOu7q-1644162092711)(D:\web\git\document\assets\image-20220121011213703.png)]
Class c1 = Class.forName("com.test.study.reflect.User");
User user = (User) c1.newInstance();
System.out.println(user);
Constructor declaredConstructor = c1.getDeclaredConstructor(Integer.class,String.class);
User user2 = (User)declaredConstructor.newInstance(11,"清");
System.out.println(user2);
User user3 = (User) c1.newInstance();
Method setName = c1.getDeclaredMethod("setName", String.class);
setName.invoke(user3,"小绵羊");
System.out.println(user3.getName());
User user4 = (User)c1.newInstance();
Field name = c1.getDeclaredField("name");
name.setAccessible(true);
name.set(user4,"操作属性");
System.out.println(user4.getName());
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m06sAYih-1644162092712)(D:\web\git\document\assets\image-20220121164439896.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y3xNu9Be-1644162092712)(D:\web\git\document\assets\image-20220121164510369.png)]
反射操作泛型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jqG7Krlg-1644162092713)(D:\web\git\document\assets\image-20220121171603711.png)]
public void test01(Map<String,User> map, List<User> list){
System.out.println("test01");
}
public Map<String,User> test02(){
System.out.println("test02");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
Method method = Test09.class.getMethod("test01", Map.class, List.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
System.out.println("#" + genericParameterType);
if (genericParameterType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
Method method1 = Test09.class.getMethod("test02", null);
Type genericReturnType = method1.getGenericReturnType();
if (genericReturnType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
······ Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } }
}
Method method1 = Test09.class.getMethod("test02", null);
Type genericReturnType = method1.getGenericReturnType();
if (genericReturnType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
······
|