Java 基础重点知识-(泛型、反射、注解、IO)

文章目录

  • [什么是泛型? 泛型有什么用?](#什么是泛型? 泛型有什么用?)
  • [Java 反射](#Java 反射)
    • [什么是反射? 反射作用是什么?](#什么是反射? 反射作用是什么?)
    • [动态代理有几种实现方式? 有什么特点?](#动态代理有几种实现方式? 有什么特点?)
  • [Java 注解](#Java 注解)
    • [什么是注解, 作用是什么?](#什么是注解, 作用是什么?)
  • [Java I/O](#Java I/O)
    • 什么是序列化?
    • [Java 是怎么实现系列化的?](#Java 是怎么实现系列化的?)
    • 常见的序列化协议有哪些?
    • [BIO/NIO/AIO 有什么区别?](#BIO/NIO/AIO 有什么区别?)
    • [IO 多路复用是什么?](#IO 多路复用是什么?)
    • [select 和 epoll 有什么区别?](#select 和 epoll 有什么区别?)

什么是泛型? 泛型有什么用?

要理解泛型, 就要从没有泛型的时候说起, 泛型是在 JDK 1.5 开始引入的, 在之前的版本中, 并不支持泛型, 只能使用 Object 类进行通用编程, 这样在处理 集合 这些数据结构的时候, 就需要显示类型转换, 为了解决这个问题, 就引入了泛型, 用大白话讲就是适用很多类型, 它把类型进行参数化, 在编译的时候可以进行类型检查, 并且减少了类型转换的代码.

  • 目的是增强类型安全性和代码的可读性, 并减少运行时类型转换的错误.通过使用泛型, 可以在编译的时候捕获类型错误, 提供了更好的代码组织和抽象.
    没哟使用泛型时:
java 复制代码
// 没有使用泛型的例子
public class WithoutGenericsExample {
    private Object data;

    public WithoutGenericsExample(Object data) {
        this.data = data;
    }

    public Object getData() {
        return data;
    }

    public static void main(String[] args) {
        WithoutGenericsExample example = new WithoutGenericsExample("Hello");
        String str = (String) example.getData(); // 需要强制类型转换
        System.out.println(str);
    }
}

使用泛型后:

java 复制代码
// 使用泛型的例子
public class WithGenericsExample<T> {
    private T data;

    public WithGenericsExample(T data) {
        this.data = data;
    }

    public T getData() {
        return data;
    }

    public static void main(String[] args) {
        WithGenericsExample<String> example = new WithGenericsExample<>("Hello");
        String str = example.getData(); // 不需要类型转换
        System.out.println(str);
    }
}

泛型原理是什么?

Java 泛型是使用类型擦除来实现的, 在Java中, 泛型的参数类型在编译后, 被擦除的机制, 比如 new ArrayList< Integer >() 变为 new ArrayList< >() , 这就是类型擦除.

类型擦除的好处有直接兼容兼容之前的代码, 节约了内存空间, 以及 jvm 层面实现简单.

Java 反射

什么是反射? 反射作用是什么?

反射是值程序在运行时, 动态的获取和操作类的一种能力.

通过反射机制, 可以在运行时动态的创建对象, 调用方法, 访问和修改属性, 获取类的信息等.
深入理解 Java 反射和动态代理

动态代理有几种实现方式? 有什么特点?

动态代理是一种方便运行时动态构建代理、动态处理代理方法调用的机制,很多场景都是利用类似机制做到的,比如用来包装 RPC 调用、面向切面的编程(AOP).

  • JDK 动态代理(基于接口的动态代理), JDK 动态代理只能代理实现了接口的类或者直接代理接口
    代理类与委托类实现同一接口,主要是通过代理类实现 InvocationHandler 并重写 invoke 方法来进行动态代理的,在 invoke 方法中将对方法进行处理。
  • CGLIB 代理(基于类的动态代理), CGLIB 可以代理未实现任何接口的类, 另外, CGLIB 动态代理是通过生成一个被代理的子类来拦截被代理类的方法调用.

Java 注解

什么是注解, 作用是什么?

注解是 JDK 5 引入的新特性, 可以看作是一种特殊的注释, 主要用于修饰类, 方法, 变量, 提供某些信息供程序在编译或运行的时候使用.
注解详解

java 复制代码
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// 定义一个自定义的注解
@Retention(RetentionPolicy.RUNTIME) // 指定注解在运行时可见
@Target(ElementType.METHOD) // 该注解可以应用于方法
public @interface MyAnnotation {
    // 定义注解的成员变量
    String value(); // 使用value作为成员变量名
    int priority() default 1; // 定义一个默认值为1的成员变量
}

Java I/O

什么是序列化?

  • 序列化就是将对象转换为二进制数据.
  • 反序列化就是将二进制数据转换为对象.

Java 是怎么实现系列化的?

JDK 中内置了一种序列化方式.

ObjectInputStream 和 ObjectOutputStream

Java 通过对象输入输出流来实现序列化和反序列化:

  • java.io.ObjectOutputStream 类的 writeObject() 方法可以实现序列化,
  • java.io.ObjectInputStream 类的 readObject() 方法用于实现反序列化.

常见的序列化协议有哪些?

常见的序列化协议包括:

  1. Java 序列化(Java Serialization) :Java 自带的一种序列化协议,通过实现 java.io.Serializable 接口来实现对象的序列化和反序列化。虽然易于使用,但它具有一些局限性,例如不跨语言、不具备灵活性等。

  2. JSON(JavaScript Object Notation):一种轻量级的数据交换格式,易于阅读和编写,也易于机器解析和生成。由于其简洁性和广泛的支持,被广泛应用于网络传输和配置文件等领域。

  3. XML(eXtensible Markup Language):一种标记语言,具有与 JSON 类似的跨平台、跨语言特性。XML 格式的数据可以通过各种方式解析和处理,但相对于 JSON 而言,XML 的语法较为繁琐,文件体积相对较大。

  4. Protocol Buffers(Protobuf):由 Google 开发的一种高效的序列化协议。Protobuf 使用二进制格式编码数据,相对于 JSON 和 XML,它的体积更小、解析速度更快。Protobuf 支持多种编程语言,并且生成的代码具有良好的可读性。

  5. Apache Avro:另一种由 Apache 开发的序列化协议,类似于 Protobuf。Avro 使用 JSON 格式定义数据结构,并支持动态生成代码。它具有较好的跨语言支持和数据压缩能力。

  6. MessagePack:一种高效的二进制序列化协议,数据格式紧凑且可读性良好。MessagePack 支持多种数据类型,并且在多种编程语言中都有相应的实现。

BIO/NIO/AIO 有什么区别?

简单来说, BIO就是传统的 IO 包, 它诞生的最早, 它是同步的, 阻塞的, NIO 是对 BIO 的改进, 提供了多路复用的同步非阻塞IO, 而 AIO 是NIO 的升级, 提供了 异步非阻塞IO.

  • BIO (同步阻塞IO): 现成发起请求后, 一直阻塞 IO, 知道缓冲区数据就绪后, 再进入下一步操作, 针对网络通信是一问答一响应的方式, 虽然简化了上层的应用开发, 但是在性能可可靠性上又巨大瓶颈, 在高并发场景下, 资源很快就会被耗尽.

  • NIO (同步非阻塞IO): 为了解决 BIO 性能, 引入了 NIO, NIO 提供了 channel , Select , Buffer 等新的抽象, 可以构建多路复用, 可以通过单线程或少量线程处理多个通道的事件.

  • AIO (异步非阻塞IO): 是 NIO 的升级版本, 基于事件和回调函数实现, 也就是在引用操作之后会直接返回, 不会阻塞在那里, 当后台处理完成, 操作系统会通知相应的线程进行后续的操作.

IO 多路复用是什么?

I/O 多路复用是一种高效的 I/O 编程模式,用于同时监视多个 I/O 流的状态,并在有数据可读、可写或者有异常时立即对其进行处理,而不需要为每个 I/O 流创建一个对应的线程。

在传统的阻塞 I/O 模型中,每个 I/O 操作都需要一个独立的线程来处理,当有大量的并发连接时,会导致大量的线程创建和上下文切换,降低系统性能。

而在多路复用模型中,通过使用特定的系统调用(如 select、poll、epoll 等),可以同时监听多个 I/O 流的状态。一旦有 I/O 事件发生,操作系统会通知应用程序,应用程序就可以根据事件类型来进行相应的处理,而无需阻塞等待。这样就可以用较少的线程来处理大量的并发连接,提高系统的并发能力和性能。

select 和 epoll 有什么区别?

  • select 每次调用都需要将文件描述符集合从用户态拷贝到内核态,而且随着文件描述符数量的增加,这个拷贝的开销会变得非常大。

    每次调用都需要线性扫描整个文件描述符集合,效率较低。

  • epoll 使用一个文件描述符来管理多个文件描述符,减少了拷贝文件描述符集合的开销。

    通过红黑树和双链表来管理文件描述符,实现了 O(1) 时间复杂度的事件注册和删除,提高了效率。

    支持水平触发(LT,Level Triggered)和边缘触发(ET,Edge Triggered)两种模式,更灵活。

select()函数基于数组,fd个数限制1024,poll()函数也是基于数组但是fd数目无限制。都会负责所有的fd,

epll()基于红黑数实现,fd无大小限制,平衡二叉数插入删除效率高.

相关推荐
龙哥说跨境13 分钟前
如何利用指纹浏览器爬虫绕过Cloudflare的防护?
服务器·网络·python·网络爬虫
Source.Liu13 分钟前
【用Rust写CAD】第二章 第四节 函数
开发语言·rust
monkey_meng13 分钟前
【Rust中的迭代器】
开发语言·后端·rust
余衫马16 分钟前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng20 分钟前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
七星静香21 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
Jacob程序员22 分钟前
java导出word文件(手绘)
java·开发语言·word
ZHOUPUYU22 分钟前
IntelliJ IDEA超详细下载安装教程(附安装包)
java·ide·intellij-idea
stewie625 分钟前
在IDEA中使用Git
java·git
小白学大数据28 分钟前
正则表达式在Kotlin中的应用:提取图片链接
开发语言·python·selenium·正则表达式·kotlin