java反射

java反射机制可以完成:

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

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

3.在运行时得到任意一个类所具有的成员变量和方法

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

5.生成动态代理

package ll;

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class example
{
    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        //根据配置文件re.properties指定信息,创建Cat对象并调用方法hi
        //1.使用Properties类可以读写配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String classfullpath = properties.get("classfullpath").toString();
        String method = properties.get("method").toString();
        System.out.println(classfullpath);
        System.out.println(method);


        //使用反射机制解决
        //(1)加载类,返回一个Class类型的对象
        Class cls = Class.forName(classfullpath);
        //(2)通过cls得到加载的类的对象实例
        Object o = cls.newInstance();
        System.out.println(o.getClass());
        //(3)通过cls得到你加载的类的method方法
        //即:在反射机制中,可以把方法视为对象(万物皆对象)
        Method method1 = cls.getMethod(method);
        //(4)通过method1调用方法:即通过方法对象来1调用方法
        method1.invoke(o);
    }
}
package ll;

public class Cat {
    private String name="tom";
    public void hi(){
        System.out.println("hi"+name);
    }
}


//配置文件src:\\re.properties

classfullpath=ll.Cat
method=hi

//这样的需求在学习框架时特别多,即通过外部文件配置,在不修改源码情况下来控制程序,

也符合设计模式的ocp原则(开闭原则:不修改源码,扩容功能)

一、反射机制

        1.反射允许程序在执行时借助于Reflection API获取任何类的内部信息(成员方法、构造器、成员变量等),并能操作对象的属性和方法,反射机制在操作模式和框架底层都有广泛应用。

        2.加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整的结构信息。通过这个对象得到类的结构,这个对象就像一面镜子,透过这个镜子看到类的结构,形象的称为反射。

package ll;

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class example
{
    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //根据配置文件re.properties指定信息,创建Cat对象并调用方法hi
        //1.使用Properties类可以读写配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String classfullpath = properties.get("classfullpath").toString();
        String method = properties.get("method").toString();
        System.out.println(classfullpath);
        System.out.println(method);


        //使用反射机制解决
        //(1)加载类,返回一个Class类型的对象
        Class cls = Class.forName(classfullpath);
        //(2)通过cls得到加载的类的对象实例
        Object o = cls.newInstance();
        System.out.println(o.getClass());
        //(3)通过cls得到你加载的类的method方法
        //即:在反射机制中,可以把方法视为对象(万物皆对象)
        Method method1 = cls.getMethod(method);
        //(4)通过method1调用方法:即通过方法对象来1调用方法
        method1.invoke(o);
        //得到name字段
        //getField不能得到私有属性
        Field nameField = cls.getField("age");
        System.out.println(nameField.get(o));
        //Constructor
        Constructor constructor = cls.getConstructor();//()中可以指定构造器参数类型,返回无参构造器
        System.out.println(constructor);
        Constructor constructor2 =cls.getConstructor(String.class);//传入的String.class就是String类的Class对象
        System.out.println(constructor2);
    }
}

        3.反射的优点和缺点:

        1)优点:可以动态的创建和使用对象(也是底层框架的核心),没有反射机制,框架底层就失去技术支撑。

        2)缺点:使用反射基本是解释执行,对执行速度有影响。

        反射调用优化,关闭访问检查

        1)Method和Field、Constructor对象都有setAccessible()方法

        2)setAccessible()的作用是启动和禁用安全访问检查开关

        3)参数值为true表示反射的对象在使用时取消访问检查,提高反射的效率。参数值为false则表示反射的对象进行访问检查。

二、Class类

        1.基本介绍

        1)Class也是类,即继承Object类。

        2)Class对象不是new出来的,而是系统创建的。

        3)对于某个类的对象,在内存中只有一个,因为类只加载一次。

        4)Class对象是存放在堆的。

        5)每个类的实例都会记得自己是由哪个Class实例所生成。

        6)类的字节码二进制数据是存放在方法区的,有的地方称为类的元数据。

String str="com.Cat";
//获取到Class类对象,表示不确定的java类型
Class<?> clazz=Class.forName(str);
System.out.println(clazz);//显示该clazz对象是哪个类的class对象
Object o=clazz.newInstance();//通过反射创建对象
Field field=clazz.getField("name");//通过反射获取属性
field(obj,"tom");//通过字段对象赋值

        2.获取Class类对象

        1)前提:已知一个类的全类名,且该类在类路径下,可通过class类静态方法forName()获取,可能抛出ClassNotFoundException,实例:Class cls1=Class.forName("java.lang.Cat");

应用场景:多用于配置文件,读取类全路径,加载类。

        2)前提:若已知具体的类,通过类的Class获取,该方式最为安全可靠,程序性能最高,实例:Class cls2=Cat.class;

应用场景:多用于参数传递,比如通过反射得到对应的构造器对象。

        3)前提:已知某个类的实例,通过该实例的getClass()方法获取Class对象。实例:Class calzz=对象.getClass();

应用场景:通过创建好的的对象,获取Class对象。

        4)其他方式

        ClassLoader cl=对象.getClassLoader();

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

        5)基本数据类型按如下方式的到Class对象:

       Class cls=基本数据类型.class;

        6)基本数据类型对应的包装类,可以通过TYPE得到Class类对象

        Class cls=包装类.TYPE;

        如下类型有Class对象

