免费建自己域名的网站,企业网站建设457216336,陇南网站设计,网站大小多少合适Java —— 反射和注解 1. 反射2. 注解 1. 反射 动态语言#xff1a;变量的类型和属性可以在运行时动态确定#xff0c;而不需要在编译时指定 常见动态语言#xff1a;Python#xff0c;JavaScript#xff0c;Ruby#xff0c;PHP#xff0c;Perl#xff1b;常见静态语言… Java —— 反射和注解 1. 反射2. 注解 1. 反射 动态语言变量的类型和属性可以在运行时动态确定而不需要在编译时指定 常见动态语言PythonJavaScriptRubyPHPPerl常见静态语言CCC#GoJava JavaJava并不算是严格意义上的动态语言从反射角度来说属于半动态语言能通过反射机制实现了部分动态编程的能力 Java反射机制Java编程语言提供的一种强大的特性它允许程序在运行时动态地获取类的信息并通过该信息操作类的成员变量、方法和构造函数 Java 的反射机制在运行状态中对于任意一个类都能够知道这个类所有的属性和方法并且对于任意一个对象都能够调用它的任意一个方法 Java反射常用API Class 类反射的核心类可以获取类的属性方法等信息 Field 类Java.lang.reflec 包中的类表示类的成员变量可以用来获取和设置类之中的属性值 Method类 Java.lang.reflec 包中的类表示类的方法它可以用来获取类中的方法信息或者执行方法 Constructor 类 Java.lang.reflec 包中的类表示类的构造方法 获取Class对象的3种方法 调用某个对象的getClass()方法 ❶ 类名 对象名 new 类名(); ❷ Class 类对象名 对象名.getClass(); 使用Class类中的forName()静态方法(安全且性能好) ❸ Class 类对象名 Class.forName(“类的完全限定名”); 高版本Java创建var 类对象名 类名需要创建类对象的类.class; Class类型类名 类对象名 类名需要创建类对象的类.class; 对应类的常用方法 对应代码
package reflect;import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;/*** 反射机制*/public class TestDemo {public static void main(String[] args) throws NoSuchMethodException,InvocationTargetException, IllegalAccessException,InstantiationException, NoSuchFieldException {// 创建类对象var classes Information.class;System.out.println(类名 classes.getSimpleName());// 根据类获取当前类的完全限定名String className classes.getName();System.out.println(当前类的完全限定名 className);// 根据获取当前类的包名String packageName classes.getPackageName();System.out.println(包名 packageName);// 根据类获取当前普通方法名ListString list new ArrayList();Method[] methods classes.getMethods();for (Method method : methods) {list.add(method.getName());}System.out.println(public方法个数 list.size());System.out.println(public方法 list);// 获取构造器(无参构造器)ConstructorInformation constructor classes.getConstructor();// 利用无参构造器创建实例Object obj constructor.newInstance();// 获取指定的普通方法带参数Method publicMethod classes.getMethod(publicMethod, String.class, int.class);// 获取指定私有方法Method privateMethod classes.getDeclaredMethod(privateMethod, String.class);System.out.println(获取指定私有方法 privateMethod);// 强行开启私有方法访问权限privateMethod.setAccessible(true);// 获取所有普通public属性Field[] fields classes.getFields();System.out.println(普通属性 Arrays.toString(fields));// 获取所有属性Field[] declaredFields classes.getDeclaredFields();System.out.println(所有属性 Arrays.toString(declaredFields));// 获取属性名for (Field field:declaredFields) {String name field.getName();System.out.print(name , );}System.out.println();// 访问单个私有属性Field name classes.getDeclaredField(name);// 强行打开权限name.setAccessible(true);System.out.println(访问单个私有属性名称 name.getName() 类型 name.getType() 权限修饰符二进制位标识的修饰符信息 name.getModifiers());// 私有方法调用privateMethod.invoke(obj, 零零);// 方法调用publicMethod.invoke(obj, 夏鸥, 22);System.out.println(无参构造器创建的实例 obj);// 获取有参构造器ConstructorInformation constructors classes.getConstructor(String.class, int.class, String.class);// 有参构造器创建实例Object object constructors.newInstance(王菲, 20, 2020002);// 获取指定的普通方法Method classesMethod classes.getMethod(publicMethod);// 方法调用classesMethod.invoke(object);System.out.println(有参构造器创建的实例 object);}
}class Information{private String name 赫敏;private int age 20;public String num 2020001;public Information() {}public Information(String name, int age, String num) {this.name name;this.age age;this.num num;}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 String getNum() {return num;}public void setNum(String num) {this.num num;}Overridepublic String toString() {return TestDemo{ name name \ , age age , num num \ };}private void privateMethod() {System.out.println(name 私有方法);}private void privateMethod(String name) {this.name name;System.out.println(name 私有方法);}public void publicMethod() {System.out.println(name 普通方法);}public void publicMethod(String name, int age) {this.name name;this.age age;System.out.println(name age 普通方法);}
}应用实例
package reflect;import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.net.URL;/*** 要求实例化与当前类在统一和包中的所有类*/
public class Instantiations {public static void main(String[] args) throws ClassNotFoundException, URISyntaxException, NoSuchMethodException,InvocationTargetException, InstantiationException, IllegalAccessException {/* 1. 获取当前包中的所有类名 */// 获取包名String packageName Instantiations.class.getPackageName();// 获取当前绝对路径资源 .表示当前路径URL path Instantiations.class.getResource(.);// 获取路径下的所有文件File file new File(path.toURI());// 将所需文件过滤存储到数组所有类File[] files file.listFiles(f - f.getName().endsWith(.class));// 获取到for (File sub:files) {String name sub.getName();// 获取类名String className name.replace(.class, );System.out.println(实例化类 packageName . className);Class? classes Class.forName(packageName . className);// 通过无参构造器创建实例Object obj classes.getConstructor().newInstance();System.out.println(obj);}}
}2. 注解 注解元数据 / 注解注解Annotation是一个接口一种提供程序中元素信息和数据的途径和方法 作用在不改变程序主体逻辑的情况下为程序员提供额外的元数据信息标记一段代码的功能、作用范围、参数要求等信息 4种标准元注解元注解的作用是负责注解其他注解 ❶ Target 注解修饰范围 / 修饰的目标元素类型 ❷ Retention注解生命周期 / 保留级别 / 被保留的时间长短 ❸ Documented注解是否会被包含在Java文档中生成 ❹ Inherited注解是否可以被继承 Target元素类型 ElementType.TYPE类、接口或枚举类型 ElementType.FIELD字段或属性 ElementType.METHOD方法 ElementType.PARAMETER方法参数 ElementType.CONSTRUCTOR构造函数 ElementType.LOCAL_VARIABLE局部变量 ElementType.ANNOTATION_TYPE注解类型 ElementType.PACKAGE包 Retention的三个值 RetentionPolicy.SOURCE注解仅存在于源代码中编译时会被丢弃 RetentionPolicy.CLASS注解存在于源码和编译后的字节码文件中但在运行时会被丢弃默认值 RetentionPolicy.RUNTIME注解在运行时保留在字节码文件中可以通过反射机制读取 Documented和Inherited 一个注解被Documented修饰那么它的信息将会被包含在生成的文档中 一个注解被Inherited修饰表示该注解可以被子类继承 基本原则不直接干扰程序代码的运行 Java 注解是一种元数据它可以提供对程序元素如类、方法、字段等的额外信息或配置并且不会直接影响程序的运行逻辑只是一种机制用于存储和传递额外的信息 注解分类 声明注解及变长参数
package reflect.annotations;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;// 注解类型
Target(ElementType.METHOD)
// 注解级别
Retention(RetentionPolicy.RUNTIME)
// 声明注解
public interface AutoRunMethod {// 注解的参数当注解下的参数只有一个时一般用valueint value() default 1;String name() default 张三;
}使用注解
package reflect;import reflect.annotations.AutoRunClass;
import reflect.annotations.AutoRunMethod;import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.util.Arrays;public class Reflect {public static void main(String[] args) {// 加载包下被注解的类被注解的方法try {String packName Reflect.class.getPackage().getName();File dir new File(Reflect.class.getResource(.).toURI());File[] subs dir.listFiles(f-f.getName().endsWith(.class));for (File sub:subs) {String className sub.getName().replace(.class,);Class classes Class.forName(packName . className);if (classes.isAnnotationPresent(AutoRunClass.class)){System.out.println(实例化 className);Constructor constructor classes.getConstructor();Object obj constructor.newInstance();System.out.println(obj);// 方法名获取Method[] methods classes.getDeclaredMethods();for (Method method:methods) {// 判断该方法是否被注解if (method.isAnnotationPresent(AutoRunMethod.class)){System.out.println(调用方法 method.getName() ());// 获取注解参数AutoRunMethod arm method.getAnnotation(AutoRunMethod.class);// 获取值定义时将其认为参数调用时看作方法int value arm.value();String name arm.name();System.out.println(注解参数的值 value name);// 根据注解参数的值调用方法for (int i 0; i value; i) {// 方法调用method.invoke(obj);}}}}}} catch (URISyntaxException | ClassNotFoundException |NoSuchMethodException | InstantiationException |IllegalAccessException | InvocationTargetException e) {throw new RuntimeException(e);}}
}// 注解类
AutoRunClass
class Student {public String address 贵阳市花溪区;private String name 赵涛;private char gender 男;private int age 15;public Student() {}public Student(String name, char gender, int age) {this.name name;this.gender gender;this.age age;}public String getName() {return name;}public void setName(String name) {this.name name;}public char getGender() {return gender;}public void setGender(char gender) {this.gender gender;}public int getAge() {return age;}public void setAge(int age) {this.age age;}// 注解方法AutoRunMethod(3)public void sayHi() {System.out.println(name 你好);}AutoRunMethod(value 2, name 李四)public void sleep() {System.out.println(name 睡觉);}AutoRunMethod(name 王五)public void watchTV() {System.out.println(name 看电视);}public void playGame() {System.out.println(name 玩游戏);}public void say(String info) {System.out.println(name 说 info);}public void say(String info, int count) {System.out.println(name 说了 count 次, info);}public void study() {System.out.println(name 学习);}AutoRunMethodpublic void doHomework() {System.out.println(name 做作业);}// **********************普通方法参数变长只是Java编译器认可最终为数组***************************// 变长参数只能在方的最后一个参数且一个方法只能有一个变长参数public void doSome(String... s) {System.out.println(参数个数 s.length);System.out.println(参数 Arrays.toString(s));}private void privateMethod() {System.out.println(这是一个私有方法);}Overridepublic String toString() {return Student{ address address \ , name name \ , gender gender , age age };}
}变长参数只能在方的最后一个参数且一个方法只能有一个变长参数注解格式: 类型 参数名() [default 默认值] 注不指定默认值时使用注解必须传递对应参数注解传参机制 当注解仅有一个参数且参数名为value时直接传入参数不需要参数名 当注解仅有一个参数且参数名不为value时正常使用注解传参语法参数名参数值 多个参数传参使用参数名进行传参传参顺序可以与注解定义时参数顺序不一致 有多个参数时即使一个注解的参数名为value在实际使用时参数名也不可以忽略