反射

1.反射机制:

java运行期间动态的加载一些不确定的类的对象。大多数的情况下我们使用的是一个确定的类,通过在内存中的加载,再使用。
反射机制提供的功能

  • 加载运行时才能确定的数据类型
  • 解析类的结构,获取其内部信息
  • 能够访问属性,调用方法,创建新的对象。

1.1 动态加载类

image.png

通过以上的代码可以总结使用Reflection.需要如下几步:

  1. 获取目标对象的Class对象
  2. 调用Class对象内省方法获取目标对类成员信息
  3. 调用目标的成员属性

1.2 解析类的结构

1.2.1 定义一个Teacher的类

public class Teacher {
private String name;
    private  int age;
    private  static  int total;
    public Teacher(String name, int age) {
        this.name = name;
        this.age = age;
        total++;
    }
    public Teacher() {
       total++;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public static int getTotal() {
        return total;
    }
    public static void setTotal(int total) {
        Teacher.total = total;}
    @Override
    public String toString() {
        return "Teacher{" + "name='" + name + '\'' + ", age=" + age + '}';
    }
}

1.2.2 对Teacher进行解析

  public class RflectionTeacher {
    private  final  static  String TEACHER_CLASS="reflection.Teacher";
    public static void main(String[] args) {
        try {
            Class<?> clazz = Class.forName(TEACHER_CLASS);
            Field[] fields = clazz.getDeclaredFields();//获取该类中的属性属性成员
            Method[] methods = clazz.getDeclaredMethods();//获取该类的成员方法
            Constructor<?>[] constructors = clazz.getConstructors();//获取该类的所有的构造方法
            System.out.println("------打印成员属性-------");
            for(Field field:fields){
                System.out.println("属性 :"+field);
                System.out.println("名称 :"+field.getName());
                System.out.println("修饰符 :"+ Modifier.toString(field.getModifiers()));
                System.out.println("--------------------------------------------------");
            }
            for (Method method:methods){
                System.out.println("方法 :"+method.toString());
                System.out.println("方法名称 :"+method.getName());
                System.out.println("方法修饰符 :"+Modifier.toString(method.getModifiers()));
                System.out.println("------方法参数列表------");
                Class<?>[] types = method.getParameterTypes();
                System.out.println(types.length!=0?"有参数":"无参数:");
                for (Class c:types){
                    System.out.println(c.getName()+"类型\t");
                }
                System.out.println("\n方法返回类 型 :"+method.getReturnType().getName());
                System.out.println("=====================================");
            }
            System.out.println("***************打印构造方法 ***************");
            for(Constructor constructor:constructors){
                System.out.println("构造方法 :"+constructor.toString());
                System.out.println("构造方法名 :"+constructor.getName());
                System.out.println("构造方法修饰符 :"+Modifier.toString(constructor.getModifiers()));
                Class[] mClass=constructor.getParameterTypes();
                System.out.print(mClass.length!=0?"有参数:":"无参数:");
                for(Class c:mClass){
                    System.out.print(c.getName()+"类型\t");
                }
                System.out.println("\n=====================================");
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

1.2.3 输出结果

------打印成员属性-------
属性 :private java.lang.String reflection.Teacher.name
名称 :name
修饰符 :private
--------------------------------------------------
属性 :private int reflection.Teacher.age
名称 :age
修饰符 :private
--------------------------------------------------
属性 :private static int reflection.Teacher.total
名称 :total
修饰符 :private static
--------------------------------------------------
方法 :public java.lang.String reflection.Teacher.toString()
方法名称 :toString
方法修饰符 :public
------方法参数列表------
无参数:

方法返回类 型 :java.lang.String
=====================================
方法 :public java.lang.String reflection.Teacher.getName()
方法名称 :getName
方法修饰符 :public
------方法参数列表------
无参数:

方法返回类 型 :java.lang.String
=====================================
方法 :public void reflection.Teacher.setName(java.lang.String)
方法名称 :setName
方法修饰符 :public
------方法参数列表------
有参数
java.lang.String类型  

方法返回类 型 :void
=====================================
方法 :public static int reflection.Teacher.getTotal()
方法名称 :getTotal
方法修饰符 :public static
------方法参数列表------
无参数:

方法返回类 型 :int
=====================================
方法 :public int reflection.Teacher.getAge()
方法名称 :getAge
方法修饰符 :public
------方法参数列表------
无参数:

方法返回类 型 :int
=====================================
方法 :public void reflection.Teacher.setAge(int)
方法名称 :setAge
方法修饰符 :public
------方法参数列表------
有参数
int类型   

方法返回类 型 :void
=====================================
方法 :public static void reflection.Teacher.setTotal(int)
方法名称 :setTotal
方法修饰符 :public static
------方法参数列表------
有参数
int类型   

方法返回类 型 :void
=====================================
***************打印构造方法 ***************
构造方法 :public reflection.Teacher(java.lang.String,int)
构造方法名 :reflection.Teacher
构造方法修饰符 :public
有参数:java.lang.String类型  int类型   
=====================================
构造方法 :public reflection.Teacher()
构造方法名 :reflection.Teacher
构造方法修饰符 :public
无参数:
=====================================

1.3 访问类的属性和方法

1.3.1 Student类

public class Student {
private String name;
    private static  int count=100;
    public Student() {
    }
    public Student(String name) {
        this.name = name;
    }
    public void setValue(String name){
        this.name = name;
    }
    public void showCount(){
        System.out.println("Student对象被实例化了"+count+"次");
    }
    public String toString(){
        return "Name:"+this.name+",调用次数:"+count;
    }
}

1.3.2 访问 name 属性的操作方法:

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
         //访问name属性的操作方法
        Student student = new Student("zhangsan");
        Class<? extends Student> claszz = student.getClass();
        Field field = claszz.getField("name");
        Object o = field.get(student);
        System.out.println("修改前 "+ field.getName()+" 的值 "+o);
        field.set(student,"李思");
        o=field.get(student);
        System.out.println("修改后:"+field.getName()+"的值:"+o);
    }

1.3.3 访问 setValue 方法的操作方法

 public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        //访问 setValue 方法的操作方法
        Student student = new Student("zhangsan");
        Class<? extends Student> claszz = student.getClass();
        Method m = claszz.getMethod("setValue", new Class[]{String.class});
        m.invoke(student, new Object[]{"张三"});
        System.out.println(student.toString());

    }

1.3.4 访问类的有参构造方法

 public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //访问类的有参构造方法
        Class<?> clazz = Class.forName("reflection.Student");
        Constructor<?> constructor = clazz.getConstructor(new Class[]{String.class});
        Student student= (Student)constructor.newInstance(new Object[]{"陈飞"});
        System.out.println("----->>>>-----"+student);
    }

1.4 如何使用反射机制

使用反射机制,就是因为不知道运行的时候不知道使用哪一个类,所以就需要运行的时候动态加载。先加载动态的类,然后再解析类。最后使用反射API对类的成员信息进行访问。

1.5 静态代理

若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的。 通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类

public interface Subject {
    public  int add(int a ,int b);
}
public class ReadSubject implements  Subject {
    @Override
    public int add(int a, int b) {
        return a+b;
    }
}
public class Proxy implements Subject {

