java反射机制

java反射机制

1.反射机制的作用:

反射机制的作用:
1.反编译:
.class --> .java
2.通过反射机制访问java对象的属性、方法、构造方法等。

2.SUN公司提供的反射机制中的类:

java.lang.Class;
java.lang.reflect.Constructor;
java.lang.reflect.Filed;
java.lang.reflect.Method;
java.lang.reflect.Modifier; 修饰符

3.关于java中的可变长参数

package com.company.test;
/*
    关于java中可变长参数:
 */
import java.util.Date;
import java.util.LinkedList;
public class Test02 {
    // m1方法中有一个int类型可变长参数
    // m1方法在调用的时候,传递的实参可以是 0-N 个。
    public static void m1(int... a){
        System.out.println("Test");
    }

    // 注意:有精确匹配的,会优先调用精确匹配的方法
    public static void m1(int i){
        System.out.println(i);
    }

    // 可变长参数可以等同看做数组
    public static void m2(String... args){
        for(int i=0; i<args.length; i++){
            System.out.println(args[i]);
        }
    }

    public static void m3(Class... args) throws Exception{
        for(int i=0; i<args.length; i++){
            Class c = args[i];
            System.out.println(c.getDeclaredConstructor().newInstance());
        }
    }

    // 可变长参数只能出现一次,并且只能出现在所有形式参数的最后一位
    public static void m4(int a, String... b){}
    public static void main(String[] args) throws Exception{
        m1();
        m1(1);  // 1
        m1(1,2);
        m1(1,2,3,4,5);

        m2("唱","跳","rap","篮球");
        //实际上往m2中传入数组也是可以的
        String[] a = {"唱","跳","rap","篮球"};
        m2(a);

        m3(Date.class, LinkedList.class);
    }
}

4、获取class文件的三种方式:

package com.company.test;

import java.io.*;
import java.util.Date;

/*
    获取class文件的三种方式:

*/
public class ReflectTest01{
    public static void main(String[] args) throws Exception{

        // 第一种方式:
        Class c1 = Class.forName("Employee.class");

        // 第二种方式:
        // Java中每个类型都有 class 属性
        Class c2 = Employee.class;

        // 第三种方式:
        // java.lang.Object 中有getClass()方法,所以任何一个对象都有该方法
        Employee em = new Employee();
        Class c3 = em.getClass();  // c3是运行时类(em的运行时类是Employee)

        // 因为Employee这个类在JVM中只有一个,所以c1、c2、c3的内存地址是相同的,指向堆中唯一对象。
        System.out.println(c1==c2); // true
        System.out.println(c2==c3); // true

        // 例子
        // c4 c5 c6都代表Date这个类
        Class c4 = Date.class;  // c4代表 Date类,只不过这个类是SUN提供的

        Class c5 = Class.forName("java.util.Date"); // 必须写类全名,类全名带有包名。

        Date d = new Date();
        Class c6 = d.getClass();

        // c7代表int类型
        Class c7 = int.class;

        // 总结:上面c1 c2 c3就是表示Employee类型,c4 c5 c6表示Date类型,c7表示int类型
    }
}

案例1:

package com.company.test;

public class ReflectTest02 {
    public static void main(String[] args) throws Exception{
        // 将A.class文件装载到JVM中的过程
        //Class.forName("A");  //会执行A中的静态语句块

        // 下面这句不会执行静态语句块
        Class c = A.class;
    }
}

class A{
    static{
        System.out.println("A......");
    }
}

案例2:

package com.company.test;
import java.lang.Class;
import java.text.SimpleDateFormat;
import java.util.Date;

