Java反射、注解、泛型——针对实习面试

news2024/11/13 3:45:28

目录

  • Java反射、注解、泛型
    • 什么是反射?
    • 反射有什么优缺点?
      • 优点
      • 缺点
    • 什么是泛型?
      • 泛型的优点
      • 泛型的实现
    • 泛型怎么使用?
      • 泛型类
      • 泛型方法
      • 泛型接口
      • 类型参数命名约定
      • 泛型的类型限定
      • 泛型的通配符
    • 什么是泛型擦除机制?为什么要擦除?
    • 什么是注解?
      • 注解的定义
      • 注解的使用
      • 注解的用途
      • 内置注解
      • 元注解
    • 注解的解析方法有哪几种?
      • 编译时处理
      • 运行时处理
      • 注解的保留策略

Java反射、注解、泛型

在这里插入图片描述

什么是反射?

反射是框架的灵魂

反射通常指的是程序在运行时对自身进行检查和修改的能力。

在编程语言中,反射使得程序能够动态地获取自身的信息(比如类的结构、方法、属性等),并且能够动态地调用方法、访问属性,而无需在编译时确定这些操作。

反射有什么优缺点?

反射可以让我们的代码更加灵活,为各种框架提供开箱即用的功能提供了便利

但反射作为一种编程技术,具有其独特的优缺点,适用于特定的场景。以下是反射的一些主要优缺点:

优点

  1. 灵活性:反射允许程序在运行时动态地加载、探查和使用类和对象,使得程序能够更加灵活地处理不同的数据类型和对象。
  2. 动态性:反射使得程序能够在运行时动态地创建对象、调用方法、访问字段,而不是在编译时静态地确定这些操作。
  3. 扩展性:反射可以用于开发可扩展的应用程序,例如插件系统,其中新的功能可以在不修改现有代码的情况下被添加。
  4. 调试和测试:反射可以用于调试和测试,因为它允许程序在运行时检查对象的内部状态,调用私有方法,或者修改私有属性。
  5. 元编程:反射是元编程的一种形式,它允许程序在运行时创建、修改或操作其他程序,这是实现高级编程技术的基础。

缺点

  1. 性能开销反射操作通常比直接代码调用慢,因为它需要在运行时进行类型检查和动态方法调用。
  2. 安全性问题:反射可以访问和修改私有成员,这可能会破坏封装性,导致安全漏洞
  3. 代码可读性和维护性:过度使用反射可能会使代码难以理解和维护,因为它使得代码的行为在运行时才能确定,而不是在编译时。
  4. 复杂性增加:反射的使用增加了程序的复杂性,因为它需要处理更多的动态类型和运行时错误。
  5. 限制和约束:某些反射操作可能受到语言或平台的限制,例如,某些语言可能不允许反射访问某些类型的成员。

什么是泛型?

泛型是编程语言中一种支持使用类型参数(Type Parameters)的技术,它允许程序员编写代码时定义使用任意类型,然后在实际使用时指定具体的类型。使用泛型参数,可以增强代码的可读性以及稳定性。

泛型的优点

  1. 类型安全:泛型能够在编译时检查类型错误,避免在运行时出现类型转换异常。
  2. 代码复用:通过使用泛型,可以编写更加通用的代码减少重复代码提高开发效率
  3. 性能优化:泛型避免了类型转换,可以提高程序的运行效率
  4. 清晰的代码:使用泛型可以使代码更加清晰,因为它允许开发者明确指定代码中使用的数据类型。

泛型的实现

泛型可以在不同的编程语言中以不同的方式实现。以下是一些常见语言中泛型的实现方式:

  • Java:Java泛型是通过类型擦除实现的,这意味着在运行时不保留泛型的类型信息,但编译器会在编译时进行类型检查。
  • C#:C#泛型在运行时保持类型信息,因此提供了更好的类型安全和性能。
  • C++:C++模板是泛型编程的一种形式,它支持在编译时进行类型推导,并且可以在不同的类型上使用相同的模板代码。
  • Python:Python通过类型提示(Type Hints)支持泛型编程,虽然这些类型提示在运行时不会影响程序的行为,但可以帮助IDE和静态类型检查工具进行类型检查。

