精华内容
下载资源
问答
  • 反射全解

    万次阅读 多人点赞 2019-10-31 17:06:00
    反射的概念 反射的引入: Object obj = new Student(); 若程序运行时接收到外部传入的一个对象,该对象的编译类型是Object,但程序又需要调用该对象运行类型的方法: 1.若编译和运行类型都知道,使用 instanceof...

    反射的概念

    反射的引入:

    Object obj = new Student();

    若程序运行时接收到外部传入的一个对象,该对象的编译类型是Object,但程序又需要调用该对象运行类型的方法:

    1.若编译和运行类型都知道,使用 instanceof判断后,强转。

    2.编译时根本无法预知该对象属于什么类,程序只能依靠运行时信息来发现对象的真实信息,这时就必须使用反射了。

    3.要是想得到对象真正的类型,就得使用反射。

    什么是反射机制?  

            简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息。

    反射机制的优点与缺点:  

            为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念  

           静态编译:在编译时确定类型,绑定对象,即通过。  

           动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。  

           一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发。

    它的缺点是对性能有影响。

    使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。

     

    Class类和Class类实例

     

    Java程序中的各个Java类属于同一类事物,描述这类事物的Java类就是Class类。

    对比提问:众多的人用一个什么类表示?众多的Java类用一个什么类表示?

    人  Person

    Java类  Class

    对比提问: Person类代表人,它的实例对象就是张三,李四这样一个个具体的人,Class类代表Java类,它的各个实例对象又分别对应什么呢?

    对应各个类在内存中的字节码,例如,Person类的字节码,ArrayList类的字节码,等等;

    一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以它们在内存中的内容是不同的;

    用类来描述对象,类:描述数据的结构

    用元数据来描述Class,MetaData(元数据):描述数据结构的结构;

    反射就是得到元数据的行为;

     

     

    备注:一个类在虚拟机中只有一份字节码;

     

    获得Class对象

     

    如何得到各个字节码对应的实例对象?

    每个类被加载后,系统会为该类生成对应的Class对象,通过Class对象可以访问到JVM中的这个类,

    3种方式:

    1、调用某个类的class属性获取Class对象,如Date.class会返回Date类对应的Class对象(其实就是得到一个类的一份字节码文件);

    2、使用Class类的forName(String className)静态方法,className表示全限定名;如String的全限定名:java.lang.String;

    3、调用某个对象的getClass()方法。该方法属于Object类;

    Class<?> clz = new Date().getClass();

    public class ClassDemo1 {
    
       public static void main(String[] args) throws Exception {
    
          //获得Class对象的方法(三种)
    
          //一:调用属性
    
          Class<String> c = String.class;
    
          System.out.println(c);//打印结果:class java.lang.String          String.class就表示JVM中一份表示String类的字节码
    
          Class<String> c2 = String.class;
    
          System.out.println(c == c2);//true都是String类的字节码        一个类在虚拟机中只有一份字节码;
    
         
    
          //二:使用forName()方法
    
          //Class cla = Class.forName("String");//ERROR,
    
          Class<String> cla =  (Class<String>)Class.forName("java.lang.String");//必须用上全限定名,否则报错
    
          System.out.println(c == cla);//true
    
         
    
          //三:利用对象调用Object的getClass方法;
    
          Class c3 = new String().getClass();
    
          System.out.println(c == c3);//ture
    
       }
    
    }

     

    我的总结:获取Class对象最常用的是利用属性的方法!

    九个预定义Class对象

     

    基本的 Java 类型(boolean、byte、char、short、int、long、float 、double)和关键字void通过class属性也表示为 Class 对象;

    Class类中boolean isPrimitive() :判定指定的 Class 对象是否表示一个基本类型。

    包装类和Void类的静态TYPE字段;

    Integer.TYPE == int.class ;         

    Integer.class == int.class;      

     数组类型的Class实例对象:

    Class<String[]> clz = String[].class;

    数组的Class对象如何比较是否相等? 数组的维数和数组的类型;

    Class类中 boolean isArray() :判定此 Class 对象是否表示一个数组类型。

    public class PreClassDemo2 {
       public static void main(String[] args) {
          Class<?> in = int.class;
          System.out.println(in);//int
          Class<?> in2 = Integer.class;
          //包装类都有一个常量TYPE,用来表示其基本数据类型的字节码
          Class<?> in3 = Integer.TYPE;
          System.out.println(in2);//class java.lang.Integer
    
          System.out.println(in3);//int
    
          System.out.println(in3 == in);//true 包装类都有一个常量TYPE,用来表示其基本数据类型的字节码,所以这里会相等!
    
          System.out.println(in3 == in2);//false
    
          Class<String[]> s = String [].class;
    
          Class<int[]> i = int [].class;
    
          //System.out.println(i ==s);//编译根本就通过不了,一个是int,一个是String
    
       }
    
       //这两个自定义的方法是可以的,一个int,一个Integer//包装类与基本数据类型的字节码是不一样的
       public void show(int i){}
       public void show(Integer i){}
    
    }

    利用Class获取类的属性信息

    import java.lang.reflect.Modifier;
     

    class A {
    
    }
    
    interface B{
    
    }
    
    interface C{
    
    }
    public class BaseDemo3 extends A implements B,C{
       //内部类
       public class C{}
       public interface D{}
       public static void main(String[] args) {
          //类可以,接口也可以
          Class<BaseDemo3> c = BaseDemo3.class;
          System.out.println(c);//class junereflect624.BaseDemo3
          //得到包名
          System.out.println(c.getPackage());//package junereflect62;
          //得到全限定名
          System.out.println(c.getName());//junereflect624.BaseDemo3
          //得到类的简称
          System.out.println(c.getSimpleName());//BaseDemo3
          //得到父类
          /**
           * Class<? super T> getSuperclass() 此处super表示下限
                   返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。
           */
          System.out.println(c.getSuperclass().getSimpleName());//A,先获取父类,再获取父类的简称
          //得到接口
       System.out.println(c.getInterfaces());//[Ljava.lang.Class;@1b60280
          Class[] arr = c.getInterfaces();
          for (Class cla : arr) {
             System.out.println(cla);//interface junereflect624.B   interface junereflect624.C
          }
          //获得public修饰的类
          /**
           * Class<?>[] getClasses()
                    返回一个包含某些 Class 对象的数组,这些对象表示属于此 Class 对象所表示的类的成员的所有公共类和接口。 (如果内部类前面没有加上public的话那么得不到!)
           */
          Class[] cl = c.getClasses();
          System.out.println(cl.length);//在内部类没有加上public修饰的时候长度为0,加上就是2(获取的是公共的)
          for (Class class1 : cl) {
             System.out.println(class1);
          }
          //获得修饰符
          int i = c.getModifiers();
          System.out.println(i);//常量值1表示public
          System.out.println(Modifier.toString(i));//直接打印出public
       }
    }

    Class中得到构造方法Constructor、方法Method、字段Field

    常用方法:

    Constructor类用于描述类中的构造方法:

    Constructor<T> getConstructor(Class<?>... parameterTypes)

    返回该Class对象表示类的指定的public构造方法;

    Constructor<?>[] getConstructors()

    返回该Class对象表示类的所有public构造方法;

    Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)

    返回该Class对象表示类的指定的构造方法,和访问权限无关;

    Constructor<?>[] getDeclaredConstructors()

    返回该Class对象表示类的所有构造方法,和访问权限无关;

     

    Method类用于描述类中的方法:

    Method getMethod(String name, Class<?> ... parameterTypes)

    返回该Class对象表示类和其父类的指定的public方法;

    Method[] getMethods(): 

    返回该Class对象表示类和其父类的所有public方法;

    Method getDeclaredMethod(String name, Class<?>... parameterTypes)

    返回该Class对象表示类的指定的方法。和访问权限无关,但不包括继承的方法;

    Method[] getDeclaredMethods(): 获得类所有的方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法;

     

    Eg:

    import java.lang.reflect.Constructor;

    class Emp{
       private String name;
       private int age;
       private Emp() {
       }
       Emp(String name){
       }
       public Emp(String name,int age){
       }
    }

     

    public class ConstructorDemo4 {
       public static void main(String[] args) throws Exception {
          //得到所有的构造器(先得到类)
          Class<Emp> c = Emp.class;
          /**
           * Constructor<?>[] getConstructors()
                   返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。
           */
          Constructor[] con = c.getConstructors();//前面的修饰符必须是public才可以在这个方法下获取到
          for (Constructor cons : con) {
             System.out.println("c.getConstructors()"+cons);//如果上面的某构造器public去掉,则显示不出
             /**打印
                public junereflect624.Emp(java.lang.String,int)
              */
          }
    
          //得到指定的构造器,也是必须public
          Constructor c1 = c.getConstructor(String.class,int.class);
          System.out.println(c1);//public junereflect624.Emp(java.lang.String,int)
    
    System.out.println("====================================");
    
       //现在想获得不受public影响的,getDeclaredConstructors(),暴力反射
         
          con = c.getDeclaredConstructors();
          for (Constructor cons : con) {
    System.out.println("c.getDeclaredConstructors()=="+cons);//此时不受修饰符的影响
             /**打印
              *  public junereflect624.Emp()
                public junereflect624.Emp(java.lang.String)
                public junereflect624.Emp(java.lang.String,int)
              */
          }
       }
    }
    
    

     

    import java.lang.annotation.Annotation;

    import java.lang.reflect.Field;

    import java.lang.reflect.Method;

    class AB{
    
       protected String name;
    
       protected String id;
    
    }
    @Deprecated
    
    public class MethodDemo5 extends AB{
       void show(){}
       public void say(){}
       private int age;
       public char c;
       private boolean b;
       public static void main(String[] args) throws Exception {
          Class<MethodDemo5> c = MethodDemo5.class;
          //获取所有的(包含父类的方法)public修饰的方法
          Method[] m = c.getMethods();
          for (Method method : m) {
             System.out.println(method);
          }
          //总结:4个方法,获取全部,获取特定;不受修饰符影响的全部,不受修饰符影响的特定;(前两个都还是受限制的)
          //获取指定的方法
          Method me = c.getMethod("main", String[].class);
          System.out.println("main "+me);//main public static void junereflect624.MethodDemo5.main(java.lang.String[]) throws java.lang.Exception
          //访问所有方法,不受访问权限影响
          m = c.getDeclaredMethods();
          for (Method method : m) {
             System.out.println("不受影响的:"+method);
          }
          me = c.getDeclaredMethod("show");
          System.out.println(me);//void junereflect624.MethodDemo.show()
          me = c.getMethod("toString");
          System.out.println(me);//public java.lang.String java.lang.Object.toString()
          /**
           * Method[] getDeclaredMethods()
                    返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法,只可以对当前类有效
           */
          /*me = c.getDeclaredMethod("toString");//ERROR,c.getDeclaredMethod()不能得到继承的方法
          System.out.println(me);//public java.lang.String java.lang.Object.toString()
           */
          //得到字段
          Field[] f = c.getFields();
          for (Field field : f) {//只得到了public的
             System.out.println("字段"+field);
          }
          //特定字段
          Field fi = c.getField("c");//""里面是名称
          System.out.println(fi);//public char junereflect624.MethodDemo.c
          //得到不受限定名限定的全部字段
          f = c.getDeclaredFields();
          for (Field field : f) {//得到不受修饰符限定的字段,但是只对当前类有效
             System.out.println("全部字段:"+field);
             /**
              * 全部字段:private int junereflect624.MethodDemo.age
              * 全部字段:public char junereflect624.MethodDemo.c
              * 全部字段:private boolean junereflect624.MethodDemo.b
              */
          }
          //注释  Annotation
           Annotation[] a = c.getAnnotations();
           System.out.println(a.length);
           for (Annotation annotation : a) {
             System.out.println(annotation);
          }
           //特定注解
           Deprecated d = c.getAnnotation(Deprecated.class);
           System.out.println(d);
       }
    }

    获取当前对象的字段:

    import java.lang.reflect.Field;
    class Stu{
       public String name;
       public String sex;
       public int age;
       public Stu(String name, String sex, int age) {
          super();
          this.name = name;
          this.sex = sex;
          this.age = age;
       }
    }
    
    public class ReflectDemo6 {
       public static void main(String[] args) throws Exception {
          Stu s = new Stu("刘昭", "男", 12);
          Class<Stu> c = Stu.class;
          Field f = c.getField("name");
          System.out.println(f.get(s));从哪个对象身上取!此时显示刘昭!
    // 修改对象的值
    /**
    Field f = c.getField("name");
          f.set(s,"章泽天");
    System.out.println(f.get(s));//从哪个对象身上取!//此时显示章泽天
    */
    
       }
    
    }

    我的总结:对于方法,字段,构造方法之类用类获取记住四个:获取全部,获取特定,暴力获取全部,暴力获取特定!

    利用反射创建对象

    创建对象:

    1、使用Class对象的newInstance()方法创建该Class对象的实例,此时该Class对象必须要有无参数的构造方法。

    2、使用Class对象获取指定的Constructor对象,再调用Constructor的newInstance()方法创建对象类的实例,此时可以选择使用某个构造方法。如果这个构造方法被私有化起来,那么必须先申请访问,将可以访问设置为true;

    Eg:

    最简单的:

    class User{
    //将默认的构造方法私有化的话就不可以再创建对象,两种方法都是这样
       /*private User(){}*/
       public String toString() {
          return "User对象创建成功!";
       }
    }
    public class NewInstanceDemo6 {
       public static void main(String[] args) throws Exception {
          //传统方式创建对象
           System.out.println(new User());
           //使用反射的方式
           Class<User> c = User.class;
           User u = c.newInstance();(直接newInstance的话必须保证默认的构造方法正常存在,也就是没有被私有化!这是前提条件)
           System.out.println(u);
       }
    }

    复杂点的:更强大的第二种:

    使用指定构造方法来创建对象:

    获取该类的Class对象。

    利用Class对象的getConstructor()方法来获取指定的构造方法。

    调用Constructor的newInstance()方法创建对象。

    AccessibleObject对象的setAccessible(boolean flag)方法,当flag为true的时候,就会忽略访问权限(可访问私有的成员)

    其子类有Field, Method, Constructor;

    若要访问对象private的成员?

    在调用之前使用setAccessible(true),

           Xxx x = getDeclaredXxxx();//才能得到私有的类字段.

    总结步骤:

    1. 获取该类的Class对象。
    2. 利用Class对象的getConstructor()方法来获取指定的构造方法。
    3. 申请访问(设置为可访问)
    4. 调用Constructor(构造方法)的newInstance()方法创建对象。

    例子

    import java.lang.reflect.Constructor;

    class Per{
       private String name;
       private int age;
       private Per(){  
       }
       private Per(String name){
       }
       public String toString() {
          return "对象!!!";
       }
    }
    public class NewInstanceDemo7 {
       public static void main(String[] args) throws Exception {
          Class<Per> c = Per.class;
          //System.out.println(c.newInstance());;//证明利用无参的可以
          先获得需要被调用的构造器(private 修饰的构造方法)
          Constructor<Per> con = c.getDeclaredConstructor();//调用默认的,什么都不要写
          System.out.println(con);//private junereflect624.Per()
          /*con = c.getDeclaredConstructor(String.class);获取指定的构造方法
          System.out.println(con);//private junereflect624.Per(java.lang.String)*/    
          //现在只需要执行这个构造器,
          /**
           *  T newInstance(Object... initargs)
                使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
           */
          //私有的成员是受保护的,不能直接访问
          //若要访问私有的成员,得先申请一下
          con.setAccessible(true);//允许访问
          Per p = con.newInstance();//成功,通过私有的受保护的构造方法创建了对象
          System.out.println("无参构造方法"+p);
          con = c.getDeclaredConstructor(String.class);
          System.out.println(con);//private junereflect624.Per(java.lang.String);              
          con.setAccessible(true);//允许访问
          p = con.newInstance("liuzhao");//成功,通过私有的受保护的构造方法创建了对象
          System.out.println("String构造方法"+p);
       }
    }

    备注:对于此时的话,单例模式就不再安全了!反射可破之!!

    使用反射调用方法

    每个Method的对象对应一个具体的底层方法。获得Method对象后,程序可以使用Method里面的invoke方法来执行该底层方法。

    Object invoke(Object obj,Object ... args):obj表示调用底层方法的对象,后面的args表示传递的实际参数。

    如果底层方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 null,想想为什么?

    如果底层方法所需的形参个数为 0,则所提供的 args 数组长度可以为 0 或 null。

    不写,null,或 new Object[]{}

    若底层方法返回的是数组类型,invoke方法返回的不是底层方法的值,而是底层方法的返回类型;

    import java.lang.reflect.Method;

    class Dept{
       public String show(String name){//用反射的方法来调用正常的方法
          return name+",您好!";
       }
       private void privateshow(){//用反射来实现对私有化方法的调用
          System.out.println("privateshow");
       }
       public static void staticshow(){
          System.out.println("staticshow");
       }
    }
    public class InvokeDemo9 {
       public static void main(String[] args) throws Exception {  
    /* 传统方式:
    String name = new Dept().show("刘昭");
          System.out.println(name);*/    
    
    /**
           * Method getMethod(String name, Class<?>... parameterTypes)
                   返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指         定公共成员方法。
              name - 方法名
             parameterTypes - 参数列表
           */
          //想要通过反射来调用Dept中的方法
          Class<Dept> c = Dept.class;
          Method m = c.getMethod("show", String.class);
          Object o = m.invoke(c.newInstance(), "刘昭");
          System.out.println(o);
        
          //私有化的方法
          m = c.getDeclaredMethod("privateshow");//无参方法
          m.setAccessible(true);
          o = m.invoke(c.newInstance());
         
          //静态方法的调用
          m = c.getMethod("staticshow");
          m.invoke(null);//staticshow为静态方法,不需创建对象,所以这里会是null
       }
    }

    打印

    刘昭,您好!

    privateshow

    staticshow

    使用反射操作字段

    Field提供两组方法操作字段:

    xxx getXxx(Object obj):获取obj对象该Field的字段值,此处的xxx表示8个基本数据类型。若该字段的类型是引用数据类型则使用,Object get(Object obj);

    void setXxx(Object obj,xxx val):将obj对象的该Field字段设置成val值,此处的xxx表示8个基本数据类型。若该字段的类型是引用数据类型则使用,void set(Object obj, Object value);

    package junereflect624;

    //获取字符,并且赋值,然后再取出来(对应的去查看api,比如这个是Field,别的比如Constructor,Method)

    步骤:

    1. 获取类
    2. 获取字段
    3. 赋值(set(c.newInstance(),””));{如果为私有的话设置可接受}

    import java.lang.reflect.Field;

    class Cat{
       private String name;
       public int age;
       private String color;
    }
    public class FieldDemo12 {
       public static void main(String[] args) throws Exception {
          Class<Cat> clz = Cat.class;
          Field[] f = clz.getDeclaredFields();
         
          for (Field field : f) {
             System.out.println(field);
          }
        
          Field fi = clz.getDeclaredField("name");
          System.out.println(fi);
        
          System.out.println(fi.getName());//name
         
          //核心开始
          /**
          *  void set(Object obj, Object value)
    将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
           */
          Cat c = clz.newInstance();
          fi.setAccessible(true);
          fi.set(c, "刘昭");//赋值成功
          Object o = fi.get(c);
          System.out.println(o);//取出成功
         
          fi = clz.getDeclaredField("age");
          fi.setAccessible(true);
          fi.set(c, 21);
          int i = fi.getInt(c);//左边的接受类型已经写成了int,右边的返回类型就也必须是int
          System.out.println(i);//获取成功
       }
    }

     

    打印

    private java.lang.String junereflect624.Cat.name

    public int junereflect624.Cat.age

    private java.lang.String junereflect624.Cat.color

    private java.lang.String junereflect624.Cat.name

    name

    刘昭

    21

     

    反射和泛型-反射来获取泛型信息

    通过指定对应的Class对象,程序可以获得该类里面所有的Field,不管该Field使用private 方法public。获得Field对象后都可以使用getType()来获取其类型。

    Class<?> type = f.getType();//获得字段的类型

    但此方法只对普通Field有效,若该Field有泛型修饰,则不能准确得到该Field的泛型参数,如Map<String,Integer>;

    为了获得指定Field的泛型类型,我们采用:

    Type gType = f.getGenericType();得到泛型类型

    然后将Type对象强转为ParameterizedType,其表示增加泛型后的类型

    Type getRawType()//返回被泛型限制的类型;

    Type[]  getActualTypeArguments()//返回泛型参数类型;

     

    利用反射来获取泛型的类型(泛型信息)

    步骤:

    1. 获取当前类
    2. 获取目标字段
    3. 获取包含泛型类型的类型 getGenericType()
    4. 强转至子类ParameterizedType   因为Type没有任何对应的方法
    5. 获得泛型真正的类型 getActualTypeArguments()
    import java.lang.reflect.Field;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.util.HashMap;
    import java.util.Map;
    public class GetGenericTypeDemo14 {
       Map<String,Integer> map = new HashMap<String,Integer>();
      
       public static void main(String[] args) throws Exception {
          Class c = GetGenericTypeDemo14.class;
          Field f = c.getDeclaredField("map");
          System.out.println(f);
          System.out.println(f.getName());//map
         
          // Class<?> getType()  返回一个 Class 对象,它标识了此 Field 对象所表示字段的声明类型。
          Class cl = f.getType();
          System.out.println("获得其类型:"+cl);
    //获得其类型:interface java.util.Map
        
          /**
           *  Type getGenericType() 返回一个 Type 对象,它表示此 Field 对象所表示字段的声明类型。
           *  Type是Class的接口;
           */
          Type t = f.getGenericType();//包含泛型的类型
          System.out.println(t);
    //java.util.Map<java.lang.String, java.lang.Integer>
         
          /**
           * Type这个类里面没有任何的方法,所以需要调用子类的方法,那么大的类型转到小的类型,需要强转!
           */
          ParameterizedType pt = (ParameterizedType)t;//强转到其子类
          /**
           *  Type[] getActualTypeArguments()
                       返回表示此类型实际类型参数的 Type对象的数组。
              Type getOwnerType()
                       返回 Type 对象,表示此类型是其成员之一的类型。
              Type getRawType()
                       返回 Type 对象,表示声明此类型的类或接口。
           */
         
          t = pt.getRawType();//类型的类或接口
          System.out.println(t);
         
          Type[] ts = pt.getActualTypeArguments();
          for (Type type : ts) {
             System.out.println(type);
             /**
              *  class java.lang.String
                 class java.lang.Integer
              */
          }
       }
    }

    打印:

    java.util.Map junereflect624.GetGenericTypeDemo14.map

    map

    获得其类型:interface java.util.Map

    java.util.Map<java.lang.String, java.lang.Integer>

    interface java.util.Map

    class java.lang.String

    class java.lang.Integer

    我的总结:多查找api,参考api中方法使用的限制,比如是否静态、返回值类型等。

    展开全文
  • 行业资料-电子功用-具有反射性的太阳能电池用背面保护
  • 根据2.4 m望远镜主镜面型,结合ZZS3200型镀膜机真空室空间几何配置,分析了介质保护膜膜厚均匀,设计了一款自上向下热蒸发保护膜材料的蒸发舟,开展了铝反射镜的介质保护膜工艺研究。结果表明:蒸发舟蒸发特性接近...
  • 问题:反射是否会破坏类的封装见解  首先,封装,是将具体的实现细节隐藏,而把功能作为整体提供给类的外部使用,也就是说,公有方法能够完成类所具有的功能。当别人使用这个类时,如果通过反射直接调用私有方法...

    问题:反射是否会破坏类的封装性见解

           首先,封装,是将具体的实现细节隐藏,而把功能作为整体提供给类的外部使用,也就是说,公有方法能够完成类所具有的功能。当别人使用这个类时,如果通过反射直接调用私有方法,可能根本实现不了类的功能,甚至可能会出错,因此通过反射调用私有方法可以说是没有任何用处的,开发人员没有必要故意去破坏封装好的类。从这点上看,封装性并没有被破坏。(摘自百度问答)

        个人的见解:反射确实可以得到一切 类中的东西(包括私有的属性、方法等),但是或许不算是破坏封装,私有方法是为了让继承的类无法使用,避免调用那些被设为私有的方法出现一些不必要的错误。这就是封装性。反射虽然可以获取私有方法并使用方法,只能说是其功能强大,可以在保证在调用私有方法不会出现错误,但是并没有反射调用方法后,该方法就不是私有的了。他仍然是私有的,仍然在子类中不可见。

        对于是否破坏了封装性,也欢迎大家评论区说明自己的观点。

    =================================================================================

    //以下内容转发自blog:http://blog.csdn.net/sinat_38259539/article/details/71799078

    反射是框架设计的灵魂

    (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))

    一、反射的概述

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

    要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

    以上的总结就是什么是反射

    反射就是把java类中的各种成分映射成一个个的Java对象

    例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。

         (其实:一个类中这些成员方法、构造方法、在加入类中都有一个类来描述)

    如图是类的正常加载过程:反射的原理在与class对象。

    熟悉一下加载的时候:Class对象的由来是将class文件读入内存,并为之创建一个Class对象。

     

    其中这个Class对象很特殊。我们先了解一下这个Class类

    二、查看Class类在java中的api详解(1.7的API)

    如何阅读java中的api详见java基础之——String字符串处理

     

    Class 类的实例表示正在运行的 Java 应用程序中的类和接口。也就是jvm中有N多的实例每个类都有该Class对象。(包括基本数据类型)

    Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。

    没有公共的构造方法,方法共有64个太多了。下面用到哪个就详解哪个吧

     

    三、反射的使用(这里使用Student类做演示)

    先写一个Student类。

    1、获取Class对象的三种方式

    1.1 Object ——> getClass();
    1.2 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
    1.3 通过Class类的静态方法:forName(String  className)(常用)

    其中1.1是因为Object类中的getClass方法、因为所有类都继承Object类。从而调用Object类来获取

     

    /** 
     * 获取Class对象的三种方式 
     * 1 Object ——> getClass(); 
     * 2 任何数据类型(包括基本数据类型)都有一个“静态”的class属性 
     * 3 通过Class类的静态方法:forName(String  className)(常用) 
     * 
     */  
    public class Fanshe {  
        public static void main(String[] args) {  
            //第一种方式获取Class对象    
            Student stu1 = new Student();//这一new 产生一个Student对象,一个Class对象。  
            Class stuClass = stu1.getClass();//获取Class对象  
            System.out.println(stuClass.getName());  
              
            //第二种方式获取Class对象  
            Class stuClass2 = Student.class;  
            System.out.println(stuClass == stuClass2);//判断第一种方式获取的Class对象和第二种方式获取的是否是同一个  
              
            //第三种方式获取Class对象  
            try {  
                Class stuClass3 = Class.forName("fanshe.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名  
                System.out.println(stuClass3 == stuClass2);//判断三种方式是否获取的是同一个Class对象  
            } catch (ClassNotFoundException e) {  
                e.printStackTrace();  
            }  
              
        }  
    }

    注意:在运行期间,一个类,只有一个Class对象产生。

    三种方式常用第三种,第一种对象都有了还要反射干什么。第二种需要导入类的包,依赖太强,不导包就抛编译错误。一般都第三种,一个字符串可以传入也可写在配置文件中等多种方法。

     

    2、通过反射获取构造方法并使用:

    student类:

    
    public class Student {  
          
        //---------------构造方法-------------------  
        //(默认的构造方法)  
        Student(String str){  
            System.out.println("(默认)的构造方法 s = " + str);  
        }  
          
        //无参构造方法  
        public Student(){  
            System.out.println("调用了公有、无参构造方法执行了。。。");  
        }  
          
        //有一个参数的构造方法  
        public Student(char name){  
            System.out.println("姓名:" + name);  
        }  
          
        //有多个参数的构造方法  
        public Student(String name ,int age){  
            System.out.println("姓名:"+name+"年龄:"+ age);//这的执行效率有问题,以后解决。  
        }  
          
        //受保护的构造方法  
        protected Student(boolean n){  
            System.out.println("受保护的构造方法 n = " + n);  
        }  
          
        //私有构造方法  
        private Student(int age){  
            System.out.println("私有的构造方法   年龄:"+ age);  
        }  
      
    }  
    

    测试类:

    import java.lang.reflect.Constructor;  
      
      
    /* 
     * 通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问成员; 
     *  
     * 1.获取构造方法: 
     *      1).批量的方法: 
     *          public Constructor[] getConstructors():所有"公有的"构造方法 
                public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有) 
          
     *      2).获取单个的方法,并调用: 
     *          public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法: 
     *          public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有; 
     *       
     *          调用构造方法: 
     *          Constructor-->newInstance(Object... initargs) 
     */  
    public class Constructors {  
      
        public static void main(String[] args) throws Exception {  
            //1.加载Class对象  
            Class clazz = Class.forName("fanshe.Student");  
              
              
            //2.获取所有公有构造方法  
            System.out.println("**********************所有公有构造方法*********************************");  
            Constructor[] conArray = clazz.getConstructors();  
            for(Constructor c : conArray){  
                System.out.println(c);  
            }  
              
              
            System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");  
            conArray = clazz.getDeclaredConstructors();  
            for(Constructor c : conArray){  
                System.out.println(c);  
            }  
              
            System.out.println("*****************获取公有、无参的构造方法*******************************");  
            Constructor con = clazz.getConstructor(null);  
            //1>、因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型  
            //2>、返回的是描述这个无参构造函数的类对象。  
          
            System.out.println("con = " + con);  
            //调用构造方法  
            Object obj = con.newInstance();  
        //  System.out.println("obj = " + obj);  
        //  Student stu = (Student)obj;  
              
            System.out.println("******************获取私有构造方法,并调用*******************************");  
            con = clazz.getDeclaredConstructor(char.class);  
            System.out.println(con);  
            //调用构造方法  
            con.setAccessible(true);//暴力访问(忽略掉访问修饰符)  
            obj = con.newInstance('男');  
        }  
          
    }  

    后台输出:

    **********************所有公有构造方法*********************************  
    public fanshe.Student(java.lang.String,int)  
    public fanshe.Student(char)  
    public fanshe.Student()  
    ************所有的构造方法(包括:私有、受保护、默认、公有)***************  
    private fanshe.Student(int)  
    protected fanshe.Student(boolean)  
    public fanshe.Student(java.lang.String,int)  
    public fanshe.Student(char)  
    public fanshe.Student()  
    fanshe.Student(java.lang.String)  
    *****************获取公有、无参的构造方法*******************************  
    con = public fanshe.Student()  
    调用了公有、无参构造方法执行了。。。  
    ******************获取私有构造方法,并调用*******************************  
    public fanshe.Student(char)  
    姓名:男  
    

    调用方法:

    1.获取构造方法:

      1).批量的方法:

    • public Constructor[] getConstructors():所有"公有的"构造方法
    • public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)

    2).获取单个的方法,并调用:

    • public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
    • public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;

      调用构造方法:

    • Constructor-->newInstance(Object... initargs)

    2、newInstance是 Constructor类的方法(管理构造函数的类)

    api的解释为:

    • newInstance(Object... initargs)
    •            使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
    • 它的返回值是T类型,所以newInstance是创建了一个构造方法的声明类的新实例对象。并为之调用

    3、获取成员变量并调用

    student类:

    public class Student {  
        public Student(){  
              
        }  
        //**********字段*************//  
        public String name;  
        protected int age;  
        char sex;  
        private String phoneNum;  
          
        @Override  
        public String toString() {  
            return "Student [name=" + name + ", age=" + age + ", sex=" + sex  
                    + ", phoneNum=" + phoneNum + "]";  
        }  
          
          
    }

    测试类:

    import java.lang.reflect.Field;  
    /* 
     * 获取成员变量并调用: 
     *  
     * 1.批量的 
     *      1).Field[] getFields():获取所有的"公有字段" 
     *      2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有; 
     * 2.获取单个的: 
     *      1).public Field getField(String fieldName):获取某个"公有的"字段; 
     *      2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的) 
     *  
     *   设置字段的值: 
     *      Field --> public void set(Object obj,Object value): 
     *                  参数说明: 
     *                  1.obj:要设置的字段所在的对象; 
     *                  2.value:要为字段设置的值; 
     *  
     */  
    public class Fields {  
      
            public static void main(String[] args) throws Exception {  
                //1.获取Class对象  
                Class stuClass = Class.forName("fanshe.field.Student");  
                //2.获取字段  
                System.out.println("************获取所有公有的字段********************");  
                Field[] fieldArray = stuClass.getFields();  
                for(Field f : fieldArray){  
                    System.out.println(f);  
                }  
                System.out.println("************获取所有的字段(包括私有、受保护、默认的)********************");  
                fieldArray = stuClass.getDeclaredFields();  
                for(Field f : fieldArray){  
                    System.out.println(f);  
                }  
                System.out.println("*************获取公有字段**并调用***********************************");  
                Field f = stuClass.getField("name");  
                System.out.println(f);  
                //获取一个对象  
                Object obj = stuClass.getConstructor().newInstance();//产生Student对象--》Student stu = new Student();  
                //为字段设置值  
                f.set(obj, "刘德华");//为Student对象中的name属性赋值--》stu.name = "刘德华"  
                //验证  
                Student stu = (Student)obj;  
                System.out.println("验证姓名:" + stu.name);  
                  
                  
                System.out.println("**************获取私有字段****并调用********************************");  
                f = stuClass.getDeclaredField("phoneNum");  
                System.out.println(f);  
                f.setAccessible(true);//暴力反射,解除私有限定  
                f.set(obj, "18888889999");  
                System.out.println("验证电话:" + stu);  
                  
            }  
        }


    后台输出:

    ************获取所有公有的字段********************  
    public java.lang.String fanshe.field.Student.name  
    ************获取所有的字段(包括私有、受保护、默认的)********************  
    public java.lang.String fanshe.field.Student.name  
    protected int fanshe.field.Student.age  
    char fanshe.field.Student.sex  
    private java.lang.String fanshe.field.Student.phoneNum  
    *************获取公有字段**并调用***********************************  
    public java.lang.String fanshe.field.Student.name  
    验证姓名:刘德华  
    **************获取私有字段****并调用********************************  
    private java.lang.String fanshe.field.Student.phoneNum  
    验证电话:Student [name=刘德华, age=0, sex=  


    由此可见

    调用字段时:需要传递两个参数:

    Object obj = stuClass.getConstructor().newInstance();//产生Student对象--》Student stu = new Student();
    //为字段设置值
    f.set(obj, "刘德华");//为Student对象中的name属性赋值--》stu.name = "刘德华"

    第一个参数:要传入设置的对象,第二个参数:要传入实参

    4、获取成员方法并调用

    student类:

    public class Student {  
        //**************成员方法***************//  
        public void show1(String s){  
            System.out.println("调用了:公有的,String参数的show1(): s = " + s);  
        }  
        protected void show2(){  
            System.out.println("调用了:受保护的,无参的show2()");  
        }  
        void show3(){  
            System.out.println("调用了:默认的,无参的show3()");  
        }  
        private String show4(int age){  
            System.out.println("调用了,私有的,并且有返回值的,int参数的show4(): age = " + age);  
            return "abcd";  
        }  
    }  

    测试类:

    import java.lang.reflect.Method;  
      
    /* 
     * 获取成员方法并调用: 
     *  
     * 1.批量的: 
     *      public Method[] getMethods():获取所有"公有方法";(包含了父类的方法也包含Object类) 
     *      public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的) 
     * 2.获取单个的: 
     *      public Method getMethod(String name,Class<?>... parameterTypes): 
     *                  参数: 
     *                      name : 方法名; 
     *                      Class ... : 形参的Class类型对象 
     *      public Method getDeclaredMethod(String name,Class<?>... parameterTypes) 
     *  
     *   调用方法: 
     *      Method --> public Object invoke(Object obj,Object... args): 
     *                  参数说明: 
     *                  obj : 要调用方法的对象; 
     *                  args:调用方式时所传递的实参; 
     
    ): 
     */  
    public class MethodClass {  
      
        public static void main(String[] args) throws Exception {  
            //1.获取Class对象  
            Class stuClass = Class.forName("fanshe.method.Student");  
            //2.获取所有公有方法  
            System.out.println("***************获取所有的”公有“方法*******************");  
            stuClass.getMethods();  
            Method[] methodArray = stuClass.getMethods();  
            for(Method m : methodArray){  
                System.out.println(m);  
            }  
            System.out.println("***************获取所有的方法,包括私有的*******************");  
            methodArray = stuClass.getDeclaredMethods();  
            for(Method m : methodArray){  
                System.out.println(m);  
            }  
            System.out.println("***************获取公有的show1()方法*******************");  
            Method m = stuClass.getMethod("show1", String.class);  
            System.out.println(m);  
            //实例化一个Student对象  
            Object obj = stuClass.getConstructor().newInstance();  
            m.invoke(obj, "刘德华");  
              
            System.out.println("***************获取私有的show4()方法******************");  
            m = stuClass.getDeclaredMethod("show4", int.class);  
            System.out.println(m);  
            m.setAccessible(true);//解除私有限定  
            Object result = m.invoke(obj, 20);//需要两个参数,一个是要调用的对象(获取有反射),一个是实参  
            System.out.println("返回值:" + result);  
              
              
        }  
    }  

    控制台输出:

    ***************获取所有的”公有“方法*******************  
    public void fanshe.method.Student.show1(java.lang.String)  
    public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException  
    public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException  
    public final void java.lang.Object.wait() throws java.lang.InterruptedException  
    public boolean java.lang.Object.equals(java.lang.Object)  
    public java.lang.String java.lang.Object.toString()  
    public native int java.lang.Object.hashCode()  
    public final native java.lang.Class java.lang.Object.getClass()  
    public final native void java.lang.Object.notify()  
    public final native void java.lang.Object.notifyAll()  
    ***************获取所有的方法,包括私有的*******************  
    public void fanshe.method.Student.show1(java.lang.String)  
    private java.lang.String fanshe.method.Student.show4(int)  
    protected void fanshe.method.Student.show2()  
    void fanshe.method.Student.show3()  
    ***************获取公有的show1()方法*******************  
    public void fanshe.method.Student.show1(java.lang.String)  
    调用了:公有的,String参数的show1(): s = 刘德华  
    ***************获取私有的show4()方法******************  
    private java.lang.String fanshe.method.Student.show4(int)  
    调用了,私有的,并且有返回值的,int参数的show4(): age = 20  
    返回值:abcd  

    由此可见:

    m = stuClass.getDeclaredMethod("show4", int.class);//调用制定方法(所有包括私有的),需要传入两个参数,第一个是调用的方法名称,第二个是方法的形参类型,切记是类型。
    System.out.println(m);
    m.setAccessible(true);//解除私有限定
    Object result = m.invoke(obj, 20);//需要两个参数,一个是要调用的对象(获取有反射),一个是实参
    System.out.println("返回值:" + result);//

    控制台输出:

    ***************获取所有的”公有“方法*******************  
    public void fanshe.method.Student.show1(java.lang.String)  
    public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException  
    public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException  
    public final void java.lang.Object.wait() throws java.lang.InterruptedException  
    public boolean java.lang.Object.equals(java.lang.Object)  
    public java.lang.String java.lang.Object.toString()  
    public native int java.lang.Object.hashCode()  
    public final native java.lang.Class java.lang.Object.getClass()  
    public final native void java.lang.Object.notify()  
    public final native void java.lang.Object.notifyAll()  
    ***************获取所有的方法,包括私有的*******************  
    public void fanshe.method.Student.show1(java.lang.String)  
    private java.lang.String fanshe.method.Student.show4(int)  
    protected void fanshe.method.Student.show2()  
    void fanshe.method.Student.show3()  
    ***************获取公有的show1()方法*******************  
    public void fanshe.method.Student.show1(java.lang.String)  
    调用了:公有的,String参数的show1(): s = 刘德华  
    ***************获取私有的show4()方法******************  
    private java.lang.String fanshe.method.Student.show4(int)  
    调用了,私有的,并且有返回值的,int参数的show4(): age = 20  
    返回值:abcd  
    


    其实这里的成员方法:在模型中有属性一词,就是那些setter()方法和getter()方法。还有字段组成,这些内容在内省中详解

    5、反射main方法

    student类:

    public class Student {  
      
        public static void main(String[] args) {  
            System.out.println("main方法执行了。。。");  
        }  
    }  

    测试类:

    import java.lang.reflect.Method;  
      
    /** 
     * 获取Student类的main方法、不要与当前的main方法搞混了 
     */  
    public class Main {  
          
        public static void main(String[] args) {  
            try {  
                //1、获取Student对象的字节码  
                Class clazz = Class.forName("fanshe.main.Student");  
                  
                //2、获取main方法  
                 Method methodMain = clazz.getMethod("main", String[].class);//第一个参数:方法名称,第二个参数:方法形参的类型,  
                //3、调用main方法  
                // methodMain.invoke(null, new String[]{"a","b","c"});  
                 //第一个参数,对象类型,因为方法是static静态的,所以为null可以,第二个参数是String数组,这里要注意在jdk1.4时是数组,jdk1.5之后是可变参数  
                 //这里拆的时候将  new String[]{"a","b","c"} 拆成3个对象。。。所以需要将它强转。  
                 methodMain.invoke(null, (Object)new String[]{"a","b","c"});//方式一  
                // methodMain.invoke(null, new Object[]{new String[]{"a","b","c"}});//方式二  
                  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
              
              
        }  
    }

    控制台输出:

    main方法执行了。。。

    6、反射方法的其它使用之---通过反射运行配置文件内容

    student类:

    public class Student {  
        public void show(){  
            System.out.println("is show()");  
        }  
    }  
    

    配置文件以txt文件为例子(pro.txt):

    className = cn.fanshe.Student  
    methodName = show  

    测试类:

    import java.io.FileNotFoundException;  
    import java.io.FileReader;  
    import java.io.IOException;  
    import java.lang.reflect.Method;  
    import java.util.Properties;  
      
    /* 
     * 我们利用反射和配置文件,可以使:应用程序更新时,对源码无需进行任何修改 
     * 我们只需要将新类发送给客户端,并修改配置文件即可 
     */  
    public class Demo {  
        public static void main(String[] args) throws Exception {  
            //通过反射获取Class对象  
            Class stuClass = Class.forName(getValue("className"));//"cn.fanshe.Student"  
            //2获取show()方法  
            Method m = stuClass.getMethod(getValue("methodName"));//show  
            //3.调用show()方法  
            m.invoke(stuClass.getConstructor().newInstance());  
              
        }  
          
        //此方法接收一个key,在配置文件中获取相应的value  
        public static String getValue(String key) throws IOException{  
            Properties pro = new Properties();//获取配置文件的对象  
            FileReader in = new FileReader("pro.txt");//获取输入流  
            pro.load(in);//将流加载到配置文件对象中  
            in.close();  
            return pro.getProperty(key);//返回根据key获取的value值  
        }  
    }  
    

    控制台输出:

    is show()

    需求:
    当我们升级这个系统时,不要Student类,而需要新写一个Student2的类时,这时只需要更改pro.txt的文件内容就可以了。代码就一点不用改动

    要替换的student2类:

    public class Student2 {  
        public void show2(){  
            System.out.println("is show2()");  
        }  
    }  

    配置文件更改为:

    className = cn.fanshe.Student2  
    methodName = show2  

    控制台输出:

    is show2();

    7、反射方法的其它使用之---通过反射越过泛型检查

    泛型用在编译期,编译过后泛型擦除(消失掉)。所以是可以通过反射越过泛型检查的

    测试类:

    import java.lang.reflect.Method;  
    import java.util.ArrayList;  
      
    /* 
     * 通过反射越过泛型检查 
     *  
     * 例如:有一个String泛型的集合,怎样能向这个集合中添加一个Integer类型的值? 
     */  
    public class Demo {  
        public static void main(String[] args) throws Exception{  
            ArrayList<String> strList = new ArrayList<>();  
            strList.add("aaa");  
            strList.add("bbb");  
              
        //  strList.add(100);  
            //获取ArrayList的Class对象,反向的调用add()方法,添加数据  
            Class listClass = strList.getClass(); //得到 strList 对象的字节码 对象  
            //获取add()方法  
            Method m = listClass.getMethod("add", Object.class);  
            //调用add()方法  
            m.invoke(strList, 100);  
              
            //遍历集合  
            for(Object obj : strList){  
                System.out.println(obj);  
            }  
        }  
    }  
    

    控制台输出:

    aaa
    bbb
    100

    展开全文
  • Java基础篇:反射机制详解

    万次阅读 多人点赞 2018-09-29 10:19:50
    一、什么是反射反射是Java的特征之一,是一种间接操作目标对象的机制,核心是JVM在运行的时候才动态加载类,并且对于任意一个类,都能够知道这个类的所有属性和方法,调用方法/访问属性,不需要提前在编译期...

    一、什么是反射:

    (1)Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。

    (2)Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。

    二、反射的原理:

    下图是类的正常加载过程、反射原理与class对象:

    Class对象的由来是将.class文件读入内存,并为之创建一个Class对象。

    对于类加载机制与双亲委派模型感兴趣的小伙伴可以阅读这篇文章:https://blog.csdn.net/a745233700/article/details/90232862

    三、反射的优缺点:

    1、优点:在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。

    2、缺点:(1)反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;

    (2)反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。

    四、反射的用途:

    1、反编译:.class-->.java

    2、通过反射机制访问java对象的属性,方法,构造方法等

    3、当我们在使用IDE,比如Ecplise时,当我们输入一个对象或者类,并想调用他的属性和方法是,一按点号,编译器就会自动列出他的属性或者方法,这里就是用到反射。

    4、反射最重要的用途就是开发各种通用框架。比如很多框架(Spring)都是配置化的(比如通过XML文件配置Bean),为了保证框架的通用性,他们可能需要根据配置文件加载不同的类或者对象,调用不同的方法,这个时候就必须使用到反射了,运行时动态加载需要的加载的对象。

    5、例如,在使用Strut2框架的开发过程中,我们一般会在struts.xml里去配置Action,比如

    <action name="login" class="org.ScZyhSoft.test.action.SimpleLoginAction" method="execute">   
        <result>/shop/shop-index.jsp</result>           
        <result name="error">login.jsp</result>       
    </action>

    比如我们请求login.action时,那么StrutsPrepareAndExecuteFilter就会去解析struts.xml文件,从action中查找出name为login的Action,并根据class属性创建SimpleLoginAction实例,并用Invoke方法来调用execute方法,这个过程离不开反射。配置文件与Action建立了一种映射关系,当View层发出请求时,请求会被StrutsPrepareAndExecuteFilter拦截,然后StrutsPrepareAndExecuteFilter会去动态地创建Action实例。

    比如,加载数据库驱动的,用到的也是反射。

    Class.forName("com.mysql.jdbc.Driver"); // 动态加载mysql驱动

    五、反射机制常用的类:

    Java.lang.Class;

    Java.lang.reflect.Constructor;

    Java.lang.reflect.Field;

    Java.lang.reflect.Method;

    Java.lang.reflect.Modifier;

    六、反射的基本使用:

    1、获得Class:主要有三种方法:

    (1)Object-->getClass

    (2)任何数据类型(包括基本的数据类型)都有一个“静态”的class属性

    (3)通过class类的静态方法:forName(String className)(最常用)

    package fanshe;
    
    public class Fanshe {
    	public static void main(String[] args) {
    		//第一种方式获取Class对象  
    		Student stu1 = new Student();//这一new 产生一个Student对象,一个Class对象。
    		Class stuClass = stu1.getClass();//获取Class对象
    		System.out.println(stuClass.getName());
    		
    		//第二种方式获取Class对象
    		Class stuClass2 = Student.class;
    		System.out.println(stuClass == stuClass2);//判断第一种方式获取的Class对象和第二种方式获取的是否是同一个
    		
    		//第三种方式获取Class对象
    		try {
    			Class stuClass3 = Class.forName("fanshe.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
    			System.out.println(stuClass3 == stuClass2);//判断三种方式是否获取的是同一个Class对象
    		} catch (ClassNotFoundException e) {
    			e.printStackTrace();
    		}
    		
    	}
    }
    

    注意,在运行期间,一个类,只有一个Class对象产生,所以打印结果都是true;

    三种方式中,常用第三种,第一种对象都有了还要反射干什么,第二种需要导入类包,依赖太强,不导包就抛编译错误。一般都使用第三种,一个字符串可以传入也可以写在配置文件中等多种方法。

    2、判断是否为某个类的示例:

    一般的,我们使用instanceof 关键字来判断是否为某个类的实例。同时我们也可以借助反射中Class对象的isInstance()方法来判断时候为某个类的实例,他是一个native方法。

    public native boolean isInstance(Object obj);

    3、创建实例:通过反射来生成对象主要有两种方法:

    (1)使用Class对象的newInstance()方法来创建Class对象对应类的实例。

    Class<?> c = String.class;
    Object str = c.newInstance();

    (2)先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建对象,这种方法可以用指定的构造器构造类的实例。

    //获取String的Class对象
    Class<?> str = String.class;
    //通过Class对象获取指定的Constructor构造器对象
    Constructor constructor=c.getConstructor(String.class);
    //根据构造器创建实例:
    Object obj = constructor.newInstance(“hello reflection”);

    4、通过反射获取构造方法并使用:

    (1)批量获取的方法:
    public Constructor[] getConstructors():所有"公有的"构造方法
    public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)

    (2)单个获取的方法,并调用:
    public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
    public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;

    (3) 调用构造方法:

    Constructor-->newInstance(Object... initargs)

    newInstance是 Constructor类的方法(管理构造函数的类)

    api的解释为:newInstance(Object... initargs) ,使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

    它的返回值是T类型,所以newInstance是创建了一个构造方法的声明类的新实例对象,并为之调用。

    例子:

    Student类:共六个构造方法。

    package fanshe;
    public class Student {
    	//---------------构造方法-------------------
    	//(默认的构造方法)
    	Student(String str){
    		System.out.println("(默认)的构造方法 s = " + str);
    	}
    	//无参构造方法
    	public Student(){
    		System.out.println("调用了公有、无参构造方法执行了。。。");
    	}
    	//有一个参数的构造方法
    	public Student(char name){
    		System.out.println("姓名:" + name);
    	}
    	//有多个参数的构造方法
    	public Student(String name ,int age){
    		System.out.println("姓名:"+name+"年龄:"+ age);//这的执行效率有问题,以后解决。
    	}
    	//受保护的构造方法
    	protected Student(boolean n){
    		System.out.println("受保护的构造方法 n = " + n);
    	}
    	//私有构造方法
    	private Student(int age){
    		System.out.println("私有的构造方法   年龄:"+ age);
    	}
    }
    

    测试类:

    package fanshe;
    import java.lang.reflect.Constructor;
     
    /*
     * 通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问成员;
     * 
     * 1.获取构造方法:
     * 		1).批量的方法:
     * 			public Constructor[] getConstructors():所有"公有的"构造方法
                public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
     * 		2).获取单个的方法,并调用:
     * 			public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
     * 			public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有; 		
     * 		3).调用构造方法:
     * 			Constructor-->newInstance(Object... initargs)
     */
    public class Constructors {
     
    	public static void main(String[] args) throws Exception {
    		//1.加载Class对象
    		Class clazz = Class.forName("fanshe.Student");
    		
    		//2.获取所有公有构造方法
    		System.out.println("**********************所有公有构造方法*********************************");
    		Constructor[] conArray = clazz.getConstructors();
    		for(Constructor c : conArray){
    			System.out.println(c);
    		}
    		
    		System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");
    		conArray = clazz.getDeclaredConstructors();
    		for(Constructor c : conArray){
    			System.out.println(c);
    		}
    		
    		System.out.println("*****************获取公有、无参的构造方法*******************************");
    		Constructor con = clazz.getConstructor(null);
    		//1>、因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型
    		//2>、返回的是描述这个无参构造函数的类对象。
    		System.out.println("con = " + con);
    
    		//调用构造方法
    		Object obj = con.newInstance();
    	//	System.out.println("obj = " + obj);
    	//	Student stu = (Student)obj;
    		
    		System.out.println("******************获取私有构造方法,并调用*******************************");
    		con = clazz.getDeclaredConstructor(char.class);
    		System.out.println(con);
    		//调用构造方法
    		con.setAccessible(true);//暴力访问(忽略掉访问修饰符)
    		obj = con.newInstance('男');
    	}
    }
    

    控制台输出:

    **********************所有公有构造方法*********************************
    public fanshe.Student(java.lang.String,int)
    public fanshe.Student(char)
    public fanshe.Student()
    ************所有的构造方法(包括:私有、受保护、默认、公有)***************
    private fanshe.Student(int)
    protected fanshe.Student(boolean)
    public fanshe.Student(java.lang.String,int)
    public fanshe.Student(char)
    public fanshe.Student()
    fanshe.Student(java.lang.String)
    *****************获取公有、无参的构造方法*******************************
    con = public fanshe.Student()
    调用了公有、无参构造方法执行了。。。
    ******************获取私有构造方法,并调用*******************************
    public fanshe.Student(char)
    姓名:男
    

    5、获取成员变量并调用:

    Student类:

    package fanshe.field;
     
    public class Student {
    	public Student(){
    		
    	}
    	//**********字段*************//
    	public String name;
    	protected int age;
    	char sex;
    	private String phoneNum;
    	
    	@Override
    	public String toString() {
    		return "Student [name=" + name + ", age=" + age + ", sex=" + sex
    				+ ", phoneNum=" + phoneNum + "]";
    	}
    }
    

    测试类:

    package fanshe.field;
    import java.lang.reflect.Field;
    /*
     * 获取成员变量并调用:
     * 
     * 1.批量的
     * 		1).Field[] getFields():获取所有的"公有字段"
     * 		2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;
     * 2.获取单个的:
     * 		1).public Field getField(String fieldName):获取某个"公有的"字段;
     * 		2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)
     * 
     * 	 设置字段的值:
     * 		Field --> public void set(Object obj,Object value):
     * 					参数说明:
     * 					1.obj:要设置的字段所在的对象;
     * 					2.value:要为字段设置的值;
     */
    public class Fields {
     
    		public static void main(String[] args) throws Exception {
    			//1.获取Class对象
    			Class stuClass = Class.forName("fanshe.field.Student");
    			//2.获取字段
    			System.out.println("************获取所有公有的字段********************");
    			Field[] fieldArray = stuClass.getFields();
    			for(Field f : fieldArray){
    				System.out.println(f);
    			}
    			System.out.println("************获取所有的字段(包括私有、受保护、默认的)********************");
    			fieldArray = stuClass.getDeclaredFields();
    			for(Field f : fieldArray){
    				System.out.println(f);
    			}
    			System.out.println("*************获取公有字段**并调用***********************************");
    			Field f = stuClass.getField("name");
    			System.out.println(f);
    			//获取一个对象
    			Object obj = stuClass.getConstructor().newInstance();//产生Student对象--》Student stu = new Student();
    			//为字段设置值
    			f.set(obj, "刘德华");//为Student对象中的name属性赋值--》stu.name = "刘德华"
    			//验证
    			Student stu = (Student)obj;
    			System.out.println("验证姓名:" + stu.name);
    			
    			
    			System.out.println("**************获取私有字段****并调用********************************");
    			f = stuClass.getDeclaredField("phoneNum");
    			System.out.println(f);
    			f.setAccessible(true);//暴力反射,解除私有限定
    			f.set(obj, "18888889999");
    			System.out.println("验证电话:" + stu);
    			
    		}
    	}
    

    控制台输出:

    ************获取所有公有的字段********************
    public java.lang.String fanshe.field.Student.name
    ************获取所有的字段(包括私有、受保护、默认的)********************
    public java.lang.String fanshe.field.Student.name
    protected int fanshe.field.Student.age
    char fanshe.field.Student.sex
    private java.lang.String fanshe.field.Student.phoneNum
    *************获取公有字段**并调用***********************************
    public java.lang.String fanshe.field.Student.name
    验证姓名:刘德华
    **************获取私有字段****并调用********************************
    private java.lang.String fanshe.field.Student.phoneNum
    验证电话:Student [name=刘德华, age=0, sex=
    

    6、获取成员方法并调用:

    Student类:

    package fanshe.method;
     
    public class Student {
    	//**************成员方法***************//
    	public void show1(String s){
    		System.out.println("调用了:公有的,String参数的show1(): s = " + s);
    	}
    	protected void show2(){
    		System.out.println("调用了:受保护的,无参的show2()");
    	}
    	void show3(){
    		System.out.println("调用了:默认的,无参的show3()");
    	}
    	private String show4(int age){
    		System.out.println("调用了,私有的,并且有返回值的,int参数的show4(): age = " + age);
    		return "abcd";
    	}
    }
    

    测试类:

    package fanshe.method;
    import java.lang.reflect.Method;
     
    /*
     * 获取成员方法并调用:
     * 
     * 1.批量的:
     * 		public Method[] getMethods():获取所有"公有方法";(包含了父类的方法也包含Object类)
     * 		public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的)
     * 2.获取单个的:
     * 		public Method getMethod(String name,Class<?>... parameterTypes):
     * 					参数:
     * 						name : 方法名;
     * 						Class ... : 形参的Class类型对象
     * 		public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
     * 
     * 	 调用方法:
     * 		Method --> public Object invoke(Object obj,Object... args):
     * 					参数说明:
     * 					obj : 要调用方法的对象;
     * 					args:调用方式时所传递的实参;
    ):
     */
    public class MethodClass {
     
    	public static void main(String[] args) throws Exception {
    		//1.获取Class对象
    		Class stuClass = Class.forName("fanshe.method.Student");
    		//2.获取所有公有方法
    		System.out.println("***************获取所有的”公有“方法*******************");
    		stuClass.getMethods();
    		Method[] methodArray = stuClass.getMethods();
    		for(Method m : methodArray){
    			System.out.println(m);
    		}
    		System.out.println("***************获取所有的方法,包括私有的*******************");
    		methodArray = stuClass.getDeclaredMethods();
    		for(Method m : methodArray){
    			System.out.println(m);
    		}
    		System.out.println("***************获取公有的show1()方法*******************");
    		Method m = stuClass.getMethod("show1", String.class);
    		System.out.println(m);
    		//实例化一个Student对象
    		Object obj = stuClass.getConstructor().newInstance();
    		m.invoke(obj, "刘德华");
    		
    		System.out.println("***************获取私有的show4()方法******************");
    		m = stuClass.getDeclaredMethod("show4", int.class);
    		System.out.println(m);
    		m.setAccessible(true);//解除私有限定
    		Object result = m.invoke(obj, 20);//需要两个参数,一个是要调用的对象(获取有反射),一个是实参
    		System.out.println("返回值:" + result);	
    	}
    }
    

    控制台输出:

    ***************获取所有的”公有“方法*******************
    public void fanshe.method.Student.show1(java.lang.String)
    public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
    public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
    public final void java.lang.Object.wait() throws java.lang.InterruptedException
    public boolean java.lang.Object.equals(java.lang.Object)
    public java.lang.String java.lang.Object.toString()
    public native int java.lang.Object.hashCode()
    public final native java.lang.Class java.lang.Object.getClass()
    public final native void java.lang.Object.notify()
    public final native void java.lang.Object.notifyAll()
    ***************获取所有的方法,包括私有的*******************
    public void fanshe.method.Student.show1(java.lang.String)
    private java.lang.String fanshe.method.Student.show4(int)
    protected void fanshe.method.Student.show2()
    void fanshe.method.Student.show3()
    ***************获取公有的show1()方法*******************
    public void fanshe.method.Student.show1(java.lang.String)
    调用了:公有的,String参数的show1(): s = 刘德华
    ***************获取私有的show4()方法******************
    private java.lang.String fanshe.method.Student.show4(int)
    调用了,私有的,并且有返回值的,int参数的show4(): age = 20
    返回值:abcd
    

    7、反射main方法:

    Student类:

    package fanshe.main;
     
    public class Student {
    	public static void main(String[] args) {
    		System.out.println("main方法执行了。。。");
    	}
    }
    

    测试类:

    package fanshe.main;
    import java.lang.reflect.Method;
     
    /**
     * 获取Student类的main方法、不要与当前的main方法搞混了
     */
    public class Main {
    	
    	public static void main(String[] args) {
    		try {
    			//1、获取Student对象的字节码
    			Class clazz = Class.forName("fanshe.main.Student");
    			
    			//2、获取main方法
    			 Method methodMain = clazz.getMethod("main", String[].class);//第一个参数:方法名称,第二个参数:方法形参的类型,
    			//3、调用main方法
    			// methodMain.invoke(null, new String[]{"a","b","c"});
    			 //第一个参数,对象类型,因为方法是static静态的,所以为null可以,第二个参数是String数组,这里要注意在jdk1.4时是数组,jdk1.5之后是可变参数
    			 //这里拆的时候将  new String[]{"a","b","c"} 拆成3个对象。。。所以需要将它强转。
    			 methodMain.invoke(null, (Object)new String[]{"a","b","c"});//方式一
    			// methodMain.invoke(null, new Object[]{new String[]{"a","b","c"}});//方式二			
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    控制台输出:

    main方法执行了。。。

    8、利用反射创建数值:

    数组在Java里是比较特殊的一种类型,它可以赋值给一个Object Reference。

    public static void testArray() throws ClassNotFoundException {
            Class<?> cls = Class.forName("java.lang.String");
            Object array = Array.newInstance(cls,25);
            //往数组里添加内容
            Array.set(array,0,"golang");
            Array.set(array,1,"Java");
            Array.set(array,2,"pytho");
            Array.set(array,3,"Scala");
            Array.set(array,4,"Clojure");
            //获取某一项的内容
            System.out.println(Array.get(array,3));
        }

    9、反射方法的其他使用--通过反射运行配置文件内容:

    Student类:

    public class Student {
    	public void show(){
    		System.out.println("is show()");
    	}
    }
    

    配置文件以txt文件为例子:

    className = cn.fanshe.Student
    methodName = show
    

    测试类:

    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    import java.lang.reflect.Method;
    import java.util.Properties;
     
    /*
     * 我们利用反射和配置文件,可以使:应用程序更新时,对源码无需进行任何修改
     * 我们只需要将新类发送给客户端,并修改配置文件即可
     */
    public class Demo {
    	public static void main(String[] args) throws Exception {
    		//通过反射获取Class对象
    		Class stuClass = Class.forName(getValue("className"));//"cn.fanshe.Student"
    		//2获取show()方法
    		Method m = stuClass.getMethod(getValue("methodName"));//show
    		//3.调用show()方法
    		m.invoke(stuClass.getConstructor().newInstance());
    		
    	}
    	
    	//此方法接收一个key,在配置文件中获取相应的value
    	public static String getValue(String key) throws IOException{
    		Properties pro = new Properties();//获取配置文件的对象
    		FileReader in = new FileReader("pro.txt");//获取输入流
    		pro.load(in);//将流加载到配置文件对象中
    		in.close();
    		return pro.getProperty(key);//返回根据key获取的value值
    	}
    }
    

    控制台输出:

    is show()

    需求:

    当我们升级这个系统时,不要Student类,而需要新写一个Student2的类时,这时只需要更改pro.txt的文件内容就可以了。代码就一点不用改动。

    public class Student2 {
    	public void show2(){
    		System.out.println("is show2()");
    	}
    }
    

    配置文件更改为:

    className = cn.fanshe.Student2
    methodName = show2
    

    10、反射方法的其他使用--通过反射越过泛型检查:

    泛型用在编译期,编译过后泛型擦除(消失掉),所以是可以通过反射越过泛型检查的

    测试类:

    import java.lang.reflect.Method;
    import java.util.ArrayList;
     
    /*
     * 通过反射越过泛型检查
     * 例如:有一个String泛型的集合,怎样能向这个集合中添加一个Integer类型的值?
     */
    public class Demo {
    	public static void main(String[] args) throws Exception{
    		ArrayList<String> strList = new ArrayList<>();
    		strList.add("aaa");
    		strList.add("bbb");
    		
    	//	strList.add(100);
    		//获取ArrayList的Class对象,反向的调用add()方法,添加数据
    		Class listClass = strList.getClass(); //得到 strList 对象的字节码 对象
    		//获取add()方法
    		Method m = listClass.getMethod("add", Object.class);
    		//调用add()方法
    		m.invoke(strList, 100);
    		
    		//遍历集合
    		for(Object obj : strList){
    			System.out.println(obj);
    		}
    	}
    }
    

    控制台输出:

    aaa
    bbb
    100

    推荐阅读:

    参考博客:https://www.sczyh30.com/posts/Java/java-reflection-1/

    展开全文
  • 反射破坏单例的私有构造函数保护

    千次阅读 2014-03-09 12:25:15
    Java的反射破坏单例的私有构造函数保护,最典型的就是Spring的Bean注入,我们可以通过改造私有构造函数来防止。

            Java的反射破坏单例的私有构造函数保护,最典型的就是Spring的Bean注入,我们可以通过改造私有构造函数来防止。

     

            在Singleton中,我们只对外提供工厂方法(获取单例),而私有化构造函数,来防止外面多余的创建。

            对于一般的外部调用来说,私有构造函数已经很安全了。

        public class Singleton {
            private Singleton(){}  
            private static volatile Singleton instance = null;
            public static Singleton getInstance() throws Exception {
               if (instance == null) {  //为了简洁度,暂不考虑线程安全
                   instance = new Singleton();
               }
               return instance;
            }
        }
            Class singletonClass = Class.forName("com.jscai.spring.demo.Singleton");
            Constructor[] cts =singletonClass.getConstructors();
            System.out.println(cts.length);

            一般的外部调用,编译器会校验,直接提示编译错误。而正常的反射也是找不到私有构造函数的,所以上面的输出为0。

     

            但是一些特权用户可以通过反射来访问私有构造函数,并且实例化:

           Constructor[] cts = singletonClass.getDeclaredConstructors();
           System.out.println(cts.length);
           cts[0].setAccessible(true);
           Singleton singleton = (Singleton) cts[0].newInstance();

            上述代码首先通过反射的getDeclaredConstructors()来获取所有构造函数(public,protected,default * (package) access, andprivate constructors),当然这个函数会校验调用者的权限。

            此时默认还是不能调用私有构造函数的,还需要把访问权限打开setAccessible(true),就可以访问私有构造函数了,这样破坏了单例的私有构造函数保护。

     

            如果要防御这样的反射侵入,可以修改构造函数,加上第二次实例化的检查。(上面的getInstance()经过多线程(DoubleCheck)处理后,就不会出现线程冲突来触发这个异常)

        private static int cntInstance = 0;
        private Singleton()throws Exception {
           if (++cntInstance > 1 ) {
               throw new Exception("Can'tcreate another instance.");
           }
        }
    

            另外,在Spring的Bean注入中,即使你私有化构造函数,默认他还是会去调用你的私有构造函数去实例化。       【通过BeanFactory来装配Bean,和上面的逻辑如出一辙】

            所以,如果我们想保证实例的单一性,就要在定义<bean>时加上factory-method=””的属性,并且在私有构造函数中添加防御机制。单例的getInstance()可能会添加一些逻辑,而Spring的默认调用构造函数去创建,就不能保证这份逻辑的准确性,所以会带来隐患。

            我们可以通过scope="prototype"来测试单例是否被多次创建:

        <beanid="test"class="com.jscai.spring.demo.Singleton"scope="prototype"></bean>

         BeanFactory bf = new ClassPathXmlApplicationContext("demoAppTestContext.xml");
         Singleton test1 = (Singleton) bf.getBean("singleton");
         Singleton test2 = (Singleton) bf.getBean("singleton");
    

            发现防御机制生效,抛出"Can't create another instance."的异常,证明Spring能正常调用私有的构造函数来创建Bean,并且创建了多次。

            这时候我们要使用factory-method来指定工厂方法,才能达到我们想要的效果:

        <beanid="test"class="com.jscai.spring.demo.Singleton"scope="prototype"factory-method="getInstance"></bean>

     

    ----参考《Effective Java》 & 《Spring in Action》

    展开全文
  • 为了延长EUV 反射镜的稳定与使用寿命,一般采取在Mo/Si多层膜表面添加保护层。采用直流反应磁控溅射技术,建立氧气流量与溅射电压之间的“迟滞回线”关系,进而准确掌握不同氧化物保护层所需氧气量,以此减少过多...
  • Java反射

    2019-09-18 10:07:16
    什么是反射2. 反射可以用来做什么3. Class类4. 利用反射分析类5. 利用反射分析对象6. 利用反射编写泛型数组7. 利用反射实现函数指针的功能8. 小结 1. 什么是反射 反射是一种功能强大且复杂的机制。Java反射说的是在...
  • 信号完整反射

    千次阅读 2010-10-07 20:08:00
    反射是指从发射端发射出去的信号,不能被接收端完全吸收,造成部分能量返回的现象。  反射是由于阻抗不匹配引起的。实际点讲是:过长的走线、未被匹配终结的传输线、过量电容或电感以及阻抗失配。 ...
  • <br />安全反射: 在处理反射时安全是一个较复杂的问题。反射经常由框架型代码使用,由于这一点,我们可能希望框架能够全面接入代码,无需考虑常规的接入限制。但是,在其它情况下,不受控制的接入...
  • 深入理解Java类型信息(Class对象)与反射机制

    万次阅读 多人点赞 2017-05-01 23:19:19
    【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) ...深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解
  • (多选)Java是一门支持反射的语言,基于反射为Java提供了丰富的动态支持,下面关于Java反射的描述,哪些是错误的:() A. Java反射主要涉及的类如Class, Method, Filed,等,他们都在java.lang.reflet包下 B. 通过...
  • c反射机制介绍_介绍反射

    千次阅读 2020-06-30 05:33:58
    在“ Java编程动力学,第1部分 ”中,我向您介绍了... 为了使即使对于已经了解反射基础知识的开发人员来说,也使事情变得有趣,我将介绍反射性能与直接访问的比较。 不要错过本系列的其余部分 第1部分,“ 类和...
  • BGP路由反射器RR

    千次阅读 多人点赞 2020-06-23 13:46:35
    曾子曰:“吾日三省吾身:为人谋而不忠乎?与朋友交而不信乎?传不习乎?” 文章目录 一、拓扑 二、基础配置与分析 三、BGP13条选路原则 ...路由反射器的使用,会明显减少配置工作量,人为出错的可能也会大大降低。
  • Java反射机制详解

    千次阅读 2018-12-19 02:31:08
    对于一般的开发者,很少需要直接使用Java反射机制来完成功能开发,但是反射是很多框架譬如 Spring, Mybatis 实现的核心,反射虽小,能量却很大。 本文主要介绍反射相关的概念以及API的使用,关于反射的应用将在下一...
  • 为制备出在130~210 nm波段具有良好光谱性能的铝反射膜,优化设计了铝反射镜中铝层和保护层氟化镁的厚度,理论确定铝层和氟化镁保护层最佳厚度分别为80 nm和33 nm。采用热舟蒸发工艺,在BK7基片上制备了Al反射膜样品...
  • Method、Field和Constructor类都继承了AccessibleObject类,它提供了标记反射对象的能力,以抑制在使用时使用默认Java语言访问控制检查,从而能够任意调用被私有化保护的方法、域和构造函数; /** *...
  • java反射

    千次阅读 2013-10-12 17:50:23
    Java中,反射是一种强大的工具。它使您能够创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代表链接。反射允许我们在编写与执行时,使我们的程序代码能够接入装载到JVM中的类的内部信息,而不是源...
  • 反射之暴力反射

    千次阅读 2013-12-30 21:49:50
    反射对象中设置 accessible 标志允许具有足够特权的复杂应用程序(比如 Java Object Serialization 或其他持久机制)以某种通常禁止使用的方式来操作对象。 setAccessible  public void setAccessible...
  • Spring之反射

    千次阅读 2018-06-04 22:45:55
    反射 在运行状态中,对于任意一个类都能够知道它的属性和方法,对于任意一个对象都能够调用他的属性和方法,这样的动态获取属性和方法和动态调用属性和方法的功能就叫做反射。 获取Class对象的方法 调用对象的...
  • JAVA反射机制总结

    千次阅读 2016-08-16 18:22:10
    JAVA反射机制总结JAVA反射机制总结 反射的概述 什么是反射 为什么用反射机制 反射机制的关键 获取Class对象 获得构造器的方法 获得属性的方法 获得方法信息的方法 关于getMethods和getDeclaredMethods的区别 反射...
  • java反射基础学习

    千次阅读 2021-06-14 17:44:28
    什么是反射? JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言...
  • Reflect Java反射机制

    千次阅读 2016-04-18 17:10:08
    Reflect Java反射机制
  • 反射式dll注入

    千次阅读 2019-08-27 11:04:36
    (像金山毒霸kxetray.exe有自我保护机制也注入不进去)。由于对会话隔离注入不太了解,怕搞坏主机,没有再去实现注入到系统进程中。最近在网上看到dll反射注入,想把学习总结的笔记给大家分享一下。 首先什么是反射...
  • 面试官:反射都不会,还敢说自己会Java?

    万次阅读 多人点赞 2020-04-29 15:50:03
    一、反射机制 1.1 框架   在学习Java的路上,相信你一定使用过各种各样的框架。所谓的框架就是一个半成品软件,已经对基础的代码进行了封装并提供相应的API。在框架的基础上进行软件开发,可以简化编码。学习使用...
  • Java反射机制ABC

    千次阅读 2018-03-09 14:13:36
    JAVA反射机制 在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制...
  • 在“ Java编程的动态,第1部分,”我为您介绍了Java编程类和类装入。该篇文章介绍了一些Java二进制类格式的相关信息。这个月我将阐述使用Java反射API来在运行时接入和使用一些相同信息的基础。为了使已经熟知反射...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 34,154
精华内容 13,661
关键字:

保护性反射