反射机制总结篇

反射

​   反射的概念是由 Smith 在 1982 年首次提出的,主要是指程序可以访问、检测和修改它本身状 态或行为的一种能力, 并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和 相关的语义。Java 中,反射是一种强大的工具。它使您能够创建灵活的代码,这些代码可以在 运行时装配,无需在组件之间进行源代码链接。反射允许我们在写与执行时,使我们的程序 代码能够接入装载到 JVM 中的类的内部信息,而不是源代码中选定的类协作的代码。这使反 射成为构建灵活的应用的主要工具。

​ 但需注意的是:如果使用不当,反射的成本很高。

一:JAVA中的类反射

​ Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查, 或者说“自审”或“自省”,并能直接操作程序的内部属性。

 

二:reflection的工作机制

​   程序运行时,java 系统会一直对所有对象进行所谓的运行时类型识别,这项信息记录了每个对 象所属的类。通过专门的类可以访问这些信息。用来保存这些信息的类是class 类,class 类为 编写可动态操纵的 java 代码程序提供了强大功能

  一个类在加载到内存中,就会存在一个表示当前类的Class类的对象(唯一的,不会变)

  Class对象中存在当前这个类的所有内容(属性,构造器,功能…)创建对象时,其实是拿到Class对象的镜像

  如果能够获取到表示一个类的Class对象,就可以进行各种操作…

  Class对象是反射的源头如果能够获取Class对象,就可以使用Class类的中的各种功能来操作

构造 Class 对象有 3 种方式:

 

1.Class.forName()

try { 

     // 构造 Class 对象的第一种方法 

     Class clazz = Class.forName("java.lang.String"); 

     Object obj = clazz.newInstance(); 

     System.out.println(obj); 

 } catch ( ClassNotFoundException e ) { 

         e.printStackTrace(); 

 } catch (IllegalAccessException e) { 

         e.printStackTrace(); 

 } catch ( InstantiationException e) { 

         e.printStackTrace(); 

 } 

 

2.类.Class

try { 

 // 构造 Class 对象的第二种方法 

     Class stringClass = String.class; 

     System.out.println(stringClass); 

 } catch ( ClassNotFoundException e ) { 

         e.printStackTrace(); 

 } catch (IllegalAccessException e) { 

        e.printStackTrace(); 

 } catch ( InstantiationException e) { 

         e.printStackTrace(); 

 } 

 

3.Object.getClass()

try { 

     // 构造 Class 对象的第三种方法

    String s = "s"; 

     stringClass = s.getClass(); 

     System.out.println(stringClass); 

 } catch ( ClassNotFoundException e ) { 
    
     e.printStackTrace(); 

 } catch (IllegalAccessException e) { 

     e.printStackTrace(); 

 } catch ( InstantiationException e) { 

     e.printStackTrace();
}

 

类对象的比较:

相同的类

Class clazz = Class.forName("java.lang.String"); 

Class stringClass = String.class; 

System.out.println("字符串类对象的比较=" +(clazz == stringClass)); //true

不同的类:

Class stringClass = String.class; 

Class intClass = int.class; 

System.out.println("字 符 串类 对 象和 Int 类 对 象的 比较 =" +(stringClass ==  intClass)); //false

 

 

三.Java反射机制可以实现的功能

在运行时判断任意一个对象所属的类;

  ①在运行时判断任意一个对象所属的类;
  ②在运行时构造任意一个类的对象;
  ③在运行时判断任意一个类所具有的成员变量和方法;
  ④在运行时调用任意一个对象的方法;
  ⑤生成动态代理

Class类等的使用:
  基本的常用的方法
  通过获取构造器->反射创建对象
  获取方法->调用方法
  获取属性–>操作属性

public class ReflectDemo03 {
    public static void main(String[] args) {
        //getModifiers() 返回Java语言修饰符的类或接口,编码在一个整数。 
        Class<String> cls = String.class;
        System.out.println(cls.getModifiers());
                                            System.out.println(Modifier.toString(cls.getModifiers()));
            //String getName()  
        System.out.println(cls.getName());                      //java.lang.String
System.out.println(cls.getSimpleName());  //String
//getPackage() 这个类的包。 
​    System.out.println(cls.getPackage());
​    
​    //String getTypeName()  
​    System.out.println(cls.getTypeName());
    }

}    
public class RelectDemo04 {
    public static void main(String[] args) throws Exception {
        testConstructor(User.class);
    }
/*
- 反射获取构造器-->创建对象
- 
- Constructor<T> getConstructor(Class<?>... parameterTypes) 
  获取一个指定的公共额构造器对象

         Constructor<?>[] getConstructors()  获取所有的公共的构造器对象
         Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 
             所有权限的方法中的指定一个
         Constructor<?>[] getDeclaredConstructors()  所有的构造器

​    创建对象
​        1) Class类的newInstance() -->不推荐使用,默认调用空构造,没有就无法使用
​        2) Constructor类提供的newInstance(Object... initargs)方法创建对象,调用当前的构造器初始化信息
 */
public static void testConstructor(Class<User> cls) throws Exception {
​    //获取某个指定的公共的构造器
​    Constructor<User> con = cls.getConstructor(int.class,String.class,String.class,String.class,Integer.TYPE);
​    System.out.println(con);
​    //所有的构造器
​    Constructor[] cons = cls.getDeclaredConstructors();
​    for(Constructor c:cons) {
​        System.out.println(c);
​    }
​    
​    //1.创建对象Class类的newInstance()
​    User obj = cls.newInstance();
​    System.out.println(obj);
​    
​    //2.Constructor类提供的newInstance(Object... initargs)
​    User obj2 = con.newInstance(1001,"lisi","lisi123","女",18);
​    System.out.println(obj2);
​    
​    //私有的,可以放开权限
​    cons[1].setAccessible(true);
​    User obj3 = (User) cons[1].newInstance("liaoliao","1234");
​    cons[1].setAccessible(false); //关闭权限
​    System.out.println(obj3);
​    }
}

 