泛型怎么使用?

Java中,泛型是通过类型参数来实现的,这些类型参数在定义类、接口或方法时被指定,并在使用时被具体的类型替换。泛型的使用可以带来类型安全、代码复用和更强的代码可读性。以下是Java中泛型的基本使用方法:

泛型类

你可以定义一个泛型类,使用一个或多个类型参数:

public class Box<T> {
    private T t;

    public void set(T t) { this.t = t; }
    public T get() { return t; }
}

在这个例子中,Box是一个泛型类T是一个类型参数,你可以在创建Box实例时指定具体的类型:

Box<Integer> integerBox = new Box<>();
Box<String> stringBox = new Box<>();

泛型方法

你也可以定义泛型方法,这些方法可以在调用时指定类型参数

public class Util {
    public static <T> T getMiddle(T... a) {
        return a[a.length / 2];
    }
}

// 调用泛型方法
String middle = Util.<String>getMiddle("John", "Doe", "III");

在这个例子中,getMiddle是一个泛型方法T是一个类型参数,方法调用时指定了String类型。

泛型接口

泛型也可以用于接口定义

public interface Comparable<T> {
    int compareTo(T o);
}

实现泛型接口时,需要指定具体的类型

public class StringComparator implements Comparable<String> {
    @Override
    public int compareTo(String o) {
        return this.compareTo(o);
    }
}

类型参数命名约定

在Java中,类型参数名称通常使用单个大写字母,并且遵循一定的命名约定:

  • E - Element(在集合中使用)
  • K - Key(在键值对中使用)
  • V - Value(在键值对中使用)
  • N - Number(在数值类型中使用)
  • T - Type(在任意类型中使用)
  • S, U, V 等 - 第二、第三、第四类型(在泛型方法或复杂泛型类型中使用)

泛型的类型限定

你可以对泛型类型进行限定,例如,限定泛型类型必须是某个类的子类或实现了某个接口:

public class Box<T extends Number> {
    private T t;

    public void set(T t) { this.t = t; }
    public T get() { return t; }
}

在这个例子中,Box类的类型参数T被限定为Number的子类,这意味着T可以是IntegerDoubleNumber的子类。

泛型的通配符

泛型的通配符?可以用来表示未知类型,这在处理泛型类型时非常有用:

public void printList(List<?> list) {
    for (Object elem: list) {
        System.out.println(elem);
    }
}

在这个例子中,printList方法可以接受任何类型的List,因为List<?>表示未知类型的List

这些是Java中泛型的一些基本使用方法。泛型是Java编程中非常重要的一个特性,它提供了一种方式来创建可重用、类型安全的代码。

什么是泛型擦除机制?为什么要擦除?

Java中的泛型是通过类型擦除(Type Erasure)机制实现的。

类型擦除是指在编译期间,Java编译器会将泛型类型参数替换为其边界或者Object类型,从而实现泛型代码在运行时无需知晓实际类型参数。

这个机制允许Java的新旧代码共存,提高了语言的向后兼容性

类型擦除的主要目的包括:

  1. 兼容性:确保新的泛型代码可以与旧的非泛型代码共存避免版本升级时产生兼容性问题
  2. 减少代码重复:通过类型擦除,编译器在编译时尽可能发现可能出错的地方,减少了运行时的类型检查需求
  3. 性能优化:类型擦除减少了运行时对类型信息的需求,使得JVM可以更高效地处理泛型集合。

然而,类型擦除也带来了一些限制和挑战,例如:

  • 无法在运行时获取泛型参数的具体类型。
  • 泛型数组的创建受到限制。
  • 基本数据类型不能直接作为类型参数使用,必须使用相应的包装类型。

什么是注解?

注解(Annotation)是Java语言的一种特性,它提供了一种为程序元素(如类、方法、字段、参数等)添加元数据的方法元数据是关于程序的数据,它本身不是程序的一部分,但对程序的运行时行为有影响。注解可以被编译器或者运行时环境所使用。

注解的定义