/*
    获取Class类型的对象之后,可以创建该“类”的对象
*/
public class ReflectTest03 {
    public static void main(String[] args) throws Exception{
        Class c = Class.forName("java.util.Date");

        // 创建此Class对象所表示的类的一个新实例
        Object o = c.newInstance();  // 调用Date的无参数构造方法
        // Java9以后采用下面这种方法
        Object o2 = c.getDeclaredConstructor().newInstance();

        System.out.println(o);
        System.out.println(o2);

        if(o instanceof Date){
            Date t = (Date)o;
            System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(t));
        }
    }
}

5、IO + Properties联合应用

1、dbinfo这样的文件,我们称之为配置文件,配置文件的作用:使程序更加灵活

注意:一般在程序中可变的东西不要写死,推荐写在配置文件中
运行同样的程序,得到不同的结果

像dbinfo这样一个具有特殊内容的配置文件,我们又叫做:属性文件
java规范中要求属性文件以“.properties”结束

属性文建中数据要求:
key和value之间可以使用“空格”、“冒号"、”等号“
如果“空格”、“冒号”、“等号”都有,按照最前面的一个符号作为分隔符
如果有中文,需要转成Unicode码

driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@192.168.1.100:1521:company
username=scott
password=123456

案例:

import java.io.*;
import java.util.*;
public class Test03 {
    public static void main(String[] args) throws Exception{
        // 1.创建属性对象
        Properties p = new Properties();   // 和Map一样,只不过key和value只能存储字符串类型
                                           // key不能重复,如果key重复则value覆盖
        // 2.创建输入流
        FileInputStream fis = new FileInputStream("E:\\mydemo\\IDEA\\test\\day01\\dbinfo.properties");

        // 3.将fis流中所有的数据加载到属性对象中
        p.load(fis);  // 所以现在属性对象中有(key=username, value=scott)

        // 4.关闭流
         fis.close();

         // 通过key获取value
        String v1 = p.getProperty("driver");
        String v2 = p.getProperty("url");
        String v3 = p.getProperty("username");
        String v4 = p.getProperty("password");

        System.out.println(v1);
        System.out.println(v2);
        System.out.println(v3);
        System.out.println(v4);


    }
}

2、反射机制 + IO + properties联合应用,动态创建java对象

可以修改配置文件中的className,不需要再重新编译程序,直接运行class文件就可以了

反射机制的作用:
能够创建灵活的代码,这些代码可以在运行时装配,无需组件之间源代码链接,降低耦合度。
反射允许我们在编写与执行时,使我们的程序代码能够装载到JVM中的内部信息,而不是
源代码中选定的类协作的代码。

注意:如果使用不当,反射成本很高。
案例2:

className=java.util.Date
package com.company.test;

import java.io.FileReader;
import java.util.Properties;

public class Test04 {
    public static void main(String[] args) throws Exception{

        // 1.创建属性对象
        Properties p = new Properties();

        // 2.创建流
        FileReader fr = new FileReader("E:\\mydemo\\IDEA\\test\\day01\\classInfo.properties");

        // 3.加载
        p.load(fr);

        // 4.关闭流
        fr.close();

        // 通过key获取value
        String className = p.getProperty("className");

        System.out.println(className);

        // 通过反射机制创建对象
        Class c = Class.forName(className);

        // 创建对象
        Object o = c.getDeclaredConstructor().newInstance();
        System.out.println(o);
    }
}

6、java.lang.reflect.Field; 类中的属性

package com.company.test;
/*
    java.lang.reflect.Field; 类中的属性
 */
/*
public class User {
    private String id;
    public int age;
    protected String addr;
    boolean sex;
}
 */
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;



