java反射机制

1、反射机制
    1.1、反射机制有什么用?
        通过java语言中的反射机制可以操作字节码文件。
        有点类似于黑客。(可以读和修改字节码文件。)
        通过反射机制可以操作代码片段。(class文件。)

    1.2、反射机制的相关类在那个包下?
        java.lang.reflect.*;

    1.3、反射机制相关的类有哪些?
        java.lang.Class                 代表字节码文件

        java.lang.reflect.Method        代表字节码中的方法字节码

        java.lang.reflect.Constructor   代表字节码中的构造方法字节码

        java.lang.reflect.Field         代表字节码中的属性字节码

        java.lang.Class:
            public class User{
                //Field
                int no;

                //Constructor
                public User(){
                }

                public User(int no){
                    this.no=no;
                }

                //Method
                public void setNo(int no){
                    this.no=no;
                }

                public int getNo(){
                    return no;
                }
            }

2、关于JDK中自带的类加载器:
    2.1、什么是类加载器?
        专门负责加载类的命令/工具。
        ClassLoader

    2.2、JDK中自带了三个类加载器
        启动类加载器
        扩展类加载器
        应用类加载器

    2.3、假设有一段代码
        String s="abc" ;

       代码在开始执行之前,会将所有的类全部加载到JVM当中。
       通过类加载器加载,看到以上代码类加载器会找String.class
       文件,找到就加载,那么是怎么进行加载的呢?

        首先通过“启动类加载器”加载
            注意:启动类加载器专门加载:E:\java tools\JDK8\jdk1.8.0_101\jre\lib\rt.jar
            rt.jar中都是JDK最核心的类库。

        如果通过“启动类加载器”加载不到的时候。
        会通过“扩展类加载器”加载。
        注意:扩展类加载器专门加载:E:\java tools\JDK8\jdk1.8.0_101\jre\lib\ext\*.jar

        如果通过“扩展类加载器”没有加载到的时候
        会通过“应用类加载器”加载。
        注意:应用类加载器专门加载:classpath中的类。

    2.4、java为了保证类加载的安全,使用了双亲委派机制。
        优先从启动类加载器中加载,这个称为“父”
        “父”无法加载的时候,再从扩展类加载器中
        加载,这个称为“母”。双亲委派。如果都加载
        不到,才会考虑从应用类加载器中加载,直到加载
        到为止。

 

 

要操作一个类的字节码,需要首先获取到这个类的字节码,怎么获取java.lang.Class实例?
    三种方式:
        第一种:Class c=Class.forName("完整的类名带包名");
        第二种:Class c=引用.getClass();
        第三种:Class c=任何类型.class属性

 

Class.forName()
    1、静态方法
    2、方法参数是一个字符串
    3、字符串需要的是一个完整类名
    4、完整类名必须带有包名。

c1=Class.forName("java.lang.String");     //c1代表String.Class文件,或者说c1代表String类

java中任何一个对象都有一个方法:getClass();

String s="abc";
Class x=s.getClass();

java语言中任何一种类型,包括基本数据类型,都有.Class属性。

Class z= String.class;

 

获取到Class,能干什么?
    通过Class的newInstance()方法来实例化对象。
    注意:newInstance()方法内部实际上调用了无参数构造方法,必须保证无参数构造存在才可以。

通过反射机制获取Class,通过Class来实例化对象

Class c=Class.forName("home.mjjhy.java.bean.User");

//重点是:newInstance()调用的是无参构造,必须保证无参构造是存在的。
Object obj=c.newInstance();//home.mjjhy.java.bean.User@6bdf28bb

验证反射机制的灵活性:
    Java代码写一遍,在不改变java源代码的基础之上,可以做到不同对象的实例化。
    非常灵活。(符合OCP开闭原则:对扩展开放,对修改关闭)

后期要学习高级框架,而工作过程中,也都是使用高级框架。
包括:
    ssh ssm
    Spring SpringMVC MyBatis
    Spring Struts Hibernate
这些高级框架底层实现原理:都采用了反射机制。所以反射机制还是重要的。
学会了反射机制有利于理解剖析框架底层源代码。

FileReader reader=new FileReader("chapter31\\classinfo.properties");

Properties pro=new Properties();

pro.load(reader);

reader.close();

//通过key获取value
String className=pro.getProperty("className");
//System.out.println(ClassName);

//通过反射机制实例化对象
Class c=Class.forName(className);
Object obj=c.newInstance();
System.out.println(obj);

classinfo.properties文件

className=java.util.Date

 

研究:Class.forName()发生了什么?
    重点:
        如果你只希望一个类的静态代码块执行,其他代码一律不执行,
        可以使用:
            Class.forName("完整类名");
        这个方法执行会导致类加载,类加载时,静态代码块执行。

提示:
    后面JDBC技术的时候还需要。

 

反射Student类当中的field

辅助类

 

public class Student {
    //Field翻译为字段,其实就是属性/成员
    public String name;
    private int no;
    protected int age;
    boolean sex;
    public final static double MATH_PI=3.1415926;