注解是通过@interface关键字来定义的,类似于接口的定义,但注解中的方法定义了注解的属性。

public @interface MyAnnotation {
    String value();
    int count() default 1;
}

在这个例子中,MyAnnotation是一个注解,它有两个属性:valuecountcount属性有一个默认值1

注解的使用

注解可以被应用于各种程序元素上,如类、方法、字段等。

@MyAnnotation(value = "Hello", count = 5)
public class MyClass {
    @MyAnnotation(value = "World")
    private int myField;

    @MyAnnotation
    public void myMethod() {
    }
}

在这个例子中,MyClass类、它的字段myField和方法myMethod都被注解@MyAnnotation所标注。

注解的用途

注解可以用于多种目的,包括但不限于:

  1. 编译时处理:注解可以在编译时被编译器使用,例如,生成额外的源代码或资源文件。
  2. 运行时处理:注解可以在运行时通过反射被访问,用于配置应用程序的行为或创建动态代理。
  3. 文档生成:注解可以用于生成文档,例如,JavaDoc工具可以使用特定的注解来生成API文档。
  4. 框架配置:许多Java框架使用注解来简化配置,例如,Spring框架使用注解来定义依赖注入、事务管理等。
  5. 测试:注解可以用于测试框架,例如,JUnit框架使用注解来标记测试方法。

内置注解

Java提供了一些内置注解,例如:

  • @Override:表示一个方法声明打算重写父类中的另一个方法声明。
  • @Deprecated:表示某个程序元素(类、方法、字段等)已经过时。
  • @SuppressWarnings:告诉编译器忽略特定的警告。

元注解

元注解是用于注解其他注解的注解,Java提供了几种元注解,例如:

  • @Retention:指定注解的保留策略(源代码、类文件或运行时)。
  • @Target:指定注解可以应用于哪些程序元素(类、方法、字段等)。
  • @Documented:表示注解将被包含在javadoc中。
  • @Inherited:允许子类继承父类的注解。

注解是Java语言中一个强大的特性,它为程序元素提供了丰富的元数据,使得代码更加灵活和可配置。

注解的解析方法有哪几种?

在Java中,注解的解析通常有两种主要方法:
编译时处理(Compile-time processing)和运行时处理(Runtime processing)。

编译时处理

  1. 注解处理器(Annotation Processors):这是编译器在编译期间运行的工具,可以用来检查源代码中的注解,生成额外的源代码或资源文件。注解处理器可以访问到被注解的元素的抽象语法树(AST),并且可以在编译期间生成警告或错误

  2. 编译器插件:某些构建工具(如Maven或Gradle)允许你编写插件来在编译过程中执行特定的任务,这些任务可能会涉及到注解的处理。

运行时处理

  1. 反射(Reflection):这是Java提供的一种机制,允许程序在运行时查询和操作对象的属性和方法。通过反射,你可以检查对象上的注解,并根据注解来动态地改变程序的行为

    例如,使用Class类的getAnnotation()方法可以获取类上的注解,使用Method类的getAnnotation()方法可以获取方法上的注解。

  2. 动态代理(Dynamic Proxies):Java的动态代理可以在运行时动态地创建代理类和实例,这可以用来实现基于注解的动态行为

  3. 字节码操作库(如ASM, Javassist, Byte Buddy等):这些库允许你在运行时操作Java字节码,包括读取和修改注解信息。

  4. 框架支持:许多现代Java框架(如Spring, Hibernate等)提供了对注解的支持,这些框架在运行时解析注解并据此配置应用程序的行为。

注解的保留策略

注解的保留策略决定了注解信息在何时、如何被保留。Java提供了三种保留策略:

  • SOURCE:注解仅保留在源代码中,编译器在编译时丢弃注解信息。
  • CLASS:注解在编译时被记录在类文件中,但在运行时不可见。
  • RUNTIME:注解在运行时保留,可以通过反射被访问。

