java教程 反射

一、java反射概念

反射是java被视为动态语言的关键,反射机制允许程序在执行期间借助于Reflection api 取得任何类的内部信息,并能直接操作任意对象的内部的属性和方法。

  • 获取任何类的内部构成信息。
  • 直接操作任意对象的内部属性和方法。

二、java反射作用与相关API

反射能做什么

  • 在运行时判断任意一个对象所属类。
  • 在运行时新建任意一个类的实例。
  • 在运行时判断任意一个类所具有的成员属性和方法。
  • 在运行时调用任意一个对象的成员属性和方法。
  • 生成动态代理。

反射相关API

  • java.lang.Class : 代表一个类;
  • java.lang.reflect.Method : 代表类的方法;
  • java.lang.reflect.Field : 代表类的属性;
  • java.lang.reflect.Constructor : 代表类的构造器方法;

三、java反射的关键类 Class

1、Class类简介
在java的世界里,一切皆对象。从某种意义来讲,java中有两种对象:实例对象和Class对象。每个类的运行时的类型信息就是用Class对象表示的。它包含了与类相关的信息;我们的实例对象就是通过Class对象来创建的;java使用Class对象执行其RTTI(运行时类型识别),多台是基于RTTI实现的;
每一个类都有一个Class对象,每当编译一个新类就产生一个Class对象,基本类型(boolean, byte, short, int, long, float , double)有Class对象,数组有Class对象,关键字void也有Class对象(void.class)。Class对象对应着java.lang.Class类。Class类没有公共的构造方法,Class对象是在类加载的时候由java虚拟机以及通过调用类加载器中的defineClass方法自动构造的,因此不能显式地声明一个Class对象. 当.class文件加载到内存以后,就是一个运行时类,存放于缓存区,此时这个运行时类本身就是一个Class类型的实例。

  • 每个运行时类只加载一次,且线程安全。
  • 有了Class实例之后,我们才可以进行反射操作。

2、Class类型对象常用方法

方法名说明
forName()(1)获取Class对象的一个引用,但引用的类还没有加载(该类的第一个对象没有生成)就加载了这个类。
(2)为了产生Class引用,forName()立即就进行了初始化。
Object-getClass()获取Class对象的一个引用,返回表示该对象的实际类型的Class引用。
getName()取全限定的类名(包括包名),即类的完整名字。
getSimpleName()获取类名(不包括包名)
getCanonicalName()获取全限定的类名(包括包名)
isInterface()判断Class对象是否是表示一个接口
getInterfaces()返回Class对象数组,表示Class对象所引用的类所实现的所有接口。
getSupercalss()返回Class对象,表示Class对象所引用的类所继承的直接基类。应用该方法可在运行时发现一个对象完整的继承结构。
newInstance()返回一个Oject对象,是实现“虚拟构造器”的一种途径。使用该方法创建的类,必须带有无参的构造器。
getFields()获得某个类的所有的公共(public)的字段,包括继承自父类的所有公共字段。 类似的还有getMethods和getConstructors。
getDeclaredFields()获得某个类的自己声明的字段,即包括public、private和proteced,默认但是不包括父类声明的任何字段。类似的还有getDeclaredMethods和getDeclaredConstructors。
getMethods
getDeclaredMethods
getConstructors
getDeclaredConstructors

3、获取Class类型实例

  • 通过运行时类本身的.class属性获取 Class 实例。
Class clazz = Person.class;
Class clazz1 = String.class;
System.out.println( clazz.getName() );  #获取类完整名。
System.out.println( clazz1.getPackage() ); #获取类所在的包名。
  • 通过运行时类的对象.getClass()方法获取 Classs 实例。
Perosn person = new Person();
Class clazz = person.getClass();
  • 通过 Class 的静态方法获取 Class 实例。
String className = "com.mz.Person";
Class clazz = Class.forName(className);
System.out.println(clazz.getName());

三、java类加载器 ClassLoader

1、类加载器简介

当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对类进行初始化。
在这里插入图片描述

  • 类的加载 :
    将类的class文件读入内存,并为之创建一个java.lang.Class对象,此过程由类加载器完成。
  • 类的连接 :
    将类的二进制数据合并到JRE中。
  • 类的初始化 :
    JVM负责对类进行初始化。

