java基础面试题九网络编程与反射机制

1. TCP协议和UDP协议的区别

TCP 协议和 UDP 协议都是传输层协议,用于在网络中传输数据,但它们在工作机制和应用场景上存在显著差异。

连接性

TCP 协议 是一种 面向连接 的协议,这意味着在数据传输之前,必须先建立连接。建立连接需要经过三次握手,确保双方都准备好进行数据传输。数据传输完成后,还需要进行四次挥手,断开连接。

UDP 协议 是一种 面向无连接 的协议,这意味着数据传输前不需要建立连接。发送方可以直接将数据打包成数据报,然后发送到接收方。接收方只要能够识别数据报的来源和目的地址,就可以接收数据。

可靠性

TCP 协议 是一种 可靠 的协议,它提供了以下机制来保证数据的可靠传输:

  • 数据校验: TCP 会对每个数据包进行校验,确保数据在传输过程中没有被损坏。
  • 数据排序: TCP 会对接收到的数据包进行排序,确保数据按照正确的顺序到达接收方。
  • 数据重传: 如果数据包丢失,TCP 会重传丢失的数据包,直到接收方确认收到所有数据。

UDP 协议 是一种 不可靠 的协议,它不提供数据校验、排序和重传机制。如果数据包丢失,接收方将无法收到丢失的数据。

效率

TCP 协议 由于需要建立连接、进行数据校验和重传,因此 效率较低,但可以保证数据的可靠传输。

UDP 协议 由于不需要建立连接,也不进行数据校验和重传,因此 效率较高,但不能保证数据的可靠传输。

应用场景

TCP 协议 适用于对数据可靠性要求较高的场景,例如:

  • 网页浏览: 浏览器需要从服务器获取网页内容,要求数据完整且准确。
  • 文件传输: 文件传输需要保证数据的完整性,避免数据丢失或损坏。
  • 数据库管理: 数据库操作需要保证数据的准确性,避免数据丢失或错误。

UDP 协议 适用于对实时性要求较高、对可靠性要求相对较低的场景,例如:

  • 实时视频通话: 视频通话需要实时传输数据,即使偶尔丢失一些数据,也不会影响通话质量。
  • 网络游戏: 网络游戏需要实时传输玩家操作数据,即使偶尔丢失一些数据,也不会影响游戏体验。
  • DNS 查询: DNS 查询需要快速获取域名解析结果,即使偶尔丢失一些数据,也不会影响查询结果。

2. 简单说说TCP协议的三次握手与四次挥手机制

TCP 协议的三次握手和四次挥手机制是保证 TCP 连接可靠性的重要手段。

三次握手

三次握手用于建立 TCP 连接,确保双方都准备好进行数据传输。

  1. 客户端发送 SYN 包(SYN=1,seq=x): 客户端向服务器发送一个 SYN 包,表示请求建立连接。
  2. 服务器发送 SYN-ACK 包(SYN=1,ACK=x+1,seq=y): 服务器收到 SYN 包后,回复一个 SYN-ACK 包,表示同意建立连接,并确认客户端的序列号。
  3. 客户端发送 ACK 包(ACK=y+1,seq=x+1): 客户端收到 SYN-ACK 包后,回复一个 ACK 包,表示确认服务器的序列号,至此连接建立成功。

四次挥手

四次挥手用于断开 TCP 连接,确保双方都已停止数据传输。

  1. 客户端发送 FIN 包(FIN=1,seq=x): 客户端向服务器发送一个 FIN 包,表示请求断开连接。
  2. 服务器发送 ACK 包(ACK=x+1,seq=y): 服务器收到 FIN 包后,回复一个 ACK 包,表示确认客户端的请求,但此时服务器可能还有数据要发送给客户端。
  3. 服务器发送 FIN 包(FIN=1,seq=y): 当服务器发送完所有数据后,再发送一个 FIN 包,表示服务器也请求断开连接。
  4. 客户端发送 ACK 包(ACK=y+1,seq=x+1): 客户端收到 FIN 包后,回复一个 ACK 包,表示确认服务器的请求,至此连接断开。

3. 对反射了解吗?反射有什么好处?为什么需要反射?

反射的好处:

  • 动态加载类: 反射机制允许在运行时动态地加载类,而无需在编译时指定类名。这使得程序更加灵活,可以根据需要加载不同的类。
  • 获取类信息: 反射机制可以获取类的所有信息,包括类的属性、方法、构造函数、接口、父类等。这使得程序可以对类进行深入的分析和操作。
  • 动态调用方法: 反射机制可以动态地调用类的任意方法,即使该方法是在运行时才被定义的。这使得程序更加灵活,可以根据需要调用不同的方法。
  • 动态创建对象: 反射机制可以动态地创建类的对象,即使该类是在运行时才被加载的。这使得程序更加灵活,可以根据需要创建不同的对象。