public class Test05 {
    public static void main(String[] args) throws Exception{

        // 获取整个类
        Class c = Class.forName("User.class");

        // 获取属性Field
        // getField()获取单个,并且括号里面需要传入属性名
        // getFields()只是获取所有public修饰的属性
        Field[] fs = c.getFields();
        System.out.println(fs.length);  // 1
        System.out.println(fs[0].getName());  // age

        // 获取所有属性
        Field[] fss = c.getDeclaredFields();
        for(Field field:fs){
            System.out.println(field.getName());

            // 获取属性类型
            Class type = field.getType();
            // getName()和getSimpleName()区别在于返回 int和java.lang.int
            System.out.println(type.getName());
            System.out.println(type.getSimpleName());

            // 获取属性修饰符
            // int getModifiers();  返回是int类型
            // 0表示默认 1表示public 2表示private 4表示protected
            int i = field.getModifiers();
            System.out.println(i);

            // 而java.lang.reflect.Modifier();中有一个static String toString(int mod)转换为字符串
            String str = Modifier.toString(i);
            System.out.println(str);
        }



        // 练习:将User类按照下面输出
        /*
        public class User {
            private String id;
            public int age;
            protected String addr;
            boolean sex;
        }
         */

        StringBuffer sb = new StringBuffer();
        sb.append(Modifier.toString(c.getModifiers()) + "class" + c.getSimpleName() + "{" + "\n");
        for(Field field:fss){
            sb.append("\t");
            sb.append(Modifier.toString(field.getModifiers()) + " ");
            sb.append(field.getType().getSimpleName() + " ");
            sb.append(field.getName() + ";" + "\n");
        }
    }
}

获取某个指定的类:

package com.company.test;

import java.lang.reflect.Field;

/*
    java.reflect.Field;

    获取某个指定的属性
 */
public class Test06 {
    public static void main(String[] args) throws Exception{
        //以前的方式:
        /*
        User u = new User();
        u.id = 12;  // set
        System.out.println(u.age);  // get
        */

        Class c = Class.forName("User.class");

        // 获取指定属性
        Field ageF = c.getDeclaredField("age");

        // 获取到某个指定属性之后可以用来? set & get
        // 首先需要创建对象
        Object o = c.getDeclaredConstructor().newInstance();

        // 给o对象的age属性赋值12
        ageF.set(o, 12);

        // get
        System.out.println(ageF.get(o));


        // 但是如果是private String id;私有属性,能不能访问?
        // 打破封装
        // java.lang.reflect.Field; 继承于 java.lang.reflect.AccessibleObject;
        // java.lang.reflect.AccessibleObject里面有一个方法 setAccessible

        Field idF = c.getDeclaredField("id");

        // 打破封装
        idF.setAccessible(true); // 使用反射机制可以打破封装性,导致java对象的属性不安全
        idF.set(o, "110");
        System.out.println(idF.get(o));
    }
}

7、java.lang.reflect.Method;类中的方法

package com.company.test;
/*
    java.lang.reflect.Method;
 */

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/*
public class CustomerService{
    public boolean login(String name, String pwd){
        if("admin".equals(name) && "123".equals(pwd)){
            return true;
        }
        return false;
    }

    public void logout(){
        System.out.printlm("系统安全退出");
    }
}

 */
public class Test07 {
    public static void main(String[] args) throws Exception{

        // 获取类
        Class c = Class.forName("CustomerService");

        // 获取方法
        Method[] ms = c.getMethods();

        for(Method m:ms){
            // 方法名
            System.out.println(m.getName());

            // 方法返回值类型
            Class returnType = m.getReturnType();
            System.out.println(returnType.getSimpleName());

            // 方法修饰符
            System.out.println(Modifier.toString(m.getModifiers()));

            // 方法形式参数列表
            Class[] parameterTypes = m.getParameterTypes();
            for(Class parameterType:parameterTypes){
                System.out.println(parameterType.getSimpleName());
            }
        }



        // 反编译下面代码
        /*
        public class CustomerService{
            public boolean login(String name, String pwd){
                if("admin".equals(name) && "123".equals(pwd)){
                    return true;
                }
                return false;
            }

            public void logout(){
                System.out.printlm("系统安全退出");
            }
        }

         */

        StringBuffer sb = new StringBuffer();
        sb.append(Modifier.toString(c.getModifiers()) + " class ");
        sb.append(c.getSimpleName() + "{\n");
        for(Method m:ms){
            sb.append("\t");
            sb.append(Modifier.toString(m.getModifiers()) + " ");
            sb.append(m.getReturnType().getSimpleName() + " ");
            sb.append(m.getName() + "(");

            // 形参
            Class[] parameterTypes = m.getParameterTypes();
            for(int i=0; i<parameterTypes.length; i++){
                Class parameterType = parameterTypes[i];
                if(i == parameterTypes.length -1){
                    sb.append(parameterType.getSimpleName());
                }else{
                    sb.append(parameterType.getSimpleName() + ",");
                }
            }
            sb.append("){}\n");
        }
        sb.append("}");

        System.out.println(sb);
    }
}