四.Java 反射中的主要类和方法

  软件包 java.lang.reflect

  提供类和接口,以获取关于类和对象的反射信息。

1.Constructor 构造函数对象

class A { 

 public A() { 

  

 } 

 public A( String s ) { 

  

} 

}

… 

A a = new A(); 

Class aClass = a.getClass(); 

//得到类对象的所有公共的构造函数对象 

Constructor[] constructors =     aClass.getConstructors(); 

// 得到类对象特定的公共构造函数对象 

Constructor c = aClass.getConstructor(String.class); 

// 获取全部声明的构造方法 

Constructor[] c1 = aClass.getDeclaredConstructors(); 

     for ( Constructor c1 : constructors ) { 

 System.out.println( "构造方法的名称=" + c1.getName() ); 

     System.out.println( " 构造方法的修饰符 =" +  

    Modifier.toString(c1.getModifiers()) ); 

     Class[] clazz1 = c1.getParameterTypes(); 

     for ( Class cs : clazz1 ) { 

         System.out.println("参数类型:"+cs.getName()); 

 } 

 }

 

2.Method获取所有方法

Method[] ms = aClass.**getDeclaredMethods**(); 

 for ( Method ms1 : ms ) { 

         System.out.println(); 

 System.out.println( "方法的名称=" + ms1.getName() ); 

         System.out.println( "方法的修饰符=" + ms1.getModifiers() + ":"  

\+ Modifier.toString(ms1.getModifiers()) ); 

         System.out.println( " 方 法 的 修 饰 符 是 否 为 public=" +  

    Modifier.isPublic(ms1.getModifiers()) ); 

     Class[] clazz1 = ms1.getParameterTypes(); 

     for ( Class cs : clazz1 ) { 

 System.out.println("参数类型:"+cs.getName()); 

 } 

         System.out.println( "方法是否带有可变数量的参数=" +  ms1.isVarArgs() ); 

         System.out.println( " 方 法 的 返 回 类 型 : 

"+ms1.getReturnType().getName()); 

 } 

 

3.Field获取所有属性

Field[] f = aClass.getDeclaredFields(); 

         B b = new B(); 

 for ( Field f1 : f ) { 

         System.out.println(); 

         System.out.println( "变量的名称=" + f1.getName() ); 

         System.out.println( " 变量的修饰符 =" +  

Modifier.toString(f1.getModifiers()) ); 

         System.out.println( "变量的类型=" + f1.getType().getName() ); 

         System.out.println( "变量的值=" + f1.get(b) ); 

 }

 

4、Class

Class[] classes = aClass.getInterfaces(); 

     for ( Class c3 : classes ) { 

         System.out.println("接口名称:" + c3.getName()); 

 } 

     // 获取类对象的父类 

     Class c4 = aClass.getSuperclass(); 

         System.out.println("父类名称:" + c4); 

     // 获取类对象的包对象 

 String pName = String.class.getPackage().getName(); 

         System.out.println("String 所在的包名称:" + pName); 

         System.out.println("aClass 是否为接口:" + aClass.isInterface()); 

         System.out.println("C 是否为接口:" + C.class.isInterface()); 

         System.out.println("类名:" + String.class.getName()); 

         System.out.println("类名的简称:" + String.class.getSimpleName());

 

 

五.实例化对象

  创建对象的方式,有new 、克隆、反序列化,再加一种,根据Class对象,使用newInstance() 或者构造器实例化对 象。

//获取源头 

Class<>clz=Class.forName("com.shsxt.ref.simple.User"); 

//第一种:通过newInstance()创建对象 

    User user=(User)clz.newInstance(); 

    user.setUname("sxt"); 

    user.setUpwd("good"); 

//第二种:通过getDeclaredConstructors()创建对象,取得全部构造函数(注意顺序) 

Constructor<?>[] cons=clz.getDeclaredConstructors(); 

    for(Constructor<?>c:cons){ 

        System.out.println(c); 

    }

//注意观察上面的输出结果,再实例化,否则参数容易出错 

User u1=(User)cons[0].newInstance("shsxt","good"); 

User u2=(User)cons[1].newInstance("sxt"); 

User u3=(User)cons[2].newInstance(); 

System.out.println(u1.getUname()+u1.getUpwd()); 

注意:newInstance()调用空构造,如果空构造不存在,会出现异常。由此可知,使用其他构造器创建对象比较

麻烦,使用空构造非常简单。确保空构造存在

 

六.父类与接口

Class<>clz=Class.forName("com.shsxt.ref.simple.User"); 

//获取所有接口 

Class<?>[] inters=clz.getInterfaces(); 

    for(Class<?> in:inters){ 

    System.out.println(in.getName()); 

    }

    //获取父类 

    Class<?> cls=clz.getSuperclass(); 
    
System.out.println("继承的父类为:"+cls.getName());

 

posted @ 2020-09-05 21:44  焕不涣  阅读(230)  评论(0编辑  收藏  举报