为什么需要反射?

  • 框架开发: 反射机制是许多框架的基础,例如 Spring 框架、Hibernate 框架等。这些框架使用反射机制来动态地加载、配置和管理对象。
  • 插件开发: 反射机制允许程序在运行时加载插件,而无需修改程序本身。这使得程序更加灵活,可以根据需要添加不同的功能。
  • 测试工具: 反射机制可以用于编写测试工具,例如 Mockito,它使用反射机制来模拟对象的行为。
  • 动态代理: 反射机制可以用于实现动态代理,动态代理可以拦截方法调用并执行自定义的逻辑。

4. 反射的使用场合和作用、及其优缺点

反射的使用场合

反射机制常用于以下场景:

  • 框架开发: Spring、Hibernate 等框架广泛应用反射机制来动态加载、配置和管理对象。
  • 插件开发: 反射机制允许程序在运行时加载插件,无需修改程序本身,扩展程序功能。
  • 测试工具: Mockito 等测试工具利用反射机制模拟对象行为,进行单元测试。
  • 动态代理: 反射机制可以实现动态代理,拦截方法调用并执行自定义逻辑。
  • 通用工具库: 反射机制可以用于开发通用工具库,例如数据库操作工具、数据类型转换工具等。
  • 代码生成工具: 反射机制可以用于开发代码生成工具,根据类信息自动生成代码。

反射的作用

反射机制在这些场景中发挥着重要作用,主要体现在以下方面:

  • 动态加载类: 在运行时根据需要加载不同的类,实现灵活的程序设计。
  • 获取类信息: 获取类的属性、方法、构造函数、接口、父类等信息,方便进行分析和操作。
  • 动态调用方法: 在运行时动态调用类的任意方法,提高程序的灵活性和可扩展性。
  • 动态创建对象: 在运行时动态创建类的对象,实现更灵活的实例化过程。

反射的优缺点

反射机制虽然强大,但也存在一些缺点:

优点:

  • 灵活性: 反射机制提供了极高的灵活性,允许在运行时动态地操作类和对象。
  • 可扩展性: 反射机制可以方便地扩展程序的功能,无需修改源代码。
  • 通用性: 反射机制可以用于开发通用的框架和工具。

缺点:

  • 性能损耗: 反射机制会带来一定的性能损耗,因为它需要在运行时进行动态解析和操作。
  • 安全性: 不当使用反射机制可能会导致安全问题,例如恶意代码利用反射机制绕过安全机制。
  • 代码复杂性: 使用反射机制可能会使代码变得更加复杂,难以理解和维护。

5. 实现Java反射的类有什么?

Java 反射机制主要由以下几个核心类实现,它们都位于 java.lang.reflect 包中:

  1. Class 类: 代表一个类,是反射机制的核心。通过 Class 类,我们可以获取类的所有信息,包括属性、方法、构造函数、接口、父类等。
  2. Field 类: 代表类的成员变量(属性)。通过 Field 类,我们可以获取和修改类的属性值。
  3. Method 类: 代表类的成员方法。通过 Method 类,我们可以获取和调用类的成员方法。
  4. 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 对象:

  1. 使用 Class.forName() 方法: 通过类名获取 Class 对象。
Class clazz = Class.forName("com.example.MyClass");

该方法需要传入类的全限定名,并使用 Class.forName() 方法进行加载。

  1. 使用 类名.class 语法: 直接获取类的 Class 对象。
Class clazz = MyClass.class;

该方法适用于已经知道类的具体类型的情况。

  1. 使用 对象.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 类的加载过程主要分为七个阶段:

  1. 加载 (Loading)

    • 查找并获取类的二进制字节流。
    • 将字节流所代表的静态存储结构转换为方法区的运行时数据结构。
    • 在内存中创建代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据的访问入口。[1][2][5]
  2. 验证 (Verification)

    • 确保加载的类符合 JVM 规范,例如检查字节码的格式、数据类型、访问权限等。
    • 这一阶段主要保证加载的类不会危害 JVM 的安全。
  3. 准备 (Preparation)

    • 为类的静态变量分配内存,并将其初始化为默认值。
    • 例如,如果一个类的静态变量是 int 类型,则其默认值为 0。
  4. 解析 (Resolution)

    • 将类的符号引用替换为直接引用。
    • 符号引用是指用符号来描述目标,例如类名、方法名、字段名等。
    • 直接引用是指直接指向目标的指针或偏移量。
  5. 初始化 (Initialization)

    • 执行类的静态初始化块和静态变量的赋值。
    • 静态初始化块是在类加载过程中执行的代码块,用于初始化类。
  6. 使用 (Using)

    • 使用已加载的类,包括创建类的实例、调用类的方法等。
  7. 卸载 (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) (设置的操作)进行操作。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值