根据注解的保留策略和用途,开发者可以选择适当的注解解析方法。例如,编译时的注解处理器通常用于生成代码或资源文件,而运行时的反射则用于动态配置应用程序的行为。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2236374.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【SpringMVC】——Cookie和Session机制

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 一&#xff1a;实践 1&#xff1a;获取URL中的参数 &#xff08;1&#xff09;PathVariable 2&…

webWorker基本用法

我们都知道js是一个单线程的语言&#xff0c;当线程堵塞时&#xff0c;可能会导致页面无法正常交互&#xff0c;如一些复杂的可视化处理。即使是异步处理&#xff0c;也只是将其暂存到任务队列中去&#xff0c;等主线程执行完后依然会从任务队列中取过去。 为此&#xff0c;js提…

一文学习Android中的Property

在 Android 系统中&#xff0c;Property 是一种全局的键值对存储系统&#xff0c;允许不同组件和进程间以轻量级的方式进行数据传递。它主要用于系统配置、状态标识等场景&#xff0c;使得不同进程能够通过属性的设置或获取来通信。property 的核心特性是快速、高效&#xff0…

使用PEFT在多个AMD GPU上进行StarCoder的指令微调

Instruction fine-tuning of StarCoder with PEFT on multiple AMD GPUs — ROCm Blogs 2024年4月16日&#xff0c;由 Douglas Jia撰写。 在这篇博客中&#xff0c;我们将向您展示如何使用指令-答案对数据集在AMD GPU上微调StarCoder基础模型&#xff0c;以便它能够根据指令生…

后台管理系统窗体程序:文章管理 > 文章列表

目录 文章列表的的功能介绍&#xff1a; 1、进入页面 2、页面内的各种功能设计 &#xff08;1&#xff09;文章表格 &#xff08;2&#xff09;删除按钮 &#xff08;3&#xff09;编辑按钮 &#xff08;4&#xff09;发表文章按钮 &#xff08;5&#xff09;所有分类下拉框 &a…

微软的新模拟器将为 Windows on Arm 带来更多游戏

微软正在测试一项重大的 Windows on Arm 更新&#xff0c;以便让更多 x64 软件和游戏在配备高通 Snapdragon X Elite 或 X Plus 处理器的 Copilot Plus PC 上的 Prism 仿真下运行。 该功能是 Windows 11 Insider Preview Build 27744 的一部分&#xff0c;已向 Canary Channel …

NVR小程序接入平台/设备EasyNVR多品牌NVR管理工具/设备汇聚公共资源场景方案全析

随着信息技术的飞速发展&#xff0c;视频监控已经成为现代社会安全管理和业务运营不可或缺的一部分。特别是在公共资源管理方面&#xff0c;视频监控的应用日益广泛&#xff0c;涵盖了智慧城市、智能交通、大型企业以及校园安防等多个领域。NVR小程序接入平台EasyNVR作为一款功…

从单层到 MVC,再到 DDD:架构演进的思考与实践

引言 在日常开发中&#xff0c;我们之前工作中经常接手的大多数都是传统 MVC 架构体系的项目。然而&#xff0c;随着现在分布式和微服务架构的普及&#xff0c;越来越多的项目开始重构、拆分&#xff0c;传统的 MVC 架构也逐渐向 DDD 架构演进。为什么需要将传统架构重构为 DD…

CDN到底是什么?

文章目录 CDN到底是什么&#xff1f;一、引言二、CDN的基本概念1、CDN的定义2、CDN的作用3、代码示例&#xff1a;配置CNAME记录 三、CDN的工作原理1、请求流程2、代码示例&#xff1a;DNS解析过程3、完整的CDN工作流程 四、总结 CDN到底是什么&#xff1f; 一、引言 在互联网…

uniapp—android原生插件开发(3Android真机调试)

本篇文章从实战角度出发&#xff0c;将UniApp集成新大陆PDA设备RFID的全过程分为四部曲&#xff0c;涵盖环境搭建、插件开发、AAR打包、项目引入和功能调试。通过这份教程&#xff0c;轻松应对安卓原生插件开发与打包需求&#xff01; 一、打包uniapp资源包&#xff1a; 打包…

嵌入式采集网关(golang版本)

