Java反射

Java反射

反射可以通过对象获得该对象的类,并通过类获得该类的包名

Class c= Class.forName("包名.类名")

Class 本身也是一个类,但是只能由系统创建。

一个加载的类在JVM中只会有一个Class实例

一个Class对象对应一个class文件

每个类的实例都会记得自己是由那个Class实例所生成的

通过Class可以完整的得到一个类中的所有被加载的结构

Class类时Reflection的根源,针对想获得动态加载、运行的类,唯有先获得相应的Class对象

反射相关的主要API

  1. Class

  2. Method

  3. Field

  4. Constructor

如何获得Class 类的实例?

  1. Class class =Person.class//直接通过类的class属性获得

  2. Class class = person.getClass();//直接通过类的实例获得

  3. Class class = Class.forName("包名.类名")//通过Class类的静态方法forName()获取可能抛出一个异常

  4. 内置基本数据类型可以直接用类名

Class class =Integer.TYPE

  1. Class class =class.getSuperclass()//获得父类的类型

  2. 还可以利用ClassLoader获取Class

有哪些类型可以有Class对象

  1. 所有的类都有Class对象

  2. interface

  3. 数组[]

  4. enum枚举

  5. annotation注解

  6. primitive type 基本数据类型

  7. void

Java内存分析(理解Class)

堆存放new的对象和数组

栈存放基本变量类型和引用对象的变量

方法区存放所有的class和static变量

类加载的过程

  1. 加载Load

将类的calss文件读入内存,并为之创建一个java.lang.Class对象。此过程由类加载器完成

  1. 类的链接Link

将类的二进制数据合并到JRE中,所有的static和常量和默认初始值,都在这个阶段已经完成

  1. 类的初始化Initialize

JVM负责对类进行初始化,clinit()方法

什么时候会发生类的初始化?

主动引用的时候会发生类的初始化

主动引用包括:

  1. 虚拟机启动时,初始化main方法所在的类;

  2. new一个类的对象;

  3. 调用静态成员(除了final)和方法;

  4. 使用reflect包反射调用;

  5. 子类初始化会先初始化父类。

类的被动引用不会初始化。包括:

  1. 通过数组定义类引用,不会触发初始化,因为只是声明空间但是没有指向具体对象所以没有触发类的初始化;

  2. 引用常量不会触发;

  3. 访问一个静态域时,只有真正声明这个域的类才会被初始化。如通过子类引用父类的静态变量,不会导致子类的初始化,因为父类的静态变量已经事先初始化好了。

类加载器

  1. 引导类加载器

JVM自带的,负责Java平台核心库(rt.jar),该加载器无法直接获取

  1. 扩展类加载器

负责jre/lib/ext目录下的jar包或-D java.ext.dirs指定目录下的jar包装入工作库

  1. 系统类加载器

负责java-classpath或-D java.class.path所指的目录下的类,与jar包装入工作,是最常用的加载器

系统类加载器实例:

ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();//系统类加载器
​
ClassLoader parent =systemClassLoader.getParent();//获取扩展类加载器
​
Class.forName("com.sdds.xxx").getClassLoader();

双亲委派机制

如果用户自定义了一个String包,那么一定是在系统类加载器的范围内。java会自动搜索扩展类加载器或者引导类加载器内是否存在String包,如果存在,则自定义包String失效。

Class类的方法

class.getName();//获得包名和类名
class.getSimpleName();//获得类名
​
class.getFields();//获得类的public属性
class.getDeclaredFields();//得到类的全部属性
​
class.getMethods();//获得正常的public method包括继承的方法
class.getDeclaredMethods();//获得本类的所有方法
Method w=class.getMethod("方法名",参数类型.class...);//获取指定的方法
​
Constructor[] cons= class.getConstructors();//获得public的构造器
Constructor con = class.getConstructor();//获得本类的全部方法包括private
class.getDeclaredConstructor(参数类型.class....);
​
User u = (User) class.newInstance();//构造类的对象,调用了类的无参构造器
​
Construct constructor =class.getDeclaredConstructor(String.class);
User user2 =(User)constructor.newInstance("张三");//获取有参数的构造函数
​
Method setName = class.getDeclaredMethod("setName",String.class);
setName.invoke(传递的对象,传递的值);//这样就能使用函数了
​
    
Field name = class.getDeclaredField("name");//获得指定的属性名(私有)
name.setAccessible(true);//打开修改权限,私有的方法可以直接执行
name.set(指定的对象,指定的值);//修改指定对象的属性为指定的值
​
​

反射调用的运行速度比较慢(和正常调用比较)。

反射操作泛型

首先介绍四各类:

  1. ParameterizedType:表示一种参数化类型如List<String>

  2. GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型

  3. TypeVariable:是各种类型变量的公共父接口

  4. WildcardType:代表一种通配符类型表达式

例子:

public class Test{
    public void test(Map<String,User> map,List<User> list){
    sout(test);
    }
​
​
    public static coid main(String[] args) throws NoSuchMethodException {
        Method method =Test.class.getMethod("test",Map.class,List.class);
        Type[] genericParameterTypes =method.getGenericParameterTypes();
        //此时该变量成员有两个即java.util.Map<....>和java.util.List<...>
        for(Type genericParameterType : genericParameterTypes){
            if(genericParameterType instanceof ParameterizedType){
            ((ParameterizedType)genericParameterType).getActualTypeArguments();//
                //此时改成员变量有两个一个为String,一个为User 第二个循环该变量有一个为User
         }
        }
        
      
    }
}
​

反射获取注解

ORM(object relationship mapping)

即每new出来一个对象,对应于数据库中表的一行,对象的每一个属性对应着数据库表的一列

因此,可以通过注解和反射完成类和表的结构的映射关系

实例

@Table1("Db_Students")//对对象注解
class Student{
    @Field1(columnName="Db_Id",type="int",length=10)
    private int id;//对属性进行注解
    @Field1(columnName="Db_Age",type="int",length=10)
    private int age;
    @Field1(columnName="Db_Name",type="varchar",length=10)
    private String name;
}
​
​
@Target(ElementType.Type)//使用范围为对象
@Retention(RetentionPolicy.Runtime)//在运行级别
@interface Table1{
    String value();
}
​
​
@Target(ElementType.Fiele)//使用范围为属性
@Retention(RetentionPolicy.Runtime)//在运行级别
@interface Field1{
    String columnName();
    String type();
    int length();
}
public static void main(String[] args) {
    Class class = Class.forName(...);//获取Class对象
    Annotation[] annotations = class.getAnnotations();
    for(Annotation annotation : annotations){
        sout(annotation);//此时会输出外面对象的注解即@Table1(value=DbStudents)
    }
    Annotation annotation =(Annotation)class.get(Annotation(Table1.class));
    String c = annotation.value();
    sout(c);//此时会显示Db_Students
    
    //获得类的注解
    Field f =class.getDeclaredField("name");//参数填上指定的属性名
    Field1 annotation = f.getAnnotation(Field1.class);
    sout(annotation.type());//显示想要显示的注解属性
    }
​
​
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

万军j

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值