什么反射?
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为: 反射。
Java反射机制提供的功能
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时获取泛型信息
- 在运行时调用任意一个对象的成员变量和方法
- 在运行时处理注解
- 生成动态代理
反射相关的主要API
java.lang.Class: 代表一 个 类
java.lang.reflect.Method: 代表类 的 方法
java.lang.reflect.Field: 代表类的 成员 变量
java.lang.reflect.Constructor: 代表类 的 构造
Class 类
对象照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口。对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含了特定某个结构(class/interface/enum/annotation/primitive type/void/[])的有关信息
- Class本身也是一个类
- Class 对象只能由系统建立对象
- 一个加载的类在 JVM 中只会有一个Class实例
- 一个Class对象对应的是一个加载到JVM中的一个.class文件
- 每个类的实例都会记得自己是由哪个 Class 实例所生成
- 通过Class可以完整地得到一个类中的所有被加载的结构
- Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的Class对象
Class类的常用方法
方法名 | 功能说明 |
---|---|
static Class forName(String name) | 返回指定类名 name 的 Class 对象 |
Object newInstance() | 调用缺省构造函数,返回该Class对象的一个实例 |
getName() |
返回此Class对象所表示的实体(类、接口、数组类、基本类型 或void)名称 |
Class getSuperClass() | 返回当前Class对象的父类的Class对象 |
Class [] getInterfaces() | 获取当前Class对象的接口 |
ClassLoader getClassLoader() | 返回该类的类加载器 |
Class getSuperclass() | 返回表示此Class所表示的实体的超类的Class |
Constructor[] getConstructors() | 返回一个包含某些Constructor对象的数组 |
Field[] getDeclaredFields() | 返回Field对象的一个数组 |
Method getMethod(String name,Class … paramTypes) |
返回一个Method对象,此对象的形参类型为paramType |
获取Class 类的实例( 四种方法)
先创建一个实体类
package com.chen.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @AllArgsConstructor @NoArgsConstructor @Data public class Car { public String brand="宝马"; public int price=500000; public String color="白色"; }
1.前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出 ClassNotFoundException
//1.Class.forName,应用场景:多用于配置文件,读取类全路径,加载类 String classAllPath="com.chen.pojo.Car"; Class<?> cls1=Class.forName(classAllPath);
输出结果:
2.前提:若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高
//2.类名.class,应用场景:用于参数传递 Class<Car> cls2 = Car.class; System.out.println(cls2);
输出结果:
3.已知某个类的实例,调用该实例的getClass()方法获取Class对象
/3.对象.getClass(),应用场景,有对象实例 Car car=new Car(); Class cls3=car.getClass(); System.out.println(cls3);
输出结果:
4.其他方式(不做要求)
//4.通过类加载器(4)种来获取类的Class对象 //(1)先得到类加载器car ClassLoader classLoader=car.getClass().getClassLoader(); //(2)通过类加载器得到Class对象 Class<?> cls4=classLoader.loadClass(classAllPath); System.out.println(cls4);
//cls1,cls2,cls3,cls4 其实是同一个对象 System.out.println(cls1.hashCode()); System.out.println(cls2.hashCode()); System.out.println(cls3.hashCode()); System.out.println(cls4.hashCode());
//5. 基本数据(int,char,boolean,float,double,byte,long,short) 按如下方式得到Class类对象 Class<Integer> integerClass=int.class; Class<Character> characterClass=char.class; Class<Boolean> booleanClass=boolean.class; System.out.println(integerClass); //6.基本数据类型对应的包装类,可以通过 .TYPE 得到class类对象 Class<Integer> type1=Integer.TYPE; Class<Character> type2 = Character.TYPE;//其它包装类BOOLEAN,DOUBLE,LONG,BYTE System.out.println(type1);
哪些类型可以有Class 对象?
(1)class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
(2)interface:接口
(3)[]:数组
(4)enum:枚举
(5)annotation:注解@interface
(6)primitive type:基本数据类型
(7)void
Class<String> cls1=String.class;//外部类 Class<Serializable> cls2=Serializable.class;//接口 Class<Integer[]> cls3 = Integer[].class;//数组 Class<float[][]> cls4 = float[][].class;//二维数组 Class<Deprecated> cls5 = Deprecated.class;//注解 //枚举 Class<Thread.State> cls6 = Thread.State.class; Class<Long> cls7 = long.class; Class<Void> cls8= void.class; Class<Class> cls9 = Class.class; System.out.println(cls1); System.out.println(cls2); System.out.println(cls3); System.out.println(cls4); System.out.println(cls5); System.out.println(cls6); System.out.println(cls7); System.out.println(cls8); System.out.println(cls9);
演示Class类的常用方法
package com.chen; import com.chen.pojo.Car; import java.lang.reflect.Field; import java.util.Arrays; import java.util.List; //演示Class类的常用方法 public class Class02 { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException { String classAllPath="com.chen.pojo.Car"; //1.获取Car类对应的Class对象 //<?>表示不确定的Java类 Class<?> cls=Class.forName(classAllPath); //2.输出cls System.out.println(cls);//显示cls对象,是哪个类的Class对象 class com.chen.pojo.Car System.out.println(cls.getClass());//输出cls运行类型 class java.lang.Class //3.得到包名 System.out.println(cls.getPackage().getName()); //4.得到全类名 System.out.println(cls.getName()); //5.通过cls创建对象实例 Car car= (Car) cls.newInstance(); System.out.println(car); //6.通过反射获取属性 brand Field brand=cls.getField("brand"); System.out.println(brand.get(car)); //7.通过反射给属性赋值 brand.set(car,"奔驰"); System.out.println(brand.get(car)); //8.获取所有属性(字段) Field[] fields=cls.getFields(); for (Field field:fields){ System.out.println(field.getName()); } } }
输出结果
有了Class对象,能做什么?
通过反射获取运行时类类的完整结构
Field 、Method 、Constructor 、Superclass 、Interface 、Annotation(实现的全部接口 所继承的父类 全部的构造器 全部的方法 全部的Field)
1. 实现的全部接口
public Class<?>[] getInterfaces()
确定此对象所表示的类或接口实现的接口。
2. 所继承的父类
public Class<? Super T> getSuperclass()
返回表示此 Class 所表示的实体(类、接口、基本类型)的父类的
Class。
3. 全部的构造器
public Constructor<T>[] getConstructors()
返回此 Class 对象所表示的类的所有public构造方法。
public Constructor<T>[] getDeclaredConstructors()
返回此 Class 对象表示的类声明的所有构造方法。
Constructor类中:
取得修饰符: public int getModifiers();
取得方法名称: public String getName();
取得参数的类型:public Class<?>[] getParameterTypes();
4. 全部的方法
public Method[] getDeclaredMethods()
返回此Class对象所表示的类或接口的全部方法
public Method[] getMethods()
返回此Class对象所表示的类或接口的public的方法
Method类中:
public Class<?> getReturnType()取得全部的返回值
public Class<?>[] getParameterTypes()取得全部的参数
public int getModifiers()取得修饰符
public Class<?>[] getExceptionTypes()取得异常信息
5. 全部的Field
public Field[] getFields()
返回此Class对象所表示的类或接口的public的Field。
public Field[] getDeclaredFields()
返回此Class对象所表示的类或接口的全部Field。
Field方法中:
public int getModifiers() 以整数形式返回此Field的修饰符
public Class<?> getType() 得到Field的属性类型
public String getName() 返回Field的名称。
6. Annotation 相关
get Annotation(Class<T> annotationClass)
getDeclaredAnnotations()
7. 泛型相关
获取父类泛型类型:Type getGenericSuperclass()
泛型类型:ParameterizedType
获取实际的泛型类型参数数组:getActualTypeArguments()
8. 类所在的包 Package getPackage()
例:
package com.chen; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; //演示如来通过反射获取类的结构信息 public class ReflectionUtils { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException { //api_o1(); api_o2(); } //第一组API public static void api_o1() throws ClassNotFoundException, NoSuchMethodException { //得到Class对象 Class<?> person=Class.forName("com.chen.Person"); //getName:获取全类名 System.out.println(person.getName()); //getSimpleName:获取简单类名 System.out.println(person.getSimpleName()); //getFields:获取所有public修饰的属性,包含本类以及父类的 Field[] fields=person.getFields(); for(Field field:fields){ System.out.println("本类以及父类的属性="+field.getName()); } //getDeclaredFields:获取本类中所有属性 Field[] declaredFields = person.getDeclaredFields(); for(Field declaredField:declaredFields){ System.out.println("本类中所有属性="+declaredField.getName()); } //getMethods:获取所有public修饰的方法,包含本类以及父类的 Method[] methods=person.getMethods(); for(Method method:methods){ System.out.println("本类及父类的方法="+method.getName()); } //getDeclaredMethods:获取本类中所有的方法 Method[] declareMethods=person.getDeclaredMethods(); for(Method declareMethod:declareMethods){ System.out.println("本类中所有的方法:"+declareMethod); } //getConstructors:获取所有public修饰的构造器,包含本类 Constructor<?>[] constructors = person.getConstructors(); for(Constructor<?> constructor:constructors){ System.out.println("本类的构造器="+constructor.getName()); } //getDeclaredConstructors:获取本类中所有的构造器 Constructor<?>[] declaredConstructors=person.getDeclaredConstructors(); for (Constructor<?> declaredConstructor:declaredConstructors){ System.out.println("本类中所有的构造器="+declaredConstructor.getName()); System.out.println("本类中所有的构造器="+declaredConstructor); } //getPackage:以Package形式返回 包信息 System.out.println(person.getPackage()); //getSuperClass:以Class形式返回父类信息 Class<?> superclass = person.getSuperclass(); System.out.println("以Class形式返回父类信息"+superclass); //getInterfaces:以Class[]形式返回接口信息 Class<?>[] interfaces = person.getInterfaces(); for (Class<?> aninterface:interfaces){ System.out.println("接口信息"+aninterface); } //getAnnotat ions:以Annotation[]形式返回注解信息 Annotation[] annotations=person.getAnnotations(); for (Annotation annotation:annotations){ System.out.println("注解信息="+annotation); } } public static void api_o2() throws ClassNotFoundException, NoSuchMethodException { //得到Class对象 Class<?> person=Class.forName("com.chen.Person"); //getDeclaredFields:获取本类中所有属性 //规定说明:默认修饰符是0,public是1,private是2,protected是4,static是8,final是16,】 public(1)+static(8)=9 Field[] declaredFields = person.getDeclaredFields(); for(Field declaredField:declaredFields){ System.out.println("本类中所有属性="+declaredField.getName()+"该属性的修饰符="+declaredField.getModifiers() +" 该属性的类型="+declaredField.getType()); } //getDeclaredMethods:获取本类中所有的方法 Method[] declareMethods=person.getDeclaredMethods(); for(Method declareMethod:declareMethods){ System.out.println("本类中所有的方法:"+declareMethod +" 该方法的访问修饰符="+declareMethod.getModifiers() +" 该方法返回类型="+declareMethod.getReturnType()); //输出当前这个方法的形参数组情况 Class<?>[] parameterTypes=declareMethod.getParameterTypes(); for(Class<?> parameterType:parameterTypes){ System.out.println("该方法的形参类型="+parameterType); } } //getDeclaredConstructors:获取本类中所有的构造器 Constructor<?>[] declaredConstructors=person.getDeclaredConstructors(); for (Constructor<?> declaredConstructor:declaredConstructors){ System.out.println("==============="); System.out.println("本类中所有的构造器="+declaredConstructor.getName()); System.out.println("本类中所有的构造器="+declaredConstructor); Class<?>[] parameterTypes = declaredConstructor.getParameterTypes(); for(Class<?> parameterType:parameterTypes){ System.out.println("该构造器的形参类型="+parameterType); } } } } interface IA{ } interface IB{ } class A { public String hobby; public void hi(){ } public A() { } } @Deprecated class Person extends A implements IA,IB{ //属性 public String name; protected int age; String job; private double sal; public Person(){ } public Person(String name) { } private Person(String name,int age){ } //方法 public void m1(String name,int age,double sal){ } private void m2(){ } protected void m3(){ } void m4(){ } public void m5(){ } }
输出结果:
com.chen.Person
Person
本类以及父类的属性=name
本类以及父类的属性=hobby
本类中所有属性=name
本类中所有属性=age
本类中所有属性=job
本类中所有属性=sal
本类及父类的方法=m5
本类及父类的方法=m1
本类及父类的方法=hi
本类及父类的方法=wait
本类及父类的方法=wait
本类及父类的方法=wait
本类及父类的方法=equals
本类及父类的方法=toString
本类及父类的方法=hashCode
本类及父类的方法=getClass
本类及父类的方法=notify
本类及父类的方法=notifyAll
本类中所有的方法:public void com.chen.Person.m5()
本类中所有的方法:private void com.chen.Person.m2()
本类中所有的方法:void com.chen.Person.m4()
本类中所有的方法:public void com.chen.Person.m1(java.lang.String,int,double)
本类中所有的方法:protected void com.chen.Person.m3()
本类的构造器=com.chen.Person
本类的构造器=com.chen.Person
本类中所有的构造器=com.chen.Person
本类中所有的构造器=private com.chen.Person(java.lang.String,int)
本类中所有的构造器=com.chen.Person
本类中所有的构造器=public com.chen.Person(java.lang.String)
本类中所有的构造器=com.chen.Person
本类中所有的构造器=public com.chen.Person()
package com.chen
以Class形式返回父类信息class com.chen.A
接口信息interface com.chen.IA
接口信息interface com.chen.IB
注解信息=@java.lang.Deprecated()
本类中所有属性=name该属性的修饰符=1 该属性的类型=class java.lang.String
本类中所有属性=age该属性的修饰符=4 该属性的类型=int
本类中所有属性=job该属性的修饰符=0 该属性的类型=class java.lang.String
本类中所有属性=sal该属性的修饰符=2 该属性的类型=double
本类中所有的方法:public void com.chen.Person.m5() 该方法的访问修饰符=1 该方法返回类型=void
本类中所有的方法:private void com.chen.Person.m2() 该方法的访问修饰符=2 该方法返回类型=void
本类中所有的方法:void com.chen.Person.m4() 该方法的访问修饰符=0 该方法返回类型=void
本类中所有的方法:public void com.chen.Person.m1(java.lang.String,int,double) 该方法的访问修饰符=1 该方法返回类型=void
该方法的形参类型=class java.lang.String
该方法的形参类型=int
该方法的形参类型=double
本类中所有的方法:protected void com.chen.Person.m3() 该方法的访问修饰符=4 该方法返回类型=void
===============
本类中所有的构造器=com.chen.Person
本类中所有的构造器=private com.chen.Person(java.lang.String,int)
该构造器的形参类型=class java.lang.String
该构造器的形参类型=int
===============
本类中所有的构造器=com.chen.Person
本类中所有的构造器=public com.chen.Person(java.lang.String)
该构造器的形参类型=class java.lang.String
===============
本类中所有的构造器=com.chen.Person
本类中所有的构造器=public com.chen.Person()
调用运行时类的指定结构
1. 调用指定方法
通过反射,调用类中的方法,通过Method类完成。步骤:
1.通过Class类的getMethod(String name,Class…parameterTypes)方法取得一个Method对象,并设置此方法操作时所需要的参数类型。
2.之后使用Object invoke(Object obj, Object[] args)进行调用,并向方法中传递要设置的obj对象的参数信息。
Object invoke(Object obj, Object … args说明:
1.Object 对应原方法的返回值,若原方法无返回值,此时返回null
2.若原方法若为静态方法,此时形参Object obj可为null
3.若原方法形参列表为空,则Object[] args为null
4.若原方法声明为private,则需要在调用此invoke()方法前,显式调用方法对象的setAccessible(true)方法,将可访问private的方法
例:
package com.chen; //演示通过反射调用方法 import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class ReflecAccessMethod { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { //1.得到Boss 类对应的class对象 Class<?> boossCls=Class.forName("com.chen.Boss"); //2.创建对象 Object o=boossCls.newInstance(); //3调用public的hi方法 Method hi=boossCls.getMethod("hi",String.class); //3.1得到hi方法对象 Method hi2=boossCls.getDeclaredMethod("hi",String.class); hi.invoke(o,"hhhh"); hi2.invoke(o,"hhhh2"); //4.调用private static 方法 //4.1得到say方法对象 Method say=boossCls.getDeclaredMethod("say", int.class, String.class, char.class); //4.2因为say方法private,所以需要爆破,原理和前面讲的构造器和属性一样 say.setAccessible(true); System.out.println(say.invoke(o,100,"栈说","男")); //4.3因为say方法是static,还可以这样用,可以传入null System.out.println(say.invoke(null,200,"栈说2","男")); //5.在反射中,如果方法有返回值,统一返回Object,但是他运行类型和方法定义的返回值类型一致 Object invoke = say.invoke(null, 300, "小明", "男"); System.out.println("reVal的运行类型="+invoke); } } class Boss{//类 public int age; private static String name; public Boss(){ } private static String say(int n,String s,char c){ return n+" "+s+" " +c; } public void hi(String s){ System.out.println("hi "+s); } }
运行结果:
hi hhhh
hi hhhh2
100 栈说 男
200 栈说2 男
reVal的运行类型=300 小明 男
2.调用指定属性
在反射机制中,可以直接通过Field类操作类中的属性,通过Field类提供的set()和get()方法就可以完成设置和取得属性内容的操作。
public Field getField(String name) 返回此Class对象表示的类或接口的指定的public的Field。
public Field getDeclaredField(String name)返回此Class对象表示的类或接口的指定的Field。
在 在Field 中:
public Object get(Object obj) 取得指定对象obj上此Field的属性内容
public void set(Object obj,Object value) 设置指定对象obj上此Field的属性内容
例:
package com.chen; import java.lang.reflect.Field; //演示反射操作属性 public class RefleAccessProperty { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException { //1.得到Student类对应的class对象 Class<?> stuClass=Class.forName("com.chen.Student"); //2.创建对象 Object o=stuClass.newInstance();//o的运行类型就是student System.out.println(o.getClass()); //3.使用反射得到age属性 Field age = stuClass.getField("age"); age.set(o,22); System.out.println(o); System.out.println(age.get(o)); //4.使用反射操作name属性 Field name = stuClass.getDeclaredField("name"); //对name进行爆破 name.setAccessible(true); name.set(o,"小黑"); System.out.println(o); System.out.println(name.get(o)); } } class Student{//类 public int age=20; private static String name; public Student(){ } @Override public String toString() { return "Student{" + "age=" + age + " name=" + name + "}"; } }
输出结果:
class com.chen.Student
Student{age=22 name=null}
22
Student{age=22 name=小黑}
小黑
关于setAccessible
Method和Field、Constructor对象都有setAccessible()方法。
setAccessible启动和禁用访问安全检查的开关。
参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。
提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被调用,那么请设置为true。
使得原本无法访问的私有成员也可以访问
参数值为false则指示反射的对象应该实施Java语言访问检查
调用Class对象的newInstance()方法
1)类必须有一个无参数的构造器。
2)类的构造器的访问权限需要足够。
例:
package com.chen; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; //演示通过反射机制创建实例 public class ReflecCreateInstance { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { //1.先获取User类 Class<?> userClass = Class.forName("com.chen.User"); //2.通过public的无参构造器创建实例 Object o = userClass.newInstance(); System.out.println(o); //3.通过public的参数构造器创建实例 /*constructor对象就是 public User(string name){ this.name=name; } * */ Constructor<?> constructor = userClass.getConstructor(String.class); Object hh = constructor.newInstance("hh"); System.out.println("hh="+hh); //4.通过非public的有参构造器创建实例 //4.1先得到private的构造器对象 Constructor<?> constructor1 = userClass.getDeclaredConstructor(int.class, String.class); //4.2 创建实例 constructor1.setAccessible(true);//爆破,所有反射可以访问private构造器 Object user2=constructor1.newInstance(100,"小明"); System.out.println("user2="+user2); } } class User{ private int age=10; private String name="hello"; public User(){ } public User(String name){ this.name=name; } private User(int age,String name){ this.age=age; this.name=name; } @Override public String toString() { return "User{" + "age=" + age + ", name="" + name + """ + "}"; } }
输出结果:
User{age=10, name="hello"}
hh=User{age=10, name="hh"}
user2=User{age=100, name="小明"}
综合案例:
例1:
/*定义PrivateTest类,有私有name属性,并且属性值为helloKitty
* 提供getName的公有方法
* 创建PrivateTest的类,利用Class类得到私有的name属性,修改私有的name属性值,并调用getName()的方法打印name属性值*/
package com.chen; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class HomeWork01 { public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException { /*定义PrivateTest类,有私有name属性,并且属性值为helloKitty * 提供getName的公有方法 * 创建PrivateTest的类,利用Class类得到私有的name属性,修改私有的name属性值,并调用getName()的方法打印name属性值*/ //1.得到PrivateTest类对应的class对象 Class<PrivateTest> privateTestClass = PrivateTest.class; //2.创建对象实例 PrivateTest privateTest = privateTestClass.newInstance(); //3.得到name属性对象 Field name = privateTestClass.getDeclaredField("name"); //4.爆破name name.setAccessible(true); name.set(privateTest,"天龙八部"); //5.得到getName方法对象 Method getName = privateTestClass.getMethod("getName"); Object invoke = getName.invoke(privateTest); System.out.println("name属性值"+invoke); } } class PrivateTest{ private String name="hellokitty"; public String getName(){ return name; } }
例2
/*
* 利用class类的forName方法得到File类的cass对象
* 在控制台打印File类的所以构造器
* 通过newInstance的方法创建File对象,并创建E:mynew.yxy文件
* */
package com.chen; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class HomeWork02 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { /* * 利用class类的forName方法得到File类的class对象 * 在控制台打印File类的所以构造器 * 通过newInstance的方法创建File对象,并创建E:mynew.yxy文件 * */ //1.class类的forName方法得到File类的class对象 Class<?> fileClass = Class.forName("java.io.File"); //2.得到所有的构造器 Constructor<?>[] declaredConstructors = fileClass.getDeclaredConstructors(); //遍历输出 for (Constructor<?> declaredConstructor:declaredConstructors){ System.out.println("file构造器="+declaredConstructor); } //3.指定的得到public java.io.File(java.lang.String) Constructor<?> declaredConstructor = fileClass.getDeclaredConstructor(String.class); String fileAllPath="D:mynew.txt"; Object file=declaredConstructor.newInstance(fileAllPath); //4.得到createNewFile的方法对象 Method createNewFile = fileClass.getMethod("createNewFile"); createNewFile.invoke(file); //file的运行类型就是File System.out.println(file.getClass()); System.out.println("创建文件成功"+fileAllPath); } }
输出结果:
file构造器=public java.io.File(java.lang.String,java.lang.String)
file构造器=public java.io.File(java.lang.String)
file构造器=private java.io.File(java.lang.String,java.io.File)
file构造器=public java.io.File(java.io.File,java.lang.String)
file构造器=public java.io.File(java.net.URI)
file构造器=private java.io.File(java.lang.String,int)
class java.io.File
创建文件成功D:mynew.txt
注解
什么是注解?
从 JDK 5.0 开始, Java 增加了对元数据(MetaData) 的支持, 也就是Annotation(注解)
Annotation 其实就是代码里的 特殊标记, 这些标记可以在编译, 类加载, 运行时被读取, 并执行相应的处理。通过使用Annotation, 程序员可以在不改变原有逻辑的情况下, 在源文件中嵌入一些补充信息。代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证或者进行部署。
Annotation 可以像修饰符一样被使用, 可用于 修饰包, 类, 构造器, 方 方法 法, 成员变量, 参数, 局部变量的声明, 这些信息被保存在 Annotation的“name=value” 对中
注解是一种趋势,一定程度上可以说:框架 = 注解 + 反射 + 设计模式。
常见的Annotation
示例一:生成文档相关的注解
@author 标明开发该类模块的作者,多个作者之间使用,分割
@version 标明该类模块的版本
@see 参考转向,也就是相关主题
@since 从哪个版本开始增加的
@param 对方法中某参数的说明,如果没有参数就不能写
@return 对方法返回值的说明,如果方法的返回值类型是void就不能写
@exception 对方法可能抛出的异常进行说明 ,如果方法没有用throws显式抛出的异常就不能写
其中
@param @return 和 @exception 这三个标记都是只用于方法的。
@param的格式要求:@param 形参名 形参类型 形参说明
@return 的格式要求:@return 返回值类型 返回值说明
@exception的格式要求:@exception 异常类型 异常说明
@param和@exception可以并列多个
例:
/** * @author shkstart * @version 1.0 * @see Math.java */ public class JavadocTest { /** * 程序的主方法,程序的入口 * @param args String[] 命令行参数 */ public static void main(String[] args) { } /** * 求圆面积的方法 * @param radius double 半径值 * @return double 圆的面积 */ public static double getArea(double radius){ return Math.PI * radius * radius; } }
示例二: 在编译时进行格式查 检查(JDK 内置的三个基本注解
@Override: 限定重写父类方法, 该注解只能用于方法
@Deprecated: 用于表示所修饰的元素(类, 方法等)已过时。通常是因为所修饰的结构危险或存在更好的选择
@SuppressWarnings: 抑制编译器警告
例:
public class AnnotationTest{ public static void main(String[] args) { @SuppressWarnings("unused") int a = 10; } @Deprecated public void print(){ System.out.println("过时的方法"); } @Override public String toString() { return "重写的toString方法()"; } }
示例三: 跟踪 代码依赖性,实现替代配置文件功能
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException { }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
doGet(request, response);
} }
JDK 中的元注解
JDK 的元 Annotation 用于修饰其他 Annotation 定义
RetentionTargetDocumentedInherited
JDK5.0提供了4个标准的meta-annotation类型,分别是:
1. Retention
@Retention: 只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 的生命周期, @Rentention 包含一个 RetentionPolicy 类型的成员变量, 使用
@Rentention 时必须为该 value 成员变量指定值:
ØRetentionPolicy.SOURCE:在源文件中有效(即源文件保留),编译器直接丢弃这种策略的注释
ØRetentionPolicy.CLASS:在class文件中有效(即class保留) , 当运行 Java 程序时, JVM不会保留注解。 这是默认值
ØRetentionPolicy.RUNTIME:在运行时有效(即运行时保留),当 当行 运行 Java 程序时, JVM 会 会保留注释。程序 可以通过反射获取 该注释。
2. Target
用于修饰 Annotation 定义, 用于指定被修饰的 Annotation 能用于修饰哪些程序元素。 @Target 也包含一个名为 value 的成员变量。
3. Documented
@Documented: 用于指定被该元 Annotation 修饰的 Annotation 类将被javadoc 工具提取成文档。默认情况下,javadoc是不包括注解的。
Ø定义为Documented的注解必须设置Retention值为RUNTIME。
4. Inherited
@Inherited: 被它修饰的 Annotation 将具有 继承性。如果某个类使用了被
@Inherited 修饰的 Annotation, 则其子类将自动具有该注解。
Ø比如:如果把标有@Inherited注解的自定义的注解标注在类级别上,子类则可以继承父类类级别的注解
Ø实际应用中,使用较少
自定义 Annotation
定义新的 Annotation 类型使用 @interface 关键字
l 自定义注解自动继承了java.lang.annotation.Annotation 接口
l Annotation 的成员变量在 Annotation 定义中以无参数方法的形式来声明。其方法名和返回值定义了该成员的名字和类型。我们称为配置参数。类型只能
是八种基本数据类型、String 类型 、Class 类型 、enum 类型 、Annotation 类型 、以上所有类型的 数组。
l 可以在定义 Annotation 的成员变量时为其指定初始值, 指定成员变量的初始值可使用 default 关键字
l 如果只有一个参数成员,建议使用 参数名为value
l 如果定义的注解含有配置参数,那么使用时必须指定参数值,除非它有默认值。格式是“参数名 = 参数值”,如果只有一个参数成员,且名称为value,可以省略“value=”
l 没有成员定义的 Annotation 称为 标记; 包含成员变量的 Annotation 称为元数据 Annotation
注意:自定义注解必须配上注解的信息处理流程才有意义。
例:
package com.chen.annotation; import java.lang.annotation.*; //自定义注解 @MyAnnotation2(id=1,name = "s") public class MyAnnotation { //注解可以显示,默认值,如果没有默认值,我们就必须给注解赋值 @MyAnnotation2(id=2,name = "小白",age=21,schools ={"中山大学" } ) public void test(){ } @MyAnnotation3("小黑") public void test2(){ } } @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation2{ //注解的参数:参数类型+参数名(); String name() default ""; int age() default 0; int id() ; String[] schools() default {"清华大学","北京大学"}; } @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation3{ //注解的参数:参数类型+参数名(); String value() ; }
最后通过反射获取注解信息:
package com.chen.annotation; import java.lang.annotation.*; import java.lang.reflect.Field; import java.lang.reflect.Method; //注解和反射 public class AnnotationAndReflect { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { Class<?> aClass = Class.forName("com.chen.annotation.Student"); //通过反射获得注解 Annotation[] annotations = aClass.getAnnotations(); for(Annotation annotation:annotations){ System.out.println(annotation); } //获得注解的value的值 TableStudent tableAnnotation = aClass.getAnnotation(TableStudent.class); String value = tableAnnotation.value(); System.out.println(value); //获得类指定的注解 Field f= aClass.getDeclaredField("name"); FieldStudent annotation = f.getAnnotation(FieldStudent.class); System.out.println(annotation.columnName()); System.out.println(annotation.type()); System.out.println(annotation.length()); System.out.println("---------------"); Field f2= aClass.getDeclaredField("age"); FieldStudent annotation2 = f2.getAnnotation(FieldStudent.class); System.out.println(annotation2.columnName()); System.out.println(annotation2.type()); System.out.println(annotation2.length()); System.out.println("---------------"); Field f3= aClass.getDeclaredField("id"); FieldStudent annotation3 = f3.getAnnotation(FieldStudent.class); System.out.println(annotation3.columnName()); System.out.println(annotation3.type()); System.out.println(annotation3.length()); } } @TableStudent("db_student") class Student{ @FieldStudent(columnName = "db_id",type = "int",length = 10) private int id; @FieldStudent(columnName = "db_age",type = "int",length = 10) private int age; @FieldStudent(columnName = "db_name",type = "varchar",length = 5) private String name; public Student() { } public Student(int id, int age, String name) { this.id = id; this.age = age; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student{" + "id=" + id + ", age=" + age + ", name="" + name + """ + "}"; } } //类名的注解 @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @interface TableStudent{ String value(); } //属性的注解 @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @interface FieldStudent{ String columnName(); String type(); int length(); }
输出结果
@com.chen.annotation.TableStudent(value=db_student)
db_student
db_name
varchar
5
---------------
db_age
int
10
---------------
db_id
int
10
总结
到此这篇关于java中反射和注解的简单使用方法的文章就介绍到这了,更多相关java反射和注解使用内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!
原文链接:https://blog.csdn.net/qq_44716544/article/details/119328268