反射(Reflection)
什么是反射
概念:
反射机制允许程序在执行期间借助Reflection API取得类的内部信息
使用格式:Class c = Class.forName(“java.lang.String”),此时能通过c来获取String类中的信息
举例:
public class Test2 {
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Student("aaa");
//.name可以返回类名的字符串
System.out.println("is :" + person.name);
//此时我们知道person是一个student类的对象
Class c1 = person.getClass();
System.out.println(c1.hashCode());
//此时我们能够通过c1知道关于person这个类的信息
Class c2 = Class.forName("reflection_study.lession1.Student");
System.out.println(c2.hashCode());
//此时我们能够通过c1知道关于reflection_study.lession1.Student这个类的信息
Class c3 = c2.getSuperclass();
System.out.println(c3.hashCode());
Class c4 = c1.getSuperclass();
System.out.println(c4.hashCode());
}
}
class Person{
String name;
public Person(){
}
public Person(String name) {
this.name = name;
}
}
class Student extends Person{
public Student(String name) {
super("student");
}
}
class Teacher extends Person{
public Teacher() {
super("teacher");
}
}
优缺点:动态编译,但是消耗性能
反射的作用
1.可以通过对对象进行反射得出这个对象的类的信息
2.利用反射获得的信息构建新的对象
具体实现步骤:
1.创建对象
2.获得反射类
获得反射的三种方式
- 类名.class;
- 对象名.getClass();
- Class.forName(“类的路径”);
3.获得反射后进行获取相关类的信息(通过反射的API) - getMethod():存放类的方法
- getField():存放类的属性
- getConstructor():存放类的构造器
- getParent():获得类的父类的反射
举例:
Class c1 = Class.forName("reflection_study.lession2.User");
String str = c1.getName();
System.out.println(str);
//获得属性
Field[] fields = c1.getDeclaredFields();//获得全部权限的属性
for(Field field : fields){
System.out.println(field);
}
Field name = c1.getDeclaredField("name");
System.out.println(name);
System.out.println("==================");
//获得方法
Method[] method = c1.getMethods();//获得本类及其父类的所有公共方法
for (Method method1 : method) {
System.out.println(method1);
}
Method getName = c1.getMethod("getName");
System.out.println(getName);
System.out.println("==================");
Constructor[] constructors = c1.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
4.利用反射获得的信息进行操作
Class c1 = User.class;
//User user = (User)c1.getConstructor().newInstance();
//System.out.println(user);
//利用反射获得的构造器创建对象
System.out.println("====================");
Constructor constructor = c1.getConstructor(String.class, int.class, int.class);
User user2 = (User) constructor.newInstance("xiaoai", 001, 18);
System.out.println(user2);
//利用反射获得的方法
Method setName = c1.getMethod("setName", String.class);
setName.invoke(user2,"aaa");
System.out.println(user2.getName());
User user3 = (User) c1.getConstructor().newInstance();
Field name = c1.getDeclaredField("name");
name.setAccessible(true);//关闭属性访问权限检测,才能改变反射构成的对象的私有成员
name.set(user3,"xiaoai");
System.out.println(user3.getName());
反射获取方法中的泛型
public class Test09 {
public List<User> test01(Map<String,User> map,List<User> list){
return null;
}
public Map<String,User> test02(){
System.out.println("test01");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
Method method = Test09.class.getMethod("test01", Map.class, List.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
System.out.println("#"+genericParameterType);
if (genericParameterType instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
Method method2 = Test09.class.getMethod("test02");
Type genericReturnType = method2.getGenericReturnType();
System.out.println(genericReturnType);
}
}
注解(Annotation)
什么是注解
概念:
1.简单来说:注解就是对程序作出的解释,同时能够被其他程序读取.
2.注解可以理解成一个标签,是给类、方法、变量、属性等加标签
3.注解的实现是通过反射获取注解的内容,并且这些内容会被编译器实现到生成类文件中.
注解有什么用:
1、提供信息给编译器: 编译器可以利用注解来探测错误和警告信息
2、编译阶段时的处理: 软件工具可以用来利用注解信息来生成代码、Html文档或者做其它相应处理。
3、运行时的处理: 某些注解可以在程序运行的时候接受代码的提取
注解分类及其内容:
内置注解:
- @Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
- @Deprecated - 标记过时方法。不推荐使用此方法.
- @SuppressWarnings - 镇压警告,不让编译器警告.
元注解:用于解释其它注解的注解 - @Retention - 标识被修饰的注解的有效范围,(也就是保存位置)是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。(对应参数分别是:source<class<runtime)
- @Documented - 表示被修饰的注解是否包含在JavaDoc中。
- @Target - 描述被修饰的注解的使用范围(比如:参数value = ElementType.METHOD,就说明这个被修饰的注解只能用于修饰方法)。
- @Inherited - 表示子类可以继承父类的注解(默认 注解并没有继承于任何子类)
自定义注解:
格式:@interface 自定义的注解名
步骤:
1.定义范围(作用范围,运行范围,是否继承,是否在文档中显示)
2.定义名称(格式:@interface 注解名)
3.定义参数(格式:参数类型 参数名())
举例:
public class Test1 {
@MyAnnotation(name = "aaa",schools = "bbb")
public void test(){
}
}
//自定义注解
@Target(value = ElementType.METHOD)//此注解的作用范围:只能修饰方法
@Retention(value = RetentionPolicy.RUNTIME)//此注解的保存位置:运行时有效
@interface MyAnnotation{
//注解的参数格式:参数类型 参数名()
String name() default "";//default的意思是这个参数可以不用写,默认为空字符串
int id() default -1;
int age() default 0;
String[] schools() default {"aaa","bbb"};
}
练习ORM
通过前面的了解我们可以知道,反射可以获取类的信息,同样反射也能过获得注解的信息
1.我们定义了自己的注解
2.将注解放在了我们定义的类或者方法中
3.通过反射的方法,我能获得我们放在类上的注解
4.我们就能知道注解的相关信息
public class Test8 {
//练习ORM
//Object relationship Mapping
//类对应到表上
public static void main(String[] args) throws NoSuchFieldException {
Class<Student2> c1 = Student2.class;
//通过反射获得注解
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//获得注解的value的值
Table table = c1.getAnnotation(Table.class);
String value = table.value();
System.out.println(value);
java.lang.reflect.Field id = c1.getDeclaredField("id");
Field annotation = id.getAnnotation(Field.class);
System.out.println(annotation.columnName());
System.out.println(annotation.type());
System.out.println(annotation.length());
System.out.println("========");
System.out.println(new Student2());
}
}
//对student2的注解
@Table("db_student")
class Student2{
@Field(columnName = "db_id",type = "int",length = 10)
private int id;
@Field(columnName = "db_age",type = "int",length = 10)
private int age;
@Field(columnName = "db_name",type = "varchar",length = 10)
private String name;
public Student2() {
}
public Student2(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 "Student2{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
//对类的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table{
String value();
}
//对属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Field{
String columnName() default "aaa";
String type();
int length();
}
在这个程序中,我们是通过反射获得注解,并的到注解的信息
但是注解的使用是十分灵活的,并不限制于此,这个的作用根本是提供了一个能让编译器知道我修饰的这个成员或这类是什么…