注解(Annotation)
Java 注解(Annotation)是一种特殊的语言构造,用于为代码元素(如类、方法、字段等)提供元数据,通常不直接影响程序的逻辑执行。它们可以被编译器、框架或工具解析,用于执行特定操作,如自动化配置、代码生成、验证等。Java 提供了内置的注解(如 @Override
、@Deprecated
)和允许用户自定义注解。注解的处理方式可以在编译时或运行时进行,常用于框架配置、自动化处理和代码文档生成等场景
@注解名 (参数)
注释和注解的区别为注释是给编程人员看的,用于解释代码含义的,而注解是给其他程序看的,用于帮助其他程序读懂该段代码,总结就是注释是帮助人解释代码,注解就是帮助程序解释代码
内置注解
内置注解是 Java 提供的预定义注解,它们通常用于编译时检查、代码优化或者提供额外的元数据。Java 标准库中提供了几种常用的内置注解,它们有特定的用途和行为,帮助开发者提高代码的可读性、可维护性并减少错误
Java 的常见内置注解包括 @Override
、@Deprecated
、@SuppressWarnings
以上主要注意@Override
重写注解和@SuppressWarnings
警告镇压注解,而@Deprecated
早已被废弃
元注解
元注解(Meta-Annotation)是用于描述其他注解的注解。它们定义了注解的使用方式和生命周期,通常用于自定义注解时。
-
@Retention
:指定注解的保留策略,决定注解在哪个阶段可用。可以是SOURCE
(仅在源码中可见),CLASS
(在编译后仍可用,但不会被加载到 JVM 中),RUNTIME
(在运行时可用,通常用于反射)。 -
@Target
:指定注解可以应用于哪些 Java 元素,如类、方法、字段等。通过ElementType
枚举进行定义。 -
@Inherited
:表示子类可以继承父类的注解,适用于类级别的注解。 -
@Documented
:表示注解应包含在 JavaDoc 中,生成的文档会包含该注解的详细信息。
package org.example;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;// 自定义注解,作用于方法和类上,运行时
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {// 注解的参数定义:参数类型 参数名() default 默认值String name() default "李华";// 默认值 -1 表示不存在int age() default -1;
}
反射(Reflection)
反射是 Java 提供的一种在运行时动态获取类的信息、创建对象、调用方法和访问字段的机制。它通过 Class
类和相关的 API 允许程序在运行时检查和操作类的结构,而无需在编译时明确这些信息。反射广泛应用于框架设计、动态代理和工具开发等领域,但由于性能开销和安全性问题,使用时需要谨慎
动态和静态语言
动态语言是指在运行时可以改变其结构的编程语言,如新增函数、对象或修改已有结构。常见的动态语言有 Python、JavaScript、PHP、C# 等。相比之下,静态语言如 Java、C、C++ 其结构在运行时是不可变的,编译时类型和结构已经确定。然而,Java 也具有一定的动态性,尤其通过反射机制,能够在运行时进行一定的结构调整,具备类似动态语言的一些特性
Java作为一门特殊的静态语言,通过反射能表现出准动态性
Java中万物皆对象,描述Java程序编译生成的Class文件的对象就是Class类对象,因此Class文件,成员变量,成员方法和构造方法的对于的类为Class类,Field类,Method类和Constructor类
类的加载机制:父类对象->子类对象->main方法->静态成员->反射
正常是先定义类,然后通过类去实例化对象,而反射机制允许通过对对象的解析反推出类的结构,而无需一开始定义类的结构
package org.example;import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;class Student{private String name = "李华";private int age = 18;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Student(String name, int age) {this.name = name;this.age = age;}public Student() {}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}public class Main {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {Student stu = new Student();Class c = null;// 常见四种获取class类的方法c = stu.getClass();// org.example.Student为类的全限定名c = Class.forName("org.example.Student");c = Student.class;// 反射构造方法// 获取所有的非私有构造方法// getDeclared*,获取所有的包括私有的,如getDeclaredConstructors,获取所有的构造方法Constructor[] cs = c.getConstructors();for (Constructor ctor : cs) {System.out.println(ctor);}// 无参构造Constructor ctor = c.getConstructor();// 有参构造ctor = c.getConstructor(String.class,int.class);// 通过构造方法创建实例Student s = (Student) ctor.newInstance("小明",18);System.out.println(s.toString());// 获取所有成员方法包括父类的,非私有Method[] ms = c.getMethods();for (Method m : ms) {System.out.println(m);}// 获取指定方法,传入方法名和参数,用于区分不同方法和重载方法Method m = c.getMethod("setName", String.class);// 执行对应的方法,传入一个对象和方法参数m.invoke(s,"李雷");System.out.println(s.toString());Field[] fs = c.getFields();// 获取所有成员变量for (Field f : fs) {System.out.println(f);}// 获取指定成员变量Field f = c.getDeclaredField("name");// 运行操作私有成员变量f.setAccessible(true);f.set(s,"韩梅梅");System.out.println(s.toString());}
}