注解与反射
1 Annotation&Reflection
注解:Annotation , 注释:Comment
since JDK5.0. 注解可以被编译器读取
格式:@注释名
例如:@Override(重写) @Deprecated (废弃)@SuppressWarnings(“all”)(镇压警告)
1.1 元注解
@Retention:注解的保留位置
@Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
@Target:注解的作用目标
@Target(ElementType.TYPE) //接口、类、枚举、注解
@Target(ElementType.FIELD) //字段、枚举的常量
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法参数
@Target(ElementType.CONSTRUCTOR) //构造函数
@Target(ElementType.LOCAL_VARIABLE)//局部变量
@Target(ElementType.ANNOTATION_TYPE)//注解
@Target(ElementType.PACKAGE) ///包
@Document:说明该注解将被包含在javadoc中
@Inherited:说明子类可以继承父类中的该注解
1.2 自定义注解
package com.hujesse.Annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class SelfDefineAnno {
//注解可以显示赋值
@MyAnnotation(age=4,name = "123")
public void test(){ }
// 当只要一个值并且参数名为value时可以省略
@Myannotation2("fuck")
public void tet(){ }
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
// 注解的参数:参数类型+参数名();
String name() default "";
int age();
String [] schools() default {"jialidun"};
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface Myannotation2{
String value();
}
2 Reflection
java是静态语言(还有c,c++),有了反射java变成了准动态语言.
根据类名创建实例(类名可以从配置文件读取,不用new,达到解耦)
new创建对象是静态编译,而反射创建对象是动态编译的过程。动态和静态分别代表的就是运行阶段和编译阶段。
- 【核心定义】java反射机制就是对于任意一个未知的类,都能够创建其对象,调用其方法。
- 反射和new的区别:new只能针对编译阶段已经存在的类,如果在编译时这个类不存在,就无法创建对象,因为你都不知道该new谁。而使用反射,在编译阶段这个类不需要存在,只要在运行时要创建对象的时候存在即可。简单来说,new只能为已知的类创建对象,反射可以为未知的类创建对象。
博文:https://www.cnblogs.com/chanshuyi/p/head_first_of_reflection.html 写的很棒
假如你写了一段代码:Object o=new Object();
运行了起来!
首先JVM会启动,你的代码会编译成一个.class文件,然后被类加载器加载进JVM的内存中,你的类Object加载到方法区中,创建了Object类的Class对象到堆中,注意这个不是new出来的对象,而是类的类型对象,每个类只有一个Class对象,作为方法区类的数据结构的接口。jvm创建对象前,会先检查类是否加载,寻找类对应的Class对象,若加载好,则为你的对象分配内存,初始化也就是代码:new Object()。
反射相关的主要API
一个加载的类在JVM中只会有一个Class实例
Class<?> c1 = Class.forName("com.hujesse.ReflectionTest.user");
Class<?> c2 = Class.forName("com.hujesse.ReflectionTest.user");
Class<?> c3 = Class.forName("com.hujesse.ReflectionTest.user");
Class<?> c4 = Class.forName("com.hujesse.ReflectionTest.user");
// 一个类在内存中只有一个Class对象
// 一个类被加载后,类的整个结构都会被封装在Class对象中
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
System.out.println(c4.hashCode());
// hashcode是一样的,只有一个Class对象
Class类的常用方法
2.1获取Class类的实例
package com.hujesse.ReflectionTest;
public class demo02 {
public static void main(String[] args) throws ClassNotFoundException{
User stu = new student();
System.out.println(stu.name);
//方式一:通过对象获得
Class c1 = stu.getClass();
//方式二:forname获得
Class c2 = Class.forName("com.hujesse.ReflectionTest.student");
// 方式三:通过类名.class
Class c3=student.class;
//方式四 ;基本内置类型的包装类都有一个TYPE属性
Class c4 = Integer.TYPE;
// 获取父类类型
Class superclass = c1.getSuperclass();
}
}
class User{
public String name;
public int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public User() {
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
class student extends User{
public student(){
this.name="student";
}
}
class teacher extends User{
public teacher(){
this.name="teacher";
}
}
2.2 那些类型可以有Class对象?
package com.hujesse.ReflectionTest;
import java.lang.annotation.ElementType;
public class demo03 {
public static void main(String[] args) {
Object c1 = Object.class; //类
Class c2 = Runnable.class; //接口
Class c3 = String.class; //一维数组
Class c4 = int[][].class; // 二维数组
Class c5 =Override.class; //注解
Class c6 =ElementType.class; // 枚举
Class c7 = Integer.class; //基本数据类型 primitive type
Class c8 = void.class; // void
Class c9 = Class.class; // Class
}
}
2.3 Java内存分析
2.4 类的加载过程
当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对改类进行初始化
2.5类的初始化
package com.hujesse.ReflectionTest;
public class demo04 {
static {
System.out.println("main被应用");
}
public static void main(String[] args) throws Exception{
//1 主动引用
//son s = new son();
//2 反射
//Class.forName("com.hujesse.ReflectionTest.son");
//3 不会产生类的引用的方法
System.out.println(son.b);
son[] array = new son[5];
System.out.println(son.M);
}
}
class father{
static int b = 2;
static {
System.out.println("father被加载");
}
}
class son extends father{
static int m =100;
static{
m = 3000;
System.out.println("son被加载");
}
static final int M = 4;
}
2.6 类加载器
核心库:rt.jar
package com.hujesse.ReflectionTest;
public class demo06 {
public static void main(String[] args) throws Exception{
//获取系统类的加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
// 获取系统加载器的父类加载器 -- 》 拓展加载器
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent);
//获取拓展加载器的父类加载器 -- 》根加载器
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);
// 测试当前类是那个加载器加载的
ClassLoader classLoader = Class.forName("com.hujesse.ReflectionTest.User").getClassLoader();
System.out.println(classLoader);
//测试jdk下的类是那个加载器加载的(rt.jar下的根)
ClassLoader classLoader2 = Class.forName("java.lang.String").getClassLoader();
System.out.println(classLoader2); }}
2.7 获取运行时类的完整结构
package com.hujesse.ReflectionTest;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class demo07 {
public static void main(String[] args) throws Exception{
Class c = Class.forName("com.hujesse.ReflectionTest.User");
//1获得类的名字
System.out.println(c.getName()); // 完整路径
System.out.println(c.getSimpleName());
//2 获得类的属性
Field[] fields = c.getFields(); // 只能找到public属性
for (Field field : fields) {
System.out.println(field);
}
Field[] declaredFields = c.getDeclaredFields(); // 得到全部的属性
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
// 获得类的方法
Method[] methods = c.getMethods(); // 获得本类和父类的所以public方法
for (Method method : methods) {
System.out.println(method);
}
Method[] declaredMethods = c.getDeclaredMethods(); // 获得本类的所有方法
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
// 获得指定的方法
// Method getname = c.getMethod("getname", null);
//Method setname = c.getMethod("setname", String.class);
System.out.println("=============");
// 获得指定的构造器
Constructor[] constructors = c.getConstructors(); // 获得public构造器
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
Constructor[] declaredConstructors = c.getDeclaredConstructors(); //获得全部的构造方法包含private的
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
}}
2.8通过反射创建对象
package com.hujesse.ReflectionTest;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
//通过反射创建对象
public class demo08 {
public static void main(String[] args) throws Exception{
// 获得Class对象
Class c1 = Class.forName("com.hujesse.ReflectionTest.User");
// 构造一个对象
User user = (User) c1.newInstance(); //本质调用了无参构造
System.out.println(user);
// 通过反射获取一个方法
Method setname = c1.getDeclaredMethod("setname", String.class);
setname.invoke(user,"hujaja"); //invoke 激活
System.out.println(user.getName());
// 通过反射操作属性
Field name = c1.getDeclaredField("name");
name.setAccessible(true); // 关掉安全检查可以访问到private的属性
name.set(user,"hujaja2");
System.out.println(user.name);
//通过构造器创建对象
Constructor declaredConstructors = c1.getDeclaredConstructor(String.class,int.class);
User user2 = (User)declaredConstructors.newInstance("hujesse", 12);
System.out.println(user2);
}}
setAccessible 作用是启动和禁用访问安全检查的开关
3 获取注解信息
ORM:object relationship Mapping 对象关系映射
package com.hujesse.ReflectionTest;
import java.lang.annotation.*;
import java.lang.reflect.Field;
// 练习反射操作注解
public class deomolast {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c1 = Class.forName("com.hujesse.ReflectionTest.student2");
//通过反射获取注解
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
// 获取注解value的值
TableHu tableHu = (TableHu)c1.getAnnotation(TableHu.class);
String value = tableHu.value();
System.out.println(value);
// 获取类指定的注解
Field name = c1.getDeclaredField("name");
FieldHu fieldHu = name.getAnnotation(FieldHu.class);
System.out.println(fieldHu.columnName());
System.out.println(fieldHu.length());
System.out.println(fieldHu.type());
}
}
@TableHu("db_student")
class student2{
@FieldHu(columnName = "db_id",type = "int",length = 10)
private int id;
@FieldHu(columnName = "db_age",type = "int",length = 10)
private int age;
@FieldHu(columnName = "db_name",type = "int",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 TableHu{
String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldHu{
String columnName();
String type();
int length();
}