获取某个特定的方法,通过反射机制执行:

package com.company.test;

import java.lang.reflect.Method;

/*
    获取某个特定的方法,通过反射机制执行

    以前是:
    CustomerService cs = new CustomerService();
    cs.login("admin", "123");

    通过反射机制呢?
 */
public class Test08 {
    public static void main(String[] args) throws Exception{

        // 1.获取类
        Class c = Class.forName("Customer.class");

        // 获取某个特定的方法
        // 由于重载机制的存在,仅一个方法名并不能区分不同方法
        // 通过:方法名 + 形参列表
        Method m = c.getDeclaredMethod("login", String.class, String.class);

        // 通过反射机制执行login方法
        Object o = c.getDeclaredConstructor().newInstance();

        // java.lang.reflect.Method; 中有一个方法 Object invoke(Object obj, Object... args);
        // 调用o对象的m方法,传入"admin" "123"参数,方法的执行结果是returnValue
        Object returnValue = m.invoke(o,"admin","123");

        System.out.println(returnValue);

    }
}

8、java.lang.reflect.Constructor;获取构造方法 & java.lang.reflect.Modifier;获取修饰符

package com.company.test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

/*
    获取构造方法
 */
public class Test09 {
    public static void main(String[] args) throws Exception{

        // 1.获取类
        Class c = Class.forName("java.lang.String");

        // 2.获取所有的构造
        Constructor[] cs = c.getDeclaredConstructors();

        for(Constructor con:cs){

            // 获取修饰符
            System.out.println(Modifier.toString(con.getModifiers()));

            // 获取构造方法名
            System.out.println(con.getName());
            // 或者
            System.out.println(c.getSimpleName());

            // 获取构造方法的形式参数列表
            Class[] parameterTypes = con.getParameterTypes();
            for(Class parameterType:parameterTypes){
                System.out.println(parameterType.getSimpleName());
            }
        }

    }
}

获取某个特定的构造方法,然后创建对象

package com.company.test;

import java.lang.reflect.Constructor;

/*
    获取某个特定的构造方法,然后创建对象
 */
public class Test10 {
    public static void main(String[] args) throws Exception{

        // 1.获取类
        Class c = Class.forName("Customer.class");

        // 2.获取特定的构造方法
        Constructor con = c.getDeclaredConstructor(String.class, int.class);

        // 3.创建对象
        Object o = con.newInstance("张三", 23);

        System.out.println(o);
    }
}

class Customer{
    String name;
    int age;

    Customer(String name, int age){
        this.name = name;
        this.age = age;
    }

    public String toString(){
        return "Customer[" + name + "," + age + "]";
    }
}

9、关于类获取父类和父接口

package com.company.test;
/*
    关于类获取父类和父接口
 */
public class Test11 {

    // 通过反射机制获取String类的父类和父接口
    public static void main(String[] args) throws Exception{
        Class c = Class.forName("java.lang.String");

        // 获取父类
        Class superClass = c.getSuperclass();

        System.out.println(superClass.getName());

        // 获取父接口
        Class[] ins = c.getInterfaces();
        for(Class in:ins){
            System.out.println(in.getName());
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值