1. TCP协议和UDP协议的区别
TCP 协议和 UDP 协议都是传输层协议,用于在网络中传输数据,但它们在工作机制和应用场景上存在显著差异。
连接性
TCP 协议 是一种 面向连接 的协议,这意味着在数据传输之前,必须先建立连接。建立连接需要经过三次握手,确保双方都准备好进行数据传输。数据传输完成后,还需要进行四次挥手,断开连接。
UDP 协议 是一种 面向无连接 的协议,这意味着数据传输前不需要建立连接。发送方可以直接将数据打包成数据报,然后发送到接收方。接收方只要能够识别数据报的来源和目的地址,就可以接收数据。
可靠性
TCP 协议 是一种 可靠 的协议,它提供了以下机制来保证数据的可靠传输:
- 数据校验: TCP 会对每个数据包进行校验,确保数据在传输过程中没有被损坏。
- 数据排序: TCP 会对接收到的数据包进行排序,确保数据按照正确的顺序到达接收方。
- 数据重传: 如果数据包丢失,TCP 会重传丢失的数据包,直到接收方确认收到所有数据。
UDP 协议 是一种 不可靠 的协议,它不提供数据校验、排序和重传机制。如果数据包丢失,接收方将无法收到丢失的数据。
效率
TCP 协议 由于需要建立连接、进行数据校验和重传,因此 效率较低,但可以保证数据的可靠传输。
UDP 协议 由于不需要建立连接,也不进行数据校验和重传,因此 效率较高,但不能保证数据的可靠传输。
应用场景
TCP 协议 适用于对数据可靠性要求较高的场景,例如:
- 网页浏览: 浏览器需要从服务器获取网页内容,要求数据完整且准确。
- 文件传输: 文件传输需要保证数据的完整性,避免数据丢失或损坏。
- 数据库管理: 数据库操作需要保证数据的准确性,避免数据丢失或错误。
UDP 协议 适用于对实时性要求较高、对可靠性要求相对较低的场景,例如:
- 实时视频通话: 视频通话需要实时传输数据,即使偶尔丢失一些数据,也不会影响通话质量。
- 网络游戏: 网络游戏需要实时传输玩家操作数据,即使偶尔丢失一些数据,也不会影响游戏体验。
- DNS 查询: DNS 查询需要快速获取域名解析结果,即使偶尔丢失一些数据,也不会影响查询结果。
2. 简单说说TCP协议的三次握手与四次挥手机制
TCP 协议的三次握手和四次挥手机制是保证 TCP 连接可靠性的重要手段。
三次握手
三次握手用于建立 TCP 连接,确保双方都准备好进行数据传输。
- 客户端发送 SYN 包(SYN=1,seq=x): 客户端向服务器发送一个 SYN 包,表示请求建立连接。
- 服务器发送 SYN-ACK 包(SYN=1,ACK=x+1,seq=y): 服务器收到 SYN 包后,回复一个 SYN-ACK 包,表示同意建立连接,并确认客户端的序列号。
- 客户端发送 ACK 包(ACK=y+1,seq=x+1): 客户端收到 SYN-ACK 包后,回复一个 ACK 包,表示确认服务器的序列号,至此连接建立成功。
四次挥手
四次挥手用于断开 TCP 连接,确保双方都已停止数据传输。
- 客户端发送 FIN 包(FIN=1,seq=x): 客户端向服务器发送一个 FIN 包,表示请求断开连接。
- 服务器发送 ACK 包(ACK=x+1,seq=y): 服务器收到 FIN 包后,回复一个 ACK 包,表示确认客户端的请求,但此时服务器可能还有数据要发送给客户端。
- 服务器发送 FIN 包(FIN=1,seq=y): 当服务器发送完所有数据后,再发送一个 FIN 包,表示服务器也请求断开连接。
- 客户端发送 ACK 包(ACK=y+1,seq=x+1): 客户端收到 FIN 包后,回复一个 ACK 包,表示确认服务器的请求,至此连接断开。
3. 对反射了解吗?反射有什么好处?为什么需要反射?
反射的好处:
- 动态加载类: 反射机制允许在运行时动态地加载类,而无需在编译时指定类名。这使得程序更加灵活,可以根据需要加载不同的类。
- 获取类信息: 反射机制可以获取类的所有信息,包括类的属性、方法、构造函数、接口、父类等。这使得程序可以对类进行深入的分析和操作。
- 动态调用方法: 反射机制可以动态地调用类的任意方法,即使该方法是在运行时才被定义的。这使得程序更加灵活,可以根据需要调用不同的方法。
- 动态创建对象: 反射机制可以动态地创建类的对象,即使该类是在运行时才被加载的。这使得程序更加灵活,可以根据需要创建不同的对象。
为什么需要反射?
- 框架开发: 反射机制是许多框架的基础,例如 Spring 框架、Hibernate 框架等。这些框架使用反射机制来动态地加载、配置和管理对象。
- 插件开发: 反射机制允许程序在运行时加载插件,而无需修改程序本身。这使得程序更加灵活,可以根据需要添加不同的功能。
- 测试工具: 反射机制可以用于编写测试工具,例如 Mockito,它使用反射机制来模拟对象的行为。
- 动态代理: 反射机制可以用于实现动态代理,动态代理可以拦截方法调用并执行自定义的逻辑。
4. 反射的使用场合和作用、及其优缺点
反射的使用场合
反射机制常用于以下场景:
- 框架开发: Spring、Hibernate 等框架广泛应用反射机制来动态加载、配置和管理对象。
- 插件开发: 反射机制允许程序在运行时加载插件,无需修改程序本身,扩展程序功能。
- 测试工具: Mockito 等测试工具利用反射机制模拟对象行为,进行单元测试。
- 动态代理: 反射机制可以实现动态代理,拦截方法调用并执行自定义逻辑。
- 通用工具库: 反射机制可以用于开发通用工具库,例如数据库操作工具、数据类型转换工具等。
- 代码生成工具: 反射机制可以用于开发代码生成工具,根据类信息自动生成代码。
反射的作用
反射机制在这些场景中发挥着重要作用,主要体现在以下方面:
- 动态加载类: 在运行时根据需要加载不同的类,实现灵活的程序设计。
- 获取类信息: 获取类的属性、方法、构造函数、接口、父类等信息,方便进行分析和操作。
- 动态调用方法: 在运行时动态调用类的任意方法,提高程序的灵活性和可扩展性。
- 动态创建对象: 在运行时动态创建类的对象,实现更灵活的实例化过程。
反射的优缺点
反射机制虽然强大,但也存在一些缺点:
优点:
- 灵活性: 反射机制提供了极高的灵活性,允许在运行时动态地操作类和对象。
- 可扩展性: 反射机制可以方便地扩展程序的功能,无需修改源代码。
- 通用性: 反射机制可以用于开发通用的框架和工具。
缺点:
- 性能损耗: 反射机制会带来一定的性能损耗,因为它需要在运行时进行动态解析和操作。
- 安全性: 不当使用反射机制可能会导致安全问题,例如恶意代码利用反射机制绕过安全机制。
- 代码复杂性: 使用反射机制可能会使代码变得更加复杂,难以理解和维护。
5. 实现Java反射的类有什么?
Java 反射机制主要由以下几个核心类实现,它们都位于 java.lang.reflect
包中:
Class
类: 代表一个类,是反射机制的核心。通过Class
类,我们可以获取类的所有信息,包括属性、方法、构造函数、接口、父类等。Field
类: 代表类的成员变量(属性)。通过Field
类,我们可以获取和修改类的属性值。Method
类: 代表类的成员方法。通过Method
类,我们可以获取和调用类的成员方法。Constructor
类: 代表类的构造函数。通过Constructor
类,我们可以创建类的对象。
6. 反射是怎么实现的?
反射机制的实现主要依赖于 Java 虚拟机 (JVM) 的支持,而 Class
类是整个反射机制的起点。
1. Class
类
Class
类是 Java 中所有类的元数据描述,它保存了类的所有信息,包括属性、方法、构造函数、接口、父类等。- 每个类在加载时,JVM 都会为其创建一个
Class
对象,并将其保存在内存中。 - 通过
Class
对象,我们可以获取类的所有信息,并进行动态操作。
2. 获取 Class
对象
- 使用
Class.forName()
方法:通过类名获取Class
对象,例如:Class clazz = Class.forName("com.example.MyClass");
- 使用
类名.class
语法:直接获取类的Class
对象,例如:Class clazz = MyClass.class;
- 使用
对象.getClass()
方法:获取对象的Class
对象,例如:MyClass obj = new MyClass(); Class clazz = obj.getClass();
3. 利用 Class
对象实现反射
- 获取类的属性:
Field[] fields = clazz.getDeclaredFields();
- 获取类的方法:
Method[] methods = clazz.getDeclaredMethods();
- 获取类的构造函数:
Constructor[] constructors = clazz.getDeclaredConstructors();
- 创建类的对象:
Constructor constructor = clazz.getDeclaredConstructor(); Object obj = constructor.newInstance();
- 调用类的方法:
Method method = clazz.getDeclaredMethod("methodName", parameterTypes); method.invoke(obj, args);
- 设置类的属性值:
Field field = clazz.getDeclaredField("fieldName"); field.setAccessible(true); field.set(obj, value);
4. JVM 的支持
- JVM 在加载类时,会将类的字节码文件解析成元数据,并存储在内存中。
Class
类就是对这些元数据的封装,它提供了访问这些元数据的接口。- 当我们使用反射机制时,JVM 会根据
Class
对象中的元数据信息,动态地加载、解析和执行相应的代码。
7. Class类的作用?生成Class对象的方法有哪些?
Class
类的作用
- 获取类信息:
Class
类提供了获取类信息的方法,例如获取类的名称、属性、方法、构造函数、接口、父类等。 - 动态加载类:
Class
类可以用于动态加载类,例如在运行时根据需要加载不同的类。 - 动态创建对象:
Class
类可以用于动态创建类的对象,例如在运行时创建类的实例。 - 动态调用方法:
Class
类可以用于动态调用类的成员方法,例如在运行时调用类的任意方法。
生成 Class
对象的方法
有三种方法可以生成 Class
对象:
- 使用
Class.forName()
方法: 通过类名获取Class
对象。
Class clazz = Class.forName("com.example.MyClass");
该方法需要传入类的全限定名,并使用 Class.forName()
方法进行加载。
- 使用
类名.class
语法: 直接获取类的Class
对象。
Class clazz = MyClass.class;
该方法适用于已经知道类的具体类型的情况。
- 使用
对象.getClass()
方法: 获取对象的Class
对象。
MyClass obj = new MyClass();
Class clazz = obj.getClass();
8. Class.forName("全路径") 会调用哪些方法 ? 会调用构造方法吗?加载的类会放在哪?
Class.forName("全路径")
方法会调用一系列方法来完成类的加载和初始化,但不一定会调用构造方法。
1. 类加载过程
Class.forName("全路径")
方法会触发 Java 虚拟机 (JVM) 的类加载机制,这个过程包含以下步骤:
- 加载: JVM 会根据类名找到对应的字节码文件并将其加载到内存中。
- 连接: JVM 会进行验证、准备和解析,确保类符合规范并准备好运行。
- 初始化: JVM 会执行类的静态初始化块和静态变量的赋值。
2. 具体方法调用
Class.forName("全路径")
方法会调用以下方法:
ClassLoader.loadClass()
: 负责加载类文件。Class.forName0()
: 负责解析类名并找到对应的类文件。Class.initializeClass()
: 负责初始化类,包括执行静态初始化块和静态变量的赋值。
3. 构造方法调用
Class.forName("全路径")
方法本身并不会调用类的构造方法,它只负责加载和初始化类。如果需要创建类的实例,需要使用 Class.newInstance()
方法,该方法会调用类的默认构造方法。
4. 类加载位置
加载的类会被放在 JVM 的方法区中,方法区是一个所有线程共享的区域,用于存储类的元数据信息,包括类名称、属性、方法、常量池等。
9. 类加载流程
类加载流程
Java 类的加载过程主要分为七个阶段:
-
加载 (Loading)
-
验证 (Verification)
- 确保加载的类符合 JVM 规范,例如检查字节码的格式、数据类型、访问权限等。
- 这一阶段主要保证加载的类不会危害 JVM 的安全。
-
准备 (Preparation)
- 为类的静态变量分配内存,并将其初始化为默认值。
- 例如,如果一个类的静态变量是
int
类型,则其默认值为 0。
-
解析 (Resolution)
- 将类的符号引用替换为直接引用。
- 符号引用是指用符号来描述目标,例如类名、方法名、字段名等。
- 直接引用是指直接指向目标的指针或偏移量。
-
初始化 (Initialization)
- 执行类的静态初始化块和静态变量的赋值。
- 静态初始化块是在类加载过程中执行的代码块,用于初始化类。
-
使用 (Using)
- 使用已加载的类,包括创建类的实例、调用类的方法等。
-
卸载 (Unloading)
- 当类不再被使用时,JVM 会将其从内存中卸载。
10. 说一下创建对象的几种方法?
11. 如何找到对象实际类的?
对象.getClass();
Object obj = new Date();
obj.getClass();// 获取到的是Date。
12. Java反射创建对象效率高还是通过new创建对象的效率高?
通过 new
创建对象的效率远高于使用 Java 反射创建对象。
原因:
- 反射需要额外的步骤: 反射机制需要在运行时动态地解析类信息,包括加载类、查找方法、创建对象等,这些步骤都需要额外的开销,导致效率降低。
- 编译器优化: 编译器可以对
new
操作进行优化,例如将对象创建代码直接嵌入到字节码中,而反射机制则无法进行这种优化。 - 缓存机制:
new
操作会将创建的对象缓存在内存中,下次使用时可以直接从缓存中获取,而反射机制则需要每次都重新解析类信息。
13. 如何利用反射机制来访问一个类的方法?
调用指定的方法(步骤)
步骤1.通过Class的实例调用getDeclaredMethod(String methodName,Class ... args),获取指定的方法
步骤2. setAccessible(true):确保此方法是可访问的
步骤3.通过Method实例调用invoke(Object obj,Object ... objs),即为对Method对应的方法的调用。
invoke()的返回值即为Method对应的方法的返回值
特别的:如果Method对应的方法的返回值类型为void,则invoke()返回值为null
14. 说一下Java反射获取私有属性,如何改变值?
调用指定的属性(步骤)
步骤1.通过Class实例调用getDeclaredField(String fieldName),获取运行时类指定名的属性
步骤2. setAccessible(true):确保此属性是可以访问的
步骤3. 通过Filed类的实例调用get(Object obj) (获取的操作)
或 set(Object obj,Object value) (设置的操作)进行操作。