    public Student(){
        System.out.println("无参构造已经执行");
    }

    public Student(String name,int no,int age,boolean sex){
        this.name=name;
        this.no=no;
        this.age=age;
        this.sex=sex;
    }
}

 

Class studentClass =Class.forName("home.mjjhy.java.bean.Student");

Field[] fields=studentClass.getDeclaredFields();

//获取完整的类名
String studentClassName=studentClass.getName();
System.out.println("完整类名"+studentClassName);

//获取简类名
String studentClassSimpleName=studentClass.getSimpleName();
System.out.println("简类名"+studentClassSimpleName);

for(Field field:fields){
    //获取所有属性的修饰符列表
    int modifiers=field.getModifiers();
    String modifiersName=Modifier.toString(modifiers);
    //System.out.println(modifiersName);
    //获取所有属性的类型
    //filed.getType();
    Class fieldClass=field.getType();
    String fieldClassName=fieldClass.getSimpleName();
    //System.out.println(fieldClassName);

    String fieldName=field.getName();
    //System.out.println(fieldName);

    System.out.println(modifiersName+" "+fieldClassName+" "+fieldName);
}

通过反射机制,反编译一个类的属性Field

 

StringBuilder s=new StringBuilder();

//Class studentClass =Class.forName("home.mjjhy.java.bean.Student");
Class studentClass =Class.forName("java.lang.String");

s.append(Modifier.toString(studentClass.getModifiers())+" class "+studentClass.getSimpleName()+"{");

Field[] fields=studentClass.getDeclaredFields();

for (Field field:fields){
    s.append("\n");
    s.append("\t"+Modifier.toString(field.getModifiers())+" "+field.getType().getSimpleName()+" "+field.getName());

}
s.append("\n");
s.append("}");
System.out.println(s);

重点:
    怎么通过反射机制访问一个java对象的属性?
        给属性赋值set
        获取属性的值get

 

//使用反射机制,怎么访问一个对象的属性
    Class studentClass=Class.forName("home.mjjhy.java.bean.Student");

    //创建Student对象
    Object obj=studentClass.newInstance();

    //公开的属性
    Field nameField=studentClass.getDeclaredField("name");
    nameField.set(obj,"zhangsan");
    System.out.println(nameField.get(obj));

    //私有的属性
    Field noField=studentClass.getDeclaredField("no");

    //打破封装(反射机制的缺点:打破封装,可能会给不法分子留下就会!!!!)
    noField.setAccessible(true);
    noField.set(obj,1111);
    System.out.println(noField.get(obj));

反射Method

辅助类

/**
* 用户业务类
*/
public class UserService {
    /**
     *
     * @param name  用户名
     * @param password  密码
     * @return  true表示登录成功呢,false表示登录失败!!!
     */
    public boolean login(String name,String password){
        if("admin".equals(name)&&"123".equals(password))
            return true;
        else
            return false;
    }

    /**
     * 退出系统的方法
     */
    public void logout(){
        System.out.println("系统已经安全退出");
    }

}

 

Class UserClass=Class.forName("home.mjjhy.java.service.UserService");

Method[] methods=UserClass.getDeclaredMethods();