为了一次编写到处运行&#xff0c;使用纯GO编写&#xff0c;排除CGO&#xff0c;解决在嵌入式中交叉编译难问题 硬件设备&#xff1a;移远EC200A-CN LTE Cat 4 无线通信模块&#xff0c;搭载openwrt操作系统&#xff0c;90M内存

IDEA中maven更新pom文件后使其生效(自动 + 手动)

pom文件更新后默认是不生效的&#xff0c;需要手动刷新maven&#xff0c;即点击Reload Project&#xff0c;注意尽量不要用最上面那个Reload all project&#xff0c;这样的话刷新会很慢&#xff0c;因为会对整个项目Reload Project 如果懒得每次手动Reload&#xff0c;那么可…

单调栈—acwing

一、题目&#xff1a; AcWing 830. 单调栈 - AcWing 暴力算法思想 双指针算法&#xff0c;本质上是比较操作&#xff0c;两个循环&#xff0c;时间复杂度高。通过栈可以一次遍历。 可以知道&#xff0c;只要前面有一个小于我的数&#xff0c;就可以。如果前面的数&#xff…

Linux内核中IRQ Domain的结构、操作及映射机制详解

往期内容 本专栏往期内容&#xff0c;interrtupr子系统&#xff1a; 深入解析Linux内核中断管理&#xff1a;从IRQ描述符到irq domain的设计与实现 pinctrl和gpio子系统专栏&#xff1a; 专栏地址&#xff1a;pinctrl和gpio子系统 编写虚拟的GPIO控制器的驱动程序&#xff1a;…

C++ 继承:代码传承的魔法棒,开启奇幻编程之旅

文章目录 一.继承的概念及定义1.1继承的概念1.2继承类1.2.1继承方法 1.3继承模板 二.基类和派生类的转换三.继承中的作用域四.派生类的默认成员函数4.1默认成员函数的行为4.2实现一个无法被继承的类 五.继承与友元六.继承与静态成员七.多继承和菱形继承7.1多继承和菱形继承7.2虚…

无人车之编队控制算法篇

一、编队控制算法概述 无人车编队控制算法旨在实现多辆无人车之间的协同行驶&#xff0c;保持预定的队形和间距&#xff0c;以应对各种复杂环境和任务需求。该算法通常包括队形生成、队形保持、队形变换和编队模式切换等关键步骤。 二、编队控制算法的核心要素 队形生成&…

【大数据学习 | kafka高级部分】kafka的数据同步和数据均衡

1. 数据同步 通过上图我们发现每个分区的数据都不一样&#xff0c;但是三个分区对外的数据却是一致的 这个时候如果第二个副本宕机了 但是如果是leader副本宕机了会发生什么呢&#xff1f; 2. 数据均衡 在线上程序运行的时候&#xff0c;有的时候因为上面副本的损坏&#xff…

计算机网络——TCP篇

TCP篇 基本认知 TCP和UDP的区别? TCP 和 UDP 可以使用同一个端口吗&#xff1f; 可以的 传输层中 TCP 和 UDP在内核中是两个完全独立的软件模块。可以根据协议字段来选择不同的模块来处理。 TCP 连接建立 TCP 三次握手过程是怎样的&#xff1f; 一次握手:客户端发送带有 …

Xserver v1.4.2发布,支持自动重载 nginx 配置

Xserver——优雅、强大的 php 集成开发环境 本次更新为大家带来了更好的用户体验。 &#x1f389; 下载依赖组件时&#xff0c;显示进度条&#xff0c;展示下载进度。 &#x1f389; 保存站点信息和手动修改 vhost 配置文件之后&#xff0c;自动重载 nginx 配置 &#x1f41e…

Day107:代码审计-PHP模型开发篇MVC层RCE执行文件对比法1day分析0day验证

知识点&#xff1a; 1、PHP审计-MVC开发-RCE&代码执行 2、PHP审计-MVC开发-RCE&命令执行 3、PHP审计-MVC开发-RCE&文件对比 MVC 架构 MVC流程&#xff1a; Controller截获用户发出的请求&#xff1b;Controller调用Model完成状态的读写操作&#xff1b;Contr…