    private Subject subject=null;

    public Proxy(Subject subject) {
        this.subject = subject;
    }

    @Override
    public int add(int arg1, int arg2) {
        System.out.println("被加数为:"+arg1);
        System.out.println("加数为:"+arg2);
        return subject.add(arg1, arg2);
    }
}
public class ProxyTest {
    public static void main(String[] args) {
        Subject subject = new Proxy(new ReadSubject());
        int resulr=subject.add(1,4);
        System.out.println(resulr);
    }
}

1.6动态代理

静态代理解决了业务逻辑与日志信息脱耦的一种设计, 但是又带来其他的问题, 也就是
说我们有 100 个目标对象,就需要设计 100 个代理,这样会引起类爆炸(类非常多) 。
代理类在程序运行时创建的代理方式被成为 动态代理。 也就是说,这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。

public class DynamicProxy implements InvocationHandler {
    private  Object object=null;
     public Object biding(Object object){
         this.object=object;
         return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
     }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result=null;
        for (Object o:args){
            System.out.println(o);
        }
        result=method.invoke(object,args);
        return result;
    }
}
public class DymicProxyTest {
    public static void main(String[] args) {
        DynamicProxy dynamicProxy = new DynamicProxy();
        Subject biding = (Subject)dynamicProxy.biding(new ReadSubject());
        int resultt=biding.add(1,6);
        System.out.println(resultt);
    }
}

1.7 创建对象的几种方式

  • 使用new关键字:这是我们最常见的也是最简单的创建对象的方式,通过这种方式我们还可以调用任意的够赞函数(无参的和有参的)。比如:Student student = new Student()

  • 使用Class类的newInstance方法:我们也可以使用Class类的newInstance方法创建对象,这个newInstance方法调用无参的构造器创建对象,如:Student student2 = (Student)Class.forName("根路径.Student").newInstance(); 或者:Student stu = Student.class.newInstance();

  • 使用Constructor类的newInstance方法:本方法和Class类的newInstance方法很像,java.lang.relect.Constructor类里也有一个newInstance方法可以创建对象。我们可以通过这个newInstance方法调用有参数的和私有的构造函数。如: Constructor<Student> constructor = Student.class.getInstance(); Student stu = constructor.newInstance(); 这两种newInstance的方法就是大家所说的反射,事实上Class的newInstance方法内部调用Constructor的newInstance方法。这也是众多框架Spring、Hibernate、Struts等使用后者的原因。

  • 使用Clone的方法:无论何时我们调用一个对象的clone方法,JVM就会创建一个新的对象,将前面的对象的内容全部拷贝进去,用clone方法创建对象并不会调用任何构造函数。要使用clone方法,我们必须先实现Cloneable接口并实现其定义的clone方法。如:Student stu2 = <Student>stu.clone();这也是原型模式的应用。

  • 使用反序列化:当我们序列化和反序列化一个对象,JVM会给我们创建一个单独的对象,在反序列化时,JVM创建对象并不会调用任何构造函数。为了反序列化一个对象,我们需要让我们的类实现Serializable接口。如:ObjectInputStream in = new ObjectInputStream (new FileInputStream("data.obj")); Student stu3 = (Student)in.readObject();

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,991评论 18 399
  • 一. Java基础部分.................................................
    wy_sure阅读 9,273评论 0 11
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,655评论 19 139
  • 德泰能源邓总、左副总及其他诸君: 今日偶知德泰即将迎来五周年庆典,实在是可喜可贺!作为免费用了不少德泰充电宝的用户...
    平选2015阅读 1,599评论 0 0
  • 这部分内容只是对四层进行发现,发现主机是否在线。后期会针对端口进行探测。 四层发现比二层,三层更加精确。 这里要注...
    FKTX阅读 2,578评论 0 0