类加载器是用来把类(class)装载到内存中的,JVM规范定义了两种类型的类加载器: 启动类加载器Bootstrap用户自定义类加载器user-defined classLoader.JVM在运行时会产生3个类加载器组成的初始化加载器层次结构。双亲委派机制
在这里插入图片描述

  • Bootstrap classLoader 引导器加载器 :
    用c++编译,是jvm自带的类加载器,负责java平台核心库,用来加载核心类库,该加载器无法直接获取。
  • Extension classLoader 扩展器加载器 :
    负责jre/lib/ext目录下的jar包,或-D java.ext.dirs指定目录下的jar包装入工作库。
  • System classLoader 系统类加载器 :
    负责应用的类路径下的jar包加载。

2、 获取classloader的方式

#方式1
ClassLoader  loader1 = ClassLoader.getSystemClassLoader();
System.out.println( loader1 );

#方式2
ClassLoader loader2 = loader1.getParent();
System.out.println( loader2 );

#方式3
Class clazz = Person.class;
ClassLoader  loader3 = clazz.getClassLoader();
System.out.println( loader3 );

#方式4
String className = "java.lang.Object";
class clazz4 = Class.forName(className);
#java核心类库的classLoader是不能获取到的。
ClassLoader loader4 = clazz4.getClassLoader(); 
System.out.println( loader4 );  # null

#方式5
String className = "com.mz.UserInfo";
class clazz5 = Class.forName(className);
#java核心类库的classLoader是不能获取到的。
ClassLoader loader5 = clazz5.getClassLoader(); 
System.out.println( loader5 );  #存在,是SystemClassLoader

3、通过classLoader来加载类路径下的文件

#类路径下加载文件
ClassLoader  loader = this.getClass().getClassLoader();
InputStream is = loader.getResourceAsStream("com/mz/jdbc.properties");
Properties props = new Properties();
props.load(is);

三、java反射使用

利用反射获取类结构信息

1、通过Class类型实例创建对象

  • 要求:
    • 类必须有一个无参的构造器。
    • 类的构造器的访问权限需要足够(public或者同包下protected)。
    Class  clazz = Class.forName("com.mz.UserInfo");
    Object obj = claz.newInstance();
    

2、获取运行时类对象的成员属性 Field

  • getFields() : 获取到运行时类中定义的,或者继承来的public修饰符的成员属性。
    Field[] fields = clazz.getFields();
    for( Field item : fields ){
    	System.out.println(item);
    }	
    
  • getDeclaredFields() : 获取运行时类自身声明的所有的属性。
    Field[] fields = clazz.getDeclaredFields();
    for( Field item : fields ){
       System.out.println(item);
    }	
    

3、获取属性的权限修饰符变量类型,变量名

public void test(){
	Class clazz = Perosn.class;
	Field[] fields = clazz.getDeclaredFields();
	for( Field item : fields  ){
  		 //1.获取属性名
         String propertyName = item.getName();
         System.out.println(propertyName);

         //2.获取属性类型
         Class type = item.getType();
         String typeName = type.getTypeName();
         System.out.println("typeName: "+typeName);
         System.out.println(type.getName());

         //3.获取权限修饰符
         int i = item.getModifiers();
         String modifierName = Modifier.toString(i);
         System.out.println("modifierName:"+modifierName);
	}
}

4、获取运行时类对象的方法 Method,以及注解权限修饰符,返回值类型,方法名,形参列表,异常

Class clazz = Class.forName("com.company.UserInfo");
#获取public修饰的自身定义,以及继承来的方法。
Method[] methods = clazz.getMethods();
for (  Method item : methods  ){
    System.out.println(item.getName());
}

#获取自身类定义的所有方法。
methods = clazz.getDeclaredMethods();
for ( Method item : methods ){

    //1.获取方法名
    System.out.println(item.getName());

    //获取方法上的注解
    Annotation[] annotations =  item.getAnnotations();
    for ( Annotation annotation : annotations ){
        System.out.println(annotation);
    }

    //获取方法的权限修饰符
    String modifierName = Modifier.toString(item.getModifiers());
    System.out.println(modifierName);

    //获取返回值类型
    Class returnType = item.getReturnType();
    String returnTypeName = returnType.getTypeName();
    System.out.println(returnTypeName);

    //获取形参列表的类型
    Class[]  params = item.getParameterTypes();
    for ( Class p : params ){
        String paramName = p.getName();
        System.out.println("paramName: "+paramName);
    }

    //获取方法抛出异常的类型
    Class[] exps = item.getExceptionTypes();
    for ( Class exp : exps ){
        System.out.println(exp.getName());
    }

    System.out.println("============>");
}

