文章目录
-
- 1. 创建对象的几种方式
- 2. 反射机制
- 3. Java集合框架结构
- 4. ArrayList与LinkedList的区别
- 5. 如何保证ArrayList的线程安全?
- 6. HashMap和HashTable的区别
- 7. HashMap的底层结构
- 8. ConcurrentHashMap如何保证线程的安全
- 9. 创建线程的方式
- 10. PS:什么是Executor框架
- 11. 并发和并行的区别
- 12. 进程和线程的区别
- 13. 什么是上下文切换
- 14. 线程状态转换有哪些
- 15. 什么是死锁
- 16. synchronized和lock的区别
- 17. 什么是AQS锁
- 18. 常见的AQS锁
- 19. 为什么AQS锁使用双向链表
- 20. yield和join的区别
- 21. 线程池的七大参数
- 22. Java的内存模型
1. 创建对象的几种方式
- 使用 new 关键字:使用 new 关键字可以在堆内存中创建一个新的对象。
- 通过反射机制:通过Java反射机制,可以在运行时动态地获取类的信息并创建对象。这种方式可以通过 Class 类的 newInstance() 方法或 Constructor 类的 newInstance() 方法来创建对象。
-
Class 类的 newInstance() 方法
ClassName objectName = (ClassName)Class.forName("ClassName").newInstance();
-
Constructor 类的 newInstance() 方法
Constructor<ClassName> constructor = ClassName.class.getConstructor(parameterTypes); ClassName objectName = constructor.newInstance(parameters);
-
- 通过 clone() 方法:Cloneable接口提供了 clone() 方法,通过该方法可以创建一个对象副本。被复制的对象必须实现 Cloneable 接口。
- 通过反序列化:将一个对象序列化成字节流后,可以通过反序列化操作将其重新转换为对象。这种方式可以使用 ObjectInputStream 类的 readObject() 方法来实现。
- 使用工厂模式:通过定义一个工厂类,使用该工厂类中的静态方法来创建对象。这样可以封装对象的创建过程,并且可以根据需要返回不同类型的对象。
- 使用单例模式:通过单例模式可以确保一个类只有一个实例对象,可以使用静态方法或者静态块来创建这个唯一的实例。
- 通过依赖注入框架:使用依赖注入框架(如Spring)可以自动创建对象并注入依赖。
2. 反射机制
反射机制是指在运行时动态地获取类的信息、调用类的方法、操作类的属性等能力。通过反射机制,可以在运行时检查类的结构并对其进行操作,而无需在编译时知道类的具体信息。
Java 反射机制主要涉及以下几个核心类:
1. Class类:java.lang.class 类代表一个类的实例,在运行时,每个类都有一个对应的 Class 对象。通过 Class 类,可以获取类的构造函数、字段、方法等信息,以及实例化对象。
2. Constructor类:java.lang.reflect.Constructor 类用于表示类的构造函数。通过 Constructor 类可以创建新的类实例。
3. Method类:java.lang.reflect.Method 类用于表示类的方法。通过 Method 类可以调用类的方法。
4. Field类:java.lang.reflect.Field 类用于表示类的字段。通过Field 类可以访问和修改类的字段。
通过这些类,可以实现动态地加载类、调用类的方法、访问和修改类的属性等操作。反射机制常用于框架设计、动态代理、注解处理等领域,但由于反射操作较为灵活,也会导致性能上的一定开销,因此在实际应用中需要谨慎使用。
反射机制为Java提供了更大的灵活性和动态性,使得程序能够在运行时动态地适应不同的情况和需求。
3. Java集合框架结构
4. ArrayList与LinkedList的区别
- 数据结构
- ArrayList基于动态数组实现,通过数组存储元素,支持随机访问(根据索引快速访问元素)。
- LinkedLsit基于双向链表实现,通过节点间的引用关系存储元素,不支持随机访问,需要顺序遍历链表来访问元素。
- 插入和删除操作
- ArrayList在中间或末尾插入/删除元素时,需要移动移动后续元素,效率较低,在末尾增加元素时效率较高。
- LinkedList在插入和删除操作上效率较高,特别是在中间插入/删除元素时,只需调整相邻节点的指针。
- 访问效率
- ArrayList的随机访问效率比较高,时间复杂度为O(1)。
- LinkedList的随机访问效率较低,需要从头到尾开始顺序查找,时间复杂度为O(n)。
- 内存占用
- ArrayList在添加或删除元素时可能会出发数组的扩容货收缩操作,可能会产生额外的空间浪费。
- LinkedList的每个元素需要额外的空间存储前后节点的引用,可能会占用更多的内存。
- 如果频繁随机访问和末尾操作,可以选择ArrayList;如果需要频繁插入和删除,可以选择LinkedList。
- ArrayList 和 LinkedList *都是线程不安全的。
5. 如何保证ArrayList的线程安全?
- 使用 Collections 工具类中的 synchronizedList 方法
List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>());
- 使用锁机制
在访问ArratList时使用显式的锁机制(如ReentrantLock)来保证线程安全。List<String> list = new ArrayList<>(); ReentrantLock lock = new ReentantLock(); //在访问list之前获取锁 lock.lock(); try{ //对list进行访问 }finally{ //操作完成后释放锁 lock.unlock(); }
- 使用线程安全的替代类
使用CopyOnWriteArrayList 类:CopyOnWriteArrayList 是java.util.concurrent包下的一个线程安全的ArrayList实现。它通过在修改操作时创建一个新的数组来实现线程安全,适用于读多写少的场景。List<String> copyOnWriteArrayList = new CopyOnWriteArrayList<