7 - 24 反射

27 篇文章 0 订阅

1.反射

1.1 反射机概述

java能够通过反射的前提:已经加载过这个类就可以通过类名来寻找到这个类的所有相关信息

就跟人类的记忆反射一样,实现子啊记忆中有了这个事物具有的信息,人就可以通过名字来在记忆中寻找相关的书屋的具体。

java Reflection

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

java反射机制提供的功能

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

        在运行时构造任意一个类的对象

        在运行时判断任意一个类所具有的成员和方法

        在运行时调用任意一个对象的成员变量和方法

        生成动态代理

java反射机制研究及应用

反射相关的主要API

java.lang.Class:代表一个类

java.lang.reflect.Method:代表类的方法

java.lang.reflect.Field:代表了类的成员变量

java.lang.reflect.Constructor:代表类的构造方法、

一个类极限情况都有什么

        一个父类,多个接口

        多个属性

        多个构造方法,包括构造参数及其类型

        多个普通方法,包括参数及起类型,返回值类型

1.2 Class类

在Object类中定义了一下的方法,此方法将被所有子类继承:

public final Class getClass()

以上的方法返回值的类型是一个Class类,此类事Java反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即:可以通过对象反射求出类的名称

public class Test{
    public static void main(String[] args){
        Person p = new Person();
        Class clazz = p.getClass(); //clazz对象中包含对象p所属的Person类的所有信息
    }
}

        反射可以得到的信息:某个类的属性,方法和构造器,某个了到底实现了那些接口。对于每个了i而言,JRE都为其保留一个不变的Class类型的对象。一个Class对象包含了特定某个类的有关信息。

        Class本身也是一个类

        Class对象只能由系统建立对象

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

        一个Class对象对应的是一个加载到JVM中的一个.class文件        

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

        通过Class可以完整的得到一个类中的完整结构;

Class 类的常用方法

 实例化Class类对象(四种方法)

 前提:若已知具体了的类,通过类的class属性获取,该方法最为可靠,程序性能最高

        实例:Class clazz = String.class;

前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象

        实例:Class  class = “www.xyd.com”.getClass();

前提:一致一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException

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

其他方式(不要求)

        ClassLoader cl = this.getClass().getClassLoader();

        Class clazz4 = cl.loadClass("类的全类名"); 

​
public class Test{
    public static void main(String[] args){
        Person p = new Person();
        Class clazz = p.getClass(); //clazz对象中包含对象p所属的Person类的所有信息
            
         Class c0 = Person.class;//通过类名.class创建只当类的Class实例
         Class c1 = p.getClass();//通过一个类的实例对象getClass()方法 获取对应实例对象的类的class实例    
        try{
            //通过Class的静态方法forName (String className)来获取一个类的Class实例
            //forName(String className)方法中的参数是你要获取的class实例的类的全部路径(包名.类名)
             Class c2 = Class.forName("day14.Person");//获取class实例的常用方法;
            
            } catch (CLassNotFoundException e){

                e.printStackTrace();
            }
        
         
    }
}

​

//=======================================


public class Person{
    
    public String name;
    int age;
}

1.3 反射获取一个类的父类

public class Person{
    public String name;
    int age;
}

//=========================================================

public class Student extends Person imlements Move , Study{

    String school;
    
    public void showInfo(){
        System.out.println("学校是:" + this.school);
    }       

    @Override
    public void studyInfo(){
        System.out.println("学习的中学的知识");
    }
    
    @Override
    public void moceType(){
        System.out.println("骑自行车上学");
    }
}

//=============================================

public interface Move{
    void moveType();
}

//=========================================

public interface Study [
    void studyInfo();
}

//============================================

public class Test1{
    public static void main(String [] args){
        try{
            Class clazz  = Class.forName("day14.Student");//通过包名.类名的字符串,调用Class.forName方法获取指定类的Class实例
            Class superClazz = clazz.getSuperclass();//获取父类
            System.out.println(superClazz.getName());

            Class[] interfaces = clazz.getInterfaces();//获取当前类的所有接口
            for(Class c : interfaces){
                System.out.println("接口:" + c.getName());
            }
        } catch(ClassNotFoundException e){
            e.printStackTrace();
        }

    }
}

1.4 反射获取一个类的构造器

全部的构造器
    public Constructor<T>[] getConstructors()
返回此Class 对象所表示的类的所有的public 构造方法;
    public Constructor<T>[] getDeclaredConstructors()
返回此Class对象表示的类声明的所有构造方法。

Constructor类中:
    取得修饰符:public int getModifiers();
    取得方法名称:public String getName();
    取得参数的类型:public Class<?>[] getParameter();
​
public class Student exteds Person implements Move,Study{
    public Student (){

    }
    public Student (String school){
        this.school = school;
    }
    public Student (String name ,int age){
        this.name = name;
        this.age = age;
    }
    String school;
}

public class Test1{
    public static void main(String[] args){
        try{

            Constructor[] cons = clazz.getConstructors();
            for(Constructor c : cons){
                Systrm.out.println("构造方法名称" + c.getName());//获取方法名称
                   //getModifiers()取得方法的修饰符,返回数组1代表public 
                System.out.println("构造方法:" + c.getName() + "的修饰是:" + c.getModifiers());

                 Class [] paramClazz = c.getParmeterTypes();
                for(Class pc : paramClazz){
                    System.out.println("构造方法:" + c.getName() + "的参数类型是:" pc.getName());
                }
            }
            
            
            
            Constructor[] cons1 = clazz.getDeclaredConstructors();//获取类的所有构造方法,包括共有和私有的
            for(Constructor c : cons1){
                System.out.println("构造方法名称:" + c.getName());//取得方法名称
                //getModifiers取得方法的修饰符,返回数组1代表public,返回数组2代表是private
                System.out.println("构造方法:" + c.getName() + "的修饰符是:" + c.getModifers());//getModifers()取得方法修饰符


                Class [] paramClazz = c.getParmeterTypes();
                for(Class pc : paramClazz){
                    System.out.println("构造方法:" + c.getName() + "的参数类型是:" pc.getName());
            }
        }
    }
}

​

1.5 通过反射创建一个对象

public static void main(String [] args){
    try {
        //通过包名.类名的字符串,调用Class.forName方法获取指定类的Class实例
        Class Clazz = Class.forName("day14.Student");
        
        //如果用反射的构造方法来创建对象
        try{
             Obect obj = clazz.newInstance();//相当于调用Student类的无参共有的构造方法
             Student stu = (Strdent) obj;//强制类型转换

             Constructor c = clazz.getConstructor(String.class);//获取有参构造
             Student str1 =  (Student)c.newInstance("第一中学");//newInstance实例化对象,相当于调用public Student (String school)
             System.out.println(str1.school);

            //通过反射机制,可以强制的调用私有的构造方法
            Constructor c = clazz.getDeclaredConstructor(String.class,int.class);//指定获取有两个参数()的构造方法public Student (String name ,int age)
            c.setAccessible(true);//解除私有的封装,下面就可以对这个私有方法强制调用
            Strdent stu = (Student)c.newInstance("zhangsan",12);
        }catch(Exception e){
            e.printStackTrace();
        }
       
        
    } catch (ClassNotFoundException e) {
        e.printStrackTrace();
     }
}


public class Student exteds Person implements Move,Study{
    public Student (){
        System.out.printIn("调用的是public Student ()");
    }
    public Student (String school){
        this.school = school;
         System.out.printIn("调用的是public Student (String school)");
    }
    public Student (String name ,int age){
        this.name = name;
        this.age = age;
         System.out.printIn("调用的是public Student (String name ,int age)");
    }
    String school;
}

1.6 反射机制获取类的方法

全部方法
    public Method[] getDeclaredMethods();
返回此Class对象所表示的类或接口的全部方法
    public Method[] getMethods()
返回此Class都对象所表示的类或接口的public的方法

Method类中:
    public Class<?> getReturnType()取得全部的返回值
    public Class<?> getParameterTypes()取得全部的参数
    public int getModifiers()取得修饰符
public class Student exteds Person implements Move,Study{
    String school;
   public void test(String name){
        
    }

    public String getSchool() {
        return this.school;
    }
}

public class Test1{
    public static void main(String[] args){
        try{
            //通过包名.类名的字符串,调用class.forName方法获取指定类的Class实例;
            Class clazz = Class.forNmame("day14.Student");
            Method[] ms =  clazz.getMethods();//获取到类的所有公有方法
            Method[] ms = clazz.getCdclaredMethods();//获取类的所有方法,包括共有和私有
            for(Method m : ms){
                System.out.println("方法名:" + m.getName());
                System.out.println("方法名:" + m.getReturnType());
                System.out.println("方法名:" + m.getModifiers());

                //获取方法的参数类型,是一个数组,方法有几个参数数据就有几个元素
                Class [] pcs = m.getparamterTypes();
                if(pcs != null && pcs.lenth >0){
                    for(Class pc : pcs){
                        System.out.println("参数类型:" + pc.getName());
                        
                    }
                }
                Systemout.println("=======================");
            }
        }
    }
}

1.7 反射机制获取类的属性和包

全部的Field
    public Field[] getFields()
    返回此Class对象所表示的类或接口的public的Field。
    public Field[] getDeclaredFields()
   返回此Class对象所表示的类或接口的全部Field

Field方法中:
    public int getModifiers() 以整数象实放回此Field的修饰符
    public Class<?> getType() 得到Field得属性类型
    public String getName() 返回FIeld得类型。
public class Student exteds Person implements Move,Study{
    public String school;
    private String privateField;
}

public class Test1{
    public static void main(String[] args){
        try{
            //通过包名.类名的字符串,调用class.forName方法获取指定类的Class实例;
            Class clazz = Class.forNmame("day14.Student");

            Field [] fs = clazz.getFields();//获取类得公有得属性
            Field [] fs = clazz.getDeclaredFields();//获取本类(不包括父类得属性)所有得属性,包括共有和私有
            for(Field f : fs){
                System.out.println("修饰符:" + f.getModifiers());
                System.out.println("属性得类型:" + f.getType());
                System.out.println("属性得名称:" + f.getName());
                
            }


            //获取类所在的包
            Package p = clazz.getPackage();//获取类所在的包
            System.out.println(p.getName());



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

1.8 反射机制调用指定方法和指定属性

调用指定方法
    通过反射调用类中的方法,通过Method类完成。
步骤:
    1. 通过Class类的getMethod(String name , Class...parameterTypes)方法取得一个Method对象,并设置此方法操作时所需要的参数类型。
    2. 之后使用object invoke(Object obj,Object[] args)进行调用,并向方法中传递要设置的obj对象的参数信息;
public class Student exteds Person implements Move,Study{

    private void test(String name){
        System.out.println("这是私有方法private void test(String name)");
    }

    public String getSchool(){
        return this.school;
    }

    public void setInfo(String name,String school){
        this.name = name;
        this.school = school
        System.out.println("这个是setInfo(String name,String school)方法");
    }

    //方法重载   
    public void setInfo(int age){
        System.out.println("这个是public void setInfo(int age)方法");
    }
    
}


public class Test1{
    public static void main(String[] args){

        try{
            //下面不论是反射调用setInfo还是test方法,都是调用的obj对象的方法,obj对象实际上就是student对象
            
            Constructor con = clazz.getConstructor();//获取无参构造
            Object obj = con.newInstance();//使用无参构造创建对象
            
            //调用公有有参方法
            
           //得到名称叫setInfo,参数是String,String的方法
           Method e = clazz.getMethod("setInfo",String.class,String.class);
           //调用
            m.invoke(obj,“zhangsan”,"第一中学")//参数1是需要实例化的对象,后面的参数是调用当前的方法的实参
            
           //调用私有有参方法
            
            //获取方法名为test,参数为1个String类型的方法
              Method m1 = clazz.getDeclareMethod("test",String.class);
               m1.setAccessible(true);//解除私有的封装,下面可以强制调用私有方法
               m1.invoke(obj,"李四");
             

            //调用一个重载方法
              Method m2 = clazz.getMethod("setInfo",int.class);//setInfo的重载方法
              m2.invoke(obj,1);

            //有返回值的方法
            //获取方法名为getSchool并且没有参数的方法
              Method m3 = clazz.getMethod("getSchool");//没有参数就不用写
              String school = (String)m3.invoke(obj);//调用有返回值的但是没有参数的方法
              System.out.println(school)

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

1.9 反射机制调用指定属性

调用指定属性

public class Test1{
    public static void main(String[] args){
       try{

            //反射创建一个对象
            Constructor con = clazz.getConstructor();
            object stu = (Student)con.newInstance();

            //访问属性
            clazz.getField("school");//获取名称为school的属性

            f.set(stu,"第三中学");//对stu对象的school属性设置值“第三中学”
            String school = (String)f.get(stu);//获取stu对象的school属性的值
            System.out.println(School);
            
            //访问私有属性    
            Field f1 = clazz.getDeclareField("privateField");
            f1.setAccessible(true);//解除私有的封装,下面就可以强制的调用这个属性
            f1.set(stu,"测试私有属性");
            System.out.println(f1.get(stu));

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

public class Student extends Person implements Move,Study{
    public String school;
    private String privateField;
}

1.10 Java的动态代理

        Proxy: 专门完成代理的操作类,是所有动态代理类的父类。通过此类为一一个或多个接口动态地生成实现类。

创建一个动态代理类所对应的Class对象

        static Object newProxyInstance(ClassLoader loader Class<?>[] interfaces,

InvocationHandler h)直接创建一个动态代理对象

一个java项目,其中有100java类,每个java有10个方法, 这总共1000个方法

现在有这样一个需求, 需要在每个java方法上加上2句话,在方法执行前输出这

个方法开始执行,在方法执行后输出这个方法已经完成。

//接口
public interface ITestDemo {
   void test1();
   void test2();
}

 //实现类
public class TestDemoImpl implements ITestDemo{
    @Override
    public void test1{
        System.out.println("执行test1()方法");
    }

    @Override
    public void test2(){
        System.out.println("执行test2()方法");
    }
}



public class Test2{
    public static void main (String[] args) {

        ITestDemo test = new TestDemoImpl();

        /*
        *注意:
        *如果一个对象想要通过proxy.newProxyInstance方法被代理,
        *那么这个对象的类一定要有相应的接口
        *就像本类中的ITestDemo接口和实现类TestDemoImpl
        */

        test.testl() ;
        test.test2() ;

        /*
        *需求:
        *在执行test1和test2方法时需要加入一些东西
        *在执行方法前打印test1或test2开始执行
        *在执行方法后打印test1或test2执行完毕
        *打印的方法名要和当时调用方法保存一致
        */

        InvocationHandler handler = new Proxydemo(test);
        
        /*
        *Proxy.newProxyInstance(Classloader,interfaces,h);
        *参数1是代理对象的类加载器
        *参数2是被代理的对象的接口
        *参数3是代理对象
        *
        *返回的值就是成功被代理后的对象,返回的是Object类型,需要根据当时情况去转换类型
        */
        ITestDemo t = (ItestDemo)Proxy.newProxyInstance(handler.getClass().getClassLoader(),test.getClass().getInterfaces(),h);  

       t.test1();
       t.test2();     
    }
}


import java.lang. reflect. InvocationHandler;
import java.lang. reflect .Method;

//动态代理类
public class ProxyDemo implements InvocationHandler {

    object obj;//被代理的对象

    public ProxyDemo() {
        this.obj = obj;
    }


    @Override
    public object invoke (Object proxy, Method method, Object[] args)
        throws Throwable {
            System.out.println(method.getName() + "方法开始执行");
            Object result = method.invoke(this.obj,args);//执行的是指定代理对象的指定方法 
            System.out.println("method.getName()" + "方法执行完毕");
            teturn result;
    
        }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值