5、通过 Class对象 获取构造器

Class clazz = Class.forName("com.company.UserInfo");
#与Method类似
Constructor[] constructors = clazz.getConstructors();
for ( Constructor item : constructors ){
    System.out.println(item.getName());
}

6、通过 Class对象 获取类的父类

Class clazz = Class.forName("com.company.UserInfo");
#获取本类继承的父类的Class对象。
Class superClass = clazz.getSuperclass();
System.out.println(superClass.getName());

7、通过 Class对象 获取父类的泛型

Class clazz = Class.forName("com.company.UserInfo");
Type type = clazz.getGenericSuperclass();
ParameterizedType parameterizedType = (ParameterizedType) type;
//获取泛型编译之后的实际类型
Type[] ars = parameterizedType.getActualTypeArguments();
System.out.println( ((Class)ars[0]).getName() );

8、通过 Class对象 获取类实现的接口

Class clazz = Class.forName("com.company.UserInfo");
Class[] interfaces = clazz.getInterfaces();
for ( Class item : interfaces ){
    System.out.println( item);
}

9、通过 Class对象 获取类所在的包

Class clazz = Class.forName("com.company.UserInfo");
Package aPackage = clazz.getPackage();
System.out.println( aPackage.getName() );

10、通过 Class对象 获取类上的注解

Class clazz = Class.forName("com.company.UserInfo");
Annotation[] annotations = clazz.getAnnotations();

利用反射,获取和设置属性值,调用方法

利用反射,获取和设置属性值

public static void main(String[] args) throws Exception {
     
     Class clazz = Class.forName("com.company.UserInfo");
     UserInfo userInfo = (UserInfo) clazz.newInstance();
     userInfo.setUsername("meng");
     userInfo.setAge(24);
     userInfo.setAdult(true);
     userInfo.setGender(1);
     userInfo.setWeight(150);

     Field[] fields = clazz.getDeclaredFields();
     for ( Field item : fields ){

         //1.获取属性名
         String propertyName = item.getName();
         System.out.println(propertyName);

         //1.1获取属性的类型
         String propertyType = item.getType().getSimpleName();
         System.out.println(propertyType);

         //2.获取值
         item.setAccessible(true);
         System.out.println( item.get(userInfo) );
         System.out.println("=========>");

         //3.设置值
         if ( "boolean".equals(propertyType.toLowerCase())  ){
             item.set(userInfo, false);
         }else if( "float".equals(propertyType.toLowerCase()) ){
             item.set(userInfo, 0F);
         }else if( "int".equals(propertyType.toLowerCase()) ){
             item.set(userInfo,0);
         }else  {
             item.set(userInfo, null);
         }
     }
 }

利用放射,调用实例中的静态方法,成员方法

public static void main(String[] args) throws Exception {

     Class clazz = Class.forName("com.company.UserInfo");
     UserInfo userInfo = (UserInfo) clazz.newInstance();
     userInfo.setUsername("meng");
     userInfo.setAge(24);
     userInfo.setAdult(true);
     userInfo.setGender(1);
     userInfo.setWeight(150);


     //获取 并且 调用无参的实例方法,并且获取返回值。
     Method method = clazz.getDeclaredMethod("getUsername");
     String name = (String) method.invoke(userInfo);
     System.out.println(name);

     //获取 并且 调用有参的实例方法。
     Method method1 = clazz.getDeclaredMethod("setUsername", String.class);
     method1.invoke(userInfo, "mmm");
     System.out.println(userInfo.getUsername());

     //获取 并且 调用静态方法。
     Method method2 = clazz.getDeclaredMethod("info");
     method2.invoke( UserInfo.class );
 }

四、java反射实例

实例1 : 动态代理

实例2 :对象属性复制

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值