for(Method method:methods){
    //获得所有方法的修饰列表
    int i=method.getModifiers();
    String methodModifier=Modifier.toString(i);
    System.out.println(methodModifier);

    //获得所有方法类型
    String methodType=method.getReturnType().getSimpleName();
    System.out.println(methodType);

    //获得方法名
    String methodName=method.getName();
    System.out.println(methodName);

    //获取参数列表
    Class[]parameterTypes=method.getParameterTypes();
    for(Class parameterType:parameterTypes){
        System.out.println(parameterType.getSimpleName());
    }

反编译一个类

 

StringBuilder s=new StringBuilder();
//Class userClass=Class.forName("home.mjjhy.java.service.UserService");
Class userClass=Class.forName("java.lang.String");

s.append(Modifier.toString(userClass.getModifiers())+" class "+userClass.getSimpleName()+"{");
Method[] methods=userClass.getDeclaredMethods();

for(Method method:methods){
    s.append("\n");
    s.append("\t");
    s.append(Modifier.toString(method.getModifiers())+" "+method.getReturnType().getSimpleName()+" "+method.getName()+"(");

    Class[] methodParameterTypes=method.getParameterTypes();
    if (methodParameterTypes.length==0){
        s.append("){}");
    }else{
        for(Class parameterType:methodParameterTypes){
            s.append(parameterType.getSimpleName());
            s.append(",");
        }
        s.deleteCharAt(s.length()-1);
        s.append(")");
        s.append("{}");
    }

}

s.append("\n");
s.append("}");
System.out.println(s);

 

通过反射机制,调用一个对象的方法。

    反射机制,让代码具有通用性,可变化的内容都是写在配置文件当中,
    将来修改配置文件之后,创建对象不一样了,调用方法也不同了,但是
    java代码不需要改动。

 

//获取类
Class userServiceClass=Class.forName("home.mjjhy.java.service.UserService");

//创建对象
Object obj=userServiceClass.newInstance();

//获取Method
Method loginMethod=userServiceClass.getDeclaredMethod("login", String.class, String.class);

//调用方法
/*
要素分析:
    要素1:对象usrService
    要素2:login方法名
    要素3:实参列表
    要素4:返回值
*/
Object reValue=loginMethod.invoke(obj,"admin","123");
System.out.println(reValue);

反编译一个类的Constructor构造方法

辅助类

public class Vip {
    int no;
    public String name;
    String birth;
    boolean sex;

    public Vip(){
    }

    public Vip(int no){
        this.no=no;
    }

    public Vip(int no, String name) {
        this.no = no;
        this.name = name;
    }

    public Vip(int no, String name, String birth) {
        this.no = no;
        this.name = name;
        this.birth = birth;
    }

    public Vip(int no, String name, String birth, boolean sex) {
        this.no = no;
        this.name = name;
        this.birth = birth;
        this.sex = sex;
    }

StringBuilder s=new StringBuilder();

//获取vip类
//Class vipClass=Class.forName("home.mjjhy.java.bean.Vip");
Class vipClass=Class.forName("java.lang.String");

s.append(Modifier.toString(vipClass.getModifiers())+" class "+ vipClass.getSimpleName()+"{");

//获取构造方法
Constructor[] constructors =vipClass.getDeclaredConstructors();

for(Constructor constructor:constructors){
    s.append("\n\t");

    s.append(Modifier.toString(constructor.getModifiers())+"\t"+vipClass.getSimpleName()+" (");

    Class[] parameterTypes=constructor.getParameterTypes();
    if(parameterTypes.length==0){
        s.append(")");
    }else{
        for(Class parameterType:parameterTypes){
            s.append(parameterType.getSimpleName());
            s.append(",");
        }
        s.deleteCharAt(s.length()-1);
        s.append("){}");
    }
}
s.append("\n}");
System.out.println(s);

通过反射机制创建对象(使用有参构造方法)

 

Class vipClass=Class.forName("home.mjjhy.java.bean.Vip");

//调用无参数构造方法
vipClass.newInstance();

//调用有参构造
Constructor constructor=vipClass.getDeclaredConstructor(int.class,String.class,String.class,boolean.class);
Object obj=constructor.newInstance(110,"jackson","1990-10-11",true);
System.out.println(obj);

 

重点:给你一个类,怎么获取这个类的父类,已经实现了那些接口

 

public static void main(String[] args) throws Exception{
    //String举例
    Class stringClass=Class.forName("java.lang.String");

    //获取String类的父类
    Class superclass=stringClass.getSuperclass();
    System.out.println(superclass.getName());

    //获取String类的所有接口
    Class[] stringClassInterfaces=stringClass.getInterfaces();

    for(Class stringClassInterface:stringClassInterfaces){
        System.out.println(stringClassInterface.getName());
    }
}

/*
研究文件路径问题:
怎么获取一个文件的绝对路径。以下这种方式是通用的,但前提是:文件需要在类路径下。
*/
public class AboutPath {
    public static void main(String[] args) throws Exception {
        //这种方式的路径缺点是:移植性差,在IDEA中默认的当前路径是project的根。
        //这个代码假设离开了IDEA,换到其他位置,可能当前路径就不是project的根了。这时这个路径就无效了。
        //FileReader reader=new FileReader("chapter31\\classinfo.properties");

        //通用的一种路径,即使代码换位置,这样编写仍然是通用的。
        //使用以下通用方式的前提是:这个文件必须是类路径下的。
        //凡是在src下的,都是类路径下的。
        //src是类的根路径。

        /*
        解释:
            Thread.currentThread()      当前线程对象
            getContextClassLoader()     是线程对象的方法,可以获取当前线程的类加载对象
            getRResource()              【获取资源】这是类加载对象的方法,当前线程的类加载器默认从类的根路径下加载资源。
         */
        String path=Thread.currentThread().getContextClassLoader().
                    getResource("classinfo2.properties").getPath();//这种方式获取文件绝对路径通用的方法
        System.out.println(path);

        String path2=Thread.currentThread().getContextClassLoader().
                    getResource("home/mjjhy/java/bean/db.properties").getPath();
        System.out.println(path2);

    }
}

 

/*
java.util包下提供了一个资源绑定器,便于获取属性配置文件中的内容。
使用以下这种方式的时候,属性配置文件*****.properties必须放到类路径下。
*/
public class ResourceBundleTest {
    public static void main(String[] args) {

        //资源绑定器,只能绑定***.properties文件,并且文件必须在类路径下,文件扩展扩展名必须是properties
        //并且在写路径的时候,路径后面的扩展名不能写
        //ResourceBundle bundle= ResourceBundle.getBundle("classinfo2");

        ResourceBundle bundle= ResourceBundle.getBundle("home/mjjhy/java/bean/db");

        String className=bundle.getString("className");
        System.out.println(className);

    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值