反射(Reflection):
动态语言:
在运行时可以改变其结构的语言。例如:Object-C,C#,JavaScript,PHP,Python。
反射是Java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API获得类的任何内部信息,并能直接操作任意对象的内部属性及方法。
//主要API
java.lang.Class//代表一个类
java.lang.reflect.Method//代表类的方法
java.lang.reflect.Field//代表类的成员变量
java.lang.reflect.Constructor//代表类的构造器
//Object类中定义了如下方法,此方法被所有的子类继承
public final Class getClass();
//返回值是一个Class类,此类是Java反射的源头,实际上所谓反射从程序的运行结果来看:通过对象反射求出类的名称。
正常方法与反射方法的对比:
正常方法:1:引入需要的"包类"名称。2:通过new实例化。3:取得实例化对象
反射方法:1:找到实例化对象。2:使用getClass()方法。3:得到完整的"包类"名称
优点:可以实现动态创建对象和编译,体现出很大的灵活性。
缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么,并且它能满足我们的要求。这类操作总是慢于直接执行相同的操作。
那些有Class对象:class,interface,[],enum,annotation,primitive type(基本数据类型),void
Class c1=Object.class;//类
Class c2=Comparable.class;//接口
Class c3=String[].class;//一维数组
Class c4=int[][].class;//二维数组
Class c5=Override.class;//Override注解
Class c6=ElementType.class;//枚举
Class c7=Integer.class;//基本数据类型
Class c8=void.class;//void
Class c9=Class.class;//Class
//只要元素类型与维度一样,就是同一个Class,例如下面的 a和b
int[] a=new int[10];
int[] b=new int[100];
获得类的运行时结构:
Class c1=Object.class;//类
c1.getMethods();//获得全部方法
c1.getDeclaredMethod();//获得指定方法
//其他的类似(属性,构造器)
反射可以做什么?
创建类的对象:
调用Class对象的newInstance()方法:
①:类必须有一个无参数的构造器。
②:类的构造器的访问权限需要足够。
反射操作泛型:
ParameterrizedType:表示一种参数化类型,比如Collection<String>。
GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型。
TypeVariable:是各种类型变量的公共父接口。
WildcardType:代表一种通配符类型表达式。
反射操作注解:
//c1是一个反射对象
c1.getAnnotations();//获得类所有的注解
c1.getAnnotation();//获得类指定的注解
反射相关操作练习:
public class Test1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c1=Class.forName("s202303.Thread.User");//路径
//输出c1
System.out.println(c1);
Method[] methods=c1.getMethods();
//输出c1中的方法
for(Method method:methods){
System.out.println(method);
}
//一个类在内存中只有一个Class对象
//一个类被加载后,类的整个结构都会被封装在Class对象中
Class c2=Class.forName("s202303.Thread.User");
Class c3=Class.forName("s202303.Thread.User");
Class c4=Class.forName("s202303.Thread.User");
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
System.out.println(c4.hashCode());
//三个输出是一样的
//获得反射的途径
User user=new User();
//通过对象获得
Class c5=user.getClass();
//通过forName获得
Class c6=Class.forName("s202303.Thread.User");
//通过类名.class获得
Class c7=User.class;
//基本内置类型的包装类都有一个Type属性
Class c8=Integer.TYPE;
//通过反射获得对象的注解
Annotation[] annotations=c1.getAnnotations();
for (Annotation annotation :annotations) {
System.out.println(annotation);
}
//获得注解的value的值
TableSong table=(TableSong) c1.getAnnotation(TableSong.class);
System.out.println(table.value());
//获得类指定的注解
Field f=c1.getDeclaredField("name");
FieldSong annotation=f.getAnnotation(FieldSong.class);
System.out.println(annotation.age());
System.out.println(annotation.Name());
System.out.println(annotation.id());
}
}
//实体类
@TableSong("user")
public class User{
@FieldSong(Name = "userName" ,id=1,age=10)
private String name;
private int id;
private int age;
public User(){
}
public User(String name,int id,int age){
this.name=name;
this.age=age;
this.id=id;
}
public String getName() {
return name;
}
public void setName(String name) {
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;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
'}';
}
}
//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableSong{
String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldSong{
String Name();
int id();
int age();
}