1.外部类,成员内部类,静态内部类,局部内部类,匿名内部类

2.interface:接口

3.数组

4.enum

5.annotation:注解

6.基本数据类型

7.void

 三、类加载

        1.基本说明

        反射机制是java实现动态语言的关键,也就是通过反射实现类动态的加载。

        1)静态加载:编译时加载相关的类,如果没有则报错,依赖性强。

        2)动态加载:运行时加载需要的类,如果运行时不需要该类,则不报错,降低了依赖性。

        2.类加载时机

        1)当创建对象时,new//静态加载

        2)当子类加载时,父类也被加载

        3)调用类中的静态成员时

        4)通过反射//动态加载

        3.类加载各阶段完成的任务

        1)加载:将类的class文件读入内存,并为之创建一个java.lang.Class对象,这个过程由类的加载器完成。

        2)链接:将类的二进制数据合并的到jre中。

        3)初始化:jvm负责对类进行初始化,这里主要是指静态成员。

        4.链接阶段解析:

        1)虚拟机将常量池的符号引用替换为直接引用的过程。

        2)初始化

  • 到初始化阶段才真正开始执行类中定义的java程序代码,此阶段是执行<clinit>()方法的过程
  • <clinit>()语句是由编译器按语句在源文件中出现的顺序,依次自动收集类中所有静态变量的赋值动作和静态代码块中的语句,并进行合并。
  • 虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确的加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的<clinit>()方法,其他线程都需要阻塞等待,直到活动线程执行完毕。

java.lang.reflect.Field类

1.getModifiers:以int形式返回修饰符

默认修饰符是0,public是1,private是2,protected是4,static是8,final是16

2.getType:以Class形式返回类型

3.getName:返回属性名

java.lang.reflect.Method类

1.getModifiers:以int形式返回修饰符

默认修饰符是0,public是1,private是2,protected是4,static是8,final是16

2.getReturnType:以Class形式获取返回类型

3.getName:返回方法名

 通过反射创建对象:

1.方式一:调用类中的public修饰的无参构造器

2.方式二:调用类中的指定构造器

3Class类相关方法

        newInstance:调用类中的无参构造器,获取对应类的对象

        getConstructor(Class...clazz):根据参数列表,获取对应的构造器对象

        getDecalaredConstructor(Clazz..clazz):根据参数列表,获取对应的构造器对象

 4.Constructor类相关方法

        setAccessible:暴破

        newInstance(Object...obj):调用构造器

 

package hhh;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ReflecCreateInstance {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        //1.先获取到User类的Class对象
        Class<?> userClass = Class.forName("hhh.User");
        //2.通过public的无参构造器创建实例
        Object o = userClass.newInstance();
        System.out.println(o);
        //3.通过public的有参构造器创建实例
        //3.1先得到对应构造器
        Constructor<?> constructor = userClass.getConstructor(String.class);
        //3.2创建实例,并传入实参
        Object hsp = constructor.newInstance("hsp");
        System.out.println("hsp"+hsp);
        //4.通过非public的无参构造器创建实例
        Constructor<?> constructor1 = userClass.getDeclaredConstructor(int.class, String.class);
        constructor1.setAccessible(true);//暴破,使用反射可以访问private构造器
        Object user2 = constructor1.newInstance(100, "张");
    }
}
class User{
    private int age=12;
    private String name="jjj";
    public User(){
    }
    public User(String name){
        this.name=name;
    }
    private User(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

访问属性:

1.根据属性名获取Field对象

Field f=clazz对象.getDeclaredField(属性名);

2.暴破:f.setAccessible(true);

3.访问

f.set(o值);

syso(f.get(o));

4.如果是静态属性,则set和get中的参数o可以写成null

import java.lang.reflect.Field;

//演示反射操作属性
public class ReflecAccessProperty {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        //1.得到Student类对应的Class对象
        Class<?> stuClass = Class.forName("hhh.Student");
        //2.创建对象
        Object o = stuClass.newInstance();//o的运行类型就是Student
        System.out.println(o.getClass());//Student
        //3.使用反射得到age属性对象
        Field age = stuClass.getField("age");
        age.set(o,88);//通过反射来操作属性
        System.out.println(age.get(o));//返回age属性的值
        //4.使用反射操作name属性
        Field name = stuClass.getDeclaredField("name");
        //对name进行暴破,可以操作private属性
        name.setAccessible(true);
        name.set(o,"啦");//将o写成null也可以,因为静态属性属于所有对象
        System.out.println(o);
        System.out.println(name.get(o));
        System.out.println(name.get(null));//获取属性值,要求name是静态的
    }
}
class Student{
    public int age;
    private static String name;

    public Student() {
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +"name="+name+
                '}';
    }
}

访问方法

  1. 根据方法名和参数列表获取Method方法对象:Method m=clazz.getDeclaredMethod(方法名,XX.class);
  2. 获取对象:Object o=clazz.newInstance();
  3. 暴破:m.setAccessible(true);
  4. 访问:Object returnValue=m.invoke(o,实参列表);
  5. 注意:如果是静态方法,则invoke的参数o,可以写成null
  • 34
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值