自己快速了解到的反射和注解,存在很多理解不对的地方,日后深入了解后再回头修改。发在这里相当于一个云端存储方式了=。=
定义:
类User
class User{
private String name;
private int id;
private int age;
public User(){
}
public User(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setId(int id) {
this.id = id;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
'}';
}
}
c1 c2等指的是class对象
1 反射
目前对反射的一个模糊理解,通过反射可以得到一个class类的一个样板,拿着这个样板一样的东西,可以访问这个类里的任何东西:属性、方法、构造方法,哪怕是用private修饰的也可以取到;
有了class的反射,也可以进行创建对象、调用方法各种操作
1.1 如何获取类的反射
-
方式1: Class.forName(包名+类名)
Class c1 = Class.forName("com.qing.reflection.User");
-
方式2:通过对象获得
Person person = new Student(); Class c1 = person.getClass();
-
方式3:类名.class
Class c4 = Student.class;
-
方式4:基本类型的包装类型的Type属性
Class<Double> type = Double.TYPE;
-
方式5:获得父类的类型
Class c5 = c1.getSuperclass();
System.out.println(c5);
1.2 获取类的名称、属性、方法
名称:
System.out.println(c1.getName()); //包名+类名 System.out.println(c1.getSimpleName()); //获得类的简单名字
运行结果
com.qing.reflection.User
User
属性
获得public的属性
//获得类的属性
Field[] fields = c1.getFields(); //这种方式只能获得public的属性
for(Field field:fields){
System.out.println(field);
}
System.out.println("-----------------------------------");
获得所有的属性
//getDeclaredFields(); 可以获得类的所有属性 private 、 public
Field[] declaredFields = c1.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
指定方式获取类的属性
Field name1 = c1.getDeclaredField("name");
System.out.println(name1);
分别对应的打印结果
private java.lang.String com.qing.reflection.User.name
private int com.qing.reflection.User.id
private int com.qing.reflection.User.age
-----------------------------------
private java.lang.String com.qing.reflection.User.name
方法
获得类的方法
Method[] methods = c1.getMethods(); //获得本类以及父类的所有方法
for (Method method : methods) {
System.out.println("getMethods():"+method);
}
输出结果
getMethods():public java.lang.String com.qing.reflection.User.toString()
getMethods():public java.lang.String com.qing.reflection.User.getName()
getMethods():public int com.qing.reflection.User.getId()
getMethods():public void com.qing.reflection.User.setName(java.lang.String)
getMethods():public int com.qing.reflection.User.getAge()
getMethods():public void com.qing.reflection.User.setId(int)
getMethods():public void com.qing.reflection.User.setAge(int)
getMethods():public final void java.lang.Object.wait() throws java.lang.InterruptedException
getMethods():public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
getMethods():public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
getMethods():public boolean java.lang.Object.equals(java.lang.Object)
getMethods():public native int java.lang.Object.hashCode()
getMethods():public final native java.lang.Class java.lang.Object.getClass()
getMethods():public final native void java.lang.Object.notify()
getMethods():public final native void java.lang.Object.notifyAll()
可以看到有父类Object对应的方法和自身的几个方法
只获得本类的所有方法
//c1.getDeclaredMethods(); 只获得本类的所有方法
Method[] declaredMethods = c1.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println("getDeclaredMethods(): "+declaredMethod);
}
输出结果
getDeclaredMethods(): public java.lang.String com.qing.reflection.User.toString()
getDeclaredMethods(): public java.lang.String com.qing.reflection.User.getName()
getDeclaredMethods(): public int com.qing.reflection.User.getId()
getDeclaredMethods(): public void com.qing.reflection.User.setName(java.lang.String)
getDeclaredMethods(): public int com.qing.reflection.User.getAge()
getDeclaredMethods(): public void com.qing.reflection.User.setId(int)
getDeclaredMethods(): public void com.qing.reflection.User.setAge(int)
获得指定方法
//获得指定方法
Method getName = c1.getMethod("getName", null);
System.out.println(getName);
Method setName = c1.getMethod("setName", String.class);
System.out.println(setName);
//获得指定的方法时,输入方法名字,以及方法需要的参数类型,参数类型是参数对应的class对象
获取指定方法时,如果方法有参数就传入参数类型对应的class
输出结果:
public java.lang.String com.qing.reflection.User.getName()
public void com.qing.reflection.User.setName(java.lang.String)
获取构造方法
System.out.println("-----------------------------------");
//获得构造器
Constructor[] constructors = c1.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
Constructor[] declaredConstructors = c1.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
//获取指定的constructor
Constructor cstor2 = c1.getConstructor(String.class, int.class, int.class);
System.out.println(cstor2);
Constructor cstor3 = c1.getConstructor();
System.out.println(cstor3);
输出结果:
public com.qing.reflection.User()
public com.qing.reflection.User(java.lang.String,int,int)
public com.qing.reflection.User()
public com.qing.reflection.User(java.lang.String,int,int)
public com.qing.reflection.User(java.lang.String,int,int)
public com.qing.reflection.User()
和上面的调用方式没有什么区别,参数传递、不同方法类型声明的区别
1.3 反射操作-----对象、方法、属性
创建对象:
newInstance:
//获得class对象
Class c1 = Class.forName("com.qing.reflection.User");
//构造一个对象
User user =(User) c1.newInstance();
System.out.println(user);
构造器方式:
//通过构造器创建对象, 这种方式是真滴变态
Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
User user2 = (User) constructor.newInstance("wtq", 1, 18);
方法调用:
//通过反射调取一个方法
Method setName = c1.getDeclaredMethod("setName", String.class);
setName.invoke(user2,"qingshen");
System.out.println(user2.getName());
//这也太离谱了,得到Class对象,获取该Class对象中的方法如setName,方法的对象
//setName 再调用invoke 指定某个具体的实例,对这个实例进行操作
//setName.invoke(user2,"qingshen");等价于 user2.setName("qingshen");
//但是setName可以操作所有的实例
//--------------------------------------------------------------------------
属性操作:
//通过反射操作属性
User user4 =(User) c1.newInstance();
Field name = c1.getDeclaredField("name");
//因为name属性是私有的,这样访问会产生非法访问异常
name.setAccessible(true); //这样就可以破坏属性的private修饰限定,也就是破坏封装性,关闭安全检测
name.set(user4,"guangqi");
System.out.println(user4);
}
name.setAccessible(true); //这样就可以破坏属性的private修饰限定,也就是破坏封装性,关闭安全检测
输出结果:
User{name='null', id=0, age=0}
User{name='wtq', id=1, age=18}
18
qingshen
User{name='guangqi', id=0, age=0}
1.4反射的性能
通过反射的方式调用并执行方法,性能是不如常规的方式,setAccessible(true); 可以提升反射的性能
package com.qing.reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//分析性能问题
public class Test10 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException {
test01();//2ms
test02();//1224ms
test03();//796ms
//关闭检测setAccessible=true 可以提高反射的效率
}
//普通方式调用
public static void test01(){
User user = new User();
long starTime = System.currentTimeMillis();
for(int i=0;i<1000000000;i++){
user.getName();
}
long endTime = System.currentTimeMillis();
System.out.println((endTime-starTime)+"ms");
}
//反射方式调用
public static void test02() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class c1 = Class.forName("com.qing.reflection.User");
Method getName = c1.getDeclaredMethod("getName", null);
User user =(User) c1.newInstance();
long starTime = System.currentTimeMillis();
for(int i=0;i<1000000000;i++){
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println((endTime-starTime)+"ms");
}
//反射方式+setAccessible=true
public static void test03() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class c1 = Class.forName("com.qing.reflection.User");
Method getName = c1.getDeclaredMethod("getName", null);
User user =(User) c1.newInstance();
getName.setAccessible(true);
long starTime = System.currentTimeMillis();
for(int i=0;i<1000000000;i++){
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println((endTime-starTime)+"ms");
}
}
1.5 通过反射获取方法的泛型类型的参数
方法的定义
public void test01(Map<String,User> map, List<User> list){
System.out.println("test01");
}
public Map<String,User> test02(){
System.out.println("test02");
return null;
}
方法泛型参数:
public static void main(String[] args) throws NoSuchMethodException {
Method method = Test11.class.getMethod("test01", Map.class, List.class);
Type[] gPTypes = method.getGenericParameterTypes();
for (Type gPType : gPTypes) {
if(gPType instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) gPType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
System.out.println("------------------------------");
- 先通过method获取泛型类型参数getGenericParameterTypes()
- 再判断gPType instanceof ParameterizedType
- 强转为ParameterizedType,获取实际的泛型类型getActualTypeArguments()
- 遍历返回的Type[] actualTypeArguments
输出结果:
class java.lang.String
class com.qing.reflection.User
class com.qing.reflection.User
------------------------------
对应:test01(Map<String,User> map, List<User> list)
方法泛型返回类型:
//通过反射获取返回值的泛型
method = Test11.class.getMethod("test02",null);
Type gPType1 = method.getGenericReturnType();
if(gPType1 instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) gPType1).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
和上面不一样的地方就是调用method.getGenericReturnType();
输出结果:
class java.lang.String
class com.qing.reflection.User
2注解
不精确的理解:注释是写给人看的,注解是写给程序的;虽然代码程序都是给人看的,但是注释里的内容,完全不会影响到程序的执行,而注解可以
1.常见的注解
@Override重写
@Override
public String toString() {
return super.toString();
}
@Deprecated
表示此方法已废弃、暂时可用,但以后此类或方法都不会再更新、后期可能会删除,建议后来人不要调用此方法
@Deprecated
public static void test(){
System.out.println("@Deprecated");
}
@SuppressWarnings(“all”)
镇压一切警告,比如上面使用Deprecated 方法的警告
//镇压警告
@SuppressWarnings("all")
public void test02(){
List list = new ArrayList();
}
2.自定义的注解
@Target
//target作用是限定注解的作用域,TYPE--类 METHOD--方法
@Target(value= {ElementType.METHOD,ElementType.TYPE})
@Retention
//@Retention表示我们的注解在什么地方还有效
//runtime>class>sources
@Retention(value = RetentionPolicy.RUNTIME) //注解只有一个值时,value可带可不带
@Documented
//@Documented表示是否将我们的注解生成在JAVAdoc中
@Documented
@Inherited
//@Inherited 子类可以继承父类的注解
@Inherited
@interface MyAnnotation{
}
3. 注解中的参数
@MyAnnotation2
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
//注解的参数:参数类型 + 参数名 ()
String name() default ""; //这里设置了name的默认值为NULL
int age() default 0;
int id() default -1; //如果默认值为-1,代表不存在
String[] schools() default {"东北大学"};
}
使用:
//注解可以显式赋值,没有默认值,我们必须给注解赋值
@MyAnnotation2(name="wtq",schools = {"NEU"}) //注解没有赋值顺序
public void test(){
}
@MyAnnotation3
@MyAnnotation3("wtq")
public void test2(){
}
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3{
String value(); //当注解只有一个参数时,如果想省略参数名赋值,参数的名称必须是value
//否则必须加上参数名 比如name=
}
3注解与反射
package com.qing.reflection;
import java.lang.annotation.*;
import java.lang.reflect.Field;
//练习反射注解
public class Test12 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c1 = Class.forName("com.qing.reflection.student2");
//通过反射获取注解
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//获取注解value的值
TableQing tableQing=(TableQing) c1.getAnnotation(TableQing.class);
String value = tableQing.value();
System.out.println(value);
//获取类的指定注解
//FieldQing fieldQing =(FieldQing) c1.getAnnotation(FieldQing.class);
Field name = c1.getDeclaredField("name");
Field[] declaredFields = c1.getDeclaredFields();
for (Field declaredField : declaredFields) {
FieldQing annotation2 = declaredField.getAnnotation(FieldQing.class);
System.out.println(annotation2.columnName());
System.out.println(annotation2.type());
System.out.println(annotation2.length());
System.out.println("------------------");
}
FieldQing annotation = name.getAnnotation(FieldQing.class);
}
}
@TableQing("db_student")
class student2{
@FieldQing(columnName = "db_id",type ="int",length = 10)
private int id;
@FieldQing(columnName = "db_age",type ="int",length = 10)
private int age;
@FieldQing(columnName = "db_name",type ="varchar",length = 3)
private String name;
public student2(){
}
public student2(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
}
//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableQing{
String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldQing{
String columnName();
String type();
int length();
}
以数据库为例
类名注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableQing{
String value();
}
属性注解:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldQing{
String columnName(); //列名
String type(); //属性
int length();//长度
}
反射获取注解:
标注注解的类:
@TableQing("db_student")
class student2{
@FieldQing(columnName = "db_id",type ="int",length = 10)
private int id;
@FieldQing(columnName = "db_age",type ="int",length = 10)
private int age;
@FieldQing(columnName = "db_name",type ="varchar",length = 3)
private String name;
public student2(){
}
public student2(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
}
自定义的注解:
//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableQing{
String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldQing{
String columnName();
String type();
int length();
}
getAnnotations();
Class c1 = Class.forName("com.qing.reflection.student2");
//通过反射获取注解
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
获取注解的value值:
//获取注解value的值
TableQing tableQing=(TableQing) c1.getAnnotation(TableQing.class);
String value = tableQing.value();
System.out.println(value);
获取指定的注解:
Field name = c1.getDeclaredField("name");
遍历某个指定类型的所有注解:
Field[] declaredFields = c1.getDeclaredFields();
for (Field declaredField : declaredFields) {
FieldQing annotation2 = declaredField.getAnnotation(FieldQing.class);
System.out.println(annotation2.columnName());
System.out.println(annotation2.type());
System.out.println(annotation2.length());
System.out.println("------------------");
}
输出结果
@com.qing.reflection.TableQing(value=db_student)
db_student
db_id
int
10
------------------
db_age
int
10
------------------
db_name
varchar
3
------------------
小结:
- 反射得到class
- 调用getAnnotation(),从输出结果看只能得到类的注解,属性的注解没有获取到
- class.getAnnotation(注解.class) 可以获取指定类型的注解
- 获取属性注解需要先调用getDeclaredFields();
- 属性注解的参数获取:declaredField.getAnnotation(FieldQing.class);
- annotation2+注解参数名
只要是想获取注解参数,就要先获取注解类型的对象,通过这个对象得到注解中的参数