Java-反射基础

Java-反射基础

一、概念:

  • 将类的各个组成部分(变量、方法、构造器)封装为对象(即:Class、Constructor、Field、Method对象)
  • 在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
  • 对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

优点:

  1. 可以在程序运行过程中,操作这些对象。
  2. 可以解耦,提高程序的可扩展性。

缺点:效率较低


二、4个反射相关对象

1)Class对象

在程序运行期间,Java运行时系统始终为所有的对象维护一个称为运行时的类型标识,该信息跟踪着每个对象所属的类,虚拟机利用运行时类型信息选择相应的方法执行。保存这些信息的类称为Class

//获取Class对象
1. Class.forName("全类名"):将字节码文件加载进内存,返回Class对象
		* 多用于配置文件,将类名定义在配置文件中。读取文件,加载类
	2. 类名.class:通过类名的属性class获取
		* 多用于参数的传递
	3. 对象.getClass()getClass()方法在Object类中定义着。
		* 多用于对象的获取字节码的方式

	* 结论:
		同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。

Class对象功能

* 获取功能:
		1. 获取成员变量们
			* Field[] getFields() :获取所有public修饰的成员变量
			* Field getField(String name)   获取指定名称的 public修饰的成员变量

			* Field[] getDeclaredFields()  获取所有的成员变量,不考虑修饰符
			* Field getDeclaredField(String name)   同上,获取指定名称的域
			
		2. 获取构造方法们
			* Constructor<?>[] getConstructors()  
			* Constructor<T> getConstructor(Class<?>... parameterTypes)  

			* Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)  
			* Constructor<?>[] getDeclaredConstructors()  
    
		3. 获取成员方法们:
		  	* 获取从父类得到的public方法,以及自己的public方法[不包括default,private
				* Method[] getMethods()  
				* Method getMethod(String name, Class<?>... parameterTypes)  
    
		  	* 获取声明的所有方法[private , public ,default
				* Method[] getDeclaredMethods()  
				* Method getDeclaredMethod(String name, Class<?>... parameterTypes)  
    
    	  	* 参数类型:
    	  		第一个:方法的名称
    	  		第二个:参数类型的Class对象

		4. 获取全类名	
			* String getName()  

方法演示:

package pers.xu.others;

import java.lang.reflect.Field;
import java.lang.reflect.Method;


/**
 * @author a_apple
 * @create 2020-05-19 8:59
 */
class Person {
    int parentDefaultAge = 12;
    public String parentPubName = "123";
    private String parentPrivate = "no";


    public void showParentPublic() {
        System.out.println("public method --parent");
    }

    private void showParentPrivate() {
        System.out.println("private method --parent");
    }

    void showParentDefault() {
        System.out.println("default method --parent");
    }
}

class Student extends Person {
    int stuDefaultId = 1232;
    public String stuPublicName = "TomStu";
    private String stuPrivateName = "haha";

    void showStuDefault() {
        System.out.println("I am student");
    }

    public void showStuPublic() {
        System.out.println("pub");
    }

    private void showStuPrivate() {
        System.out.println("pri");
    }
}


public class TestClass {


    public static void main(String[] args) {

        Student stu = new Student();
        Class<? extends Student> stuClass = stu.getClass();

        System.out.println("------------------------getMethods()");
        // getMethods():获取从父类得到的public方法,以及自己的public方法[不包括default,private

        for (Method method : stuClass.getMethods()) {
            System.out.println("method: " + method.getName());
        }

        System.out.println("-----------------------getDeclaredMethods()");
        // 获取自己的所有方法 default,public,private

        for (Method declaredMethod : stuClass.getDeclaredMethods()) {
            System.out.println("dm: " + declaredMethod.getName());
        }

        System.out.println("-----------------------getFields()");
        // 获取父类的public属性和自己的public属性
        for (Field field : stuClass.getFields()) {
            System.out.println("field: " + field.getName());
        }


        System.out.println("-------------------------getDeclaredFields()");
        // 获取自己的所有属性public,default,private
        for (Field field : stuClass.getDeclaredFields()) {
            System.out.println("field: " + field.getName());
        }

    }
}


输出:

------------------------getMethods()
method: showStuPublic
method: showParentPublic
method: wait
method: wait
method: wait
method: equals
method: toString
method: hashCode
method: getClass
method: notify
method: notifyAll
-----------------------getDeclaredMethods()
dm: showStuDefault
dm: showStuPublic
dm: showStuPrivate
-----------------------getFields()
field: stuPublicName
field: parentPubName
-------------------------getDeclaredFields()
field: stuDefaultId
field: stuPublicName
field: stuPrivateName

Process finished with exit code 0


2)Field对象
* 操作:
		1. 设置值
			* void set(Object obj, Object value)  
    		* 参数类型:
    			第一个参数:被操作的对象
    			第二个参数:设定的值
		2. 获取值
			* get(Object obj) 	
    			
		3. 忽略访问权限修饰符的安全检查
			* setAccessible(true):暴力反射

3)Constructor对象
* 创建对象:
		* T newInstance(Object... initargs)  

		* 如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法
		3. 忽略访问权限修饰符的安全检查
			* setAccessible(true):暴力反射

4)Method对象
* 执行方法:
		* Object invoke(Object obj, Object... args)  
    *参数类型:
    	第一个:代表要调用这个方法的对象
    	第二个:该方法的参数

	* 获取方法名称:
		* String getName:获取方法名
		
	3. 忽略访问权限修饰符的安全检查
			* setAccessible(true):暴力反射	

三、反射用法举例

1)通过反射运行配置文件内容

不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法

提供2个类:
public class UserService1 {

    public void service1(){
        System.out.println("UserService1 的 service1方法...");
    }
}

public class UserService2 {
	
	//...
    public void service2(){
        System.out.println("UserService2 的 service2执行了...");
    }
}

配置文件:reflection.properties

# 类名需要提供完整的包名路径
className = com.test.UserService2
methodName = service2

测试:

package com.fanshe;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * @author a_apple
 * @create 2019-10-20 9:39
 */
public class ReflectDemo {

    public static void main(String[] args) throws Exception{
        //1.读取reflection.properties文件
        Properties pro = new Properties();
        InputStream stream = ReflectDemo.class.getClassLoader().getResourceAsStream("reflection.properties");
        pro.load(stream);

        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");

        //2.通过反射创建对象
        Class<?> class1 = Class.forName(className);
        Object instance = class1.newInstance();
        System.out.println(instance);

        //3.获取方法执行---提供的是无参方法
        Method method = class1.getMethod(methodName);
        method.invoke(instance);
    }
}

输出:

com.test.UserService2@29453f44
UserService2 的 service2执行了...

2)反射略过泛型检查

ArrayList<Integer>集合里添加一个String类型的值

因为:泛型检测是在编译期进行的,而反射是在运行时候进行的,对.class文件进行操作

public class GenericIgnore {
    public static void main(String[] args) throws Exception {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);

        //list.add("hello"); //这个是会报编译错的

        //但是下面可以让list添加String类型
        Class<?> listClass = list.getClass();

        Method addMethod = listClass.getMethod("add", Object.class); //传一个Object,此时可以加Integer,String...
        addMethod.invoke(list, "字符串");

        System.out.println(list);
    }
}

输出:

[2, 4, 1, 字符串]

3)JBDC加载Mysql驱动
public class JdbcDemo {
    public static void main(String[] args) {
        //初始化驱动
        try {
            //驱动类com.mysql.jdbc.Driver
            //就在 mysql-connector-java-5.0.8-bin.jar中
            //如果忘记了第一个步骤的导包,就会抛出ClassNotFoundException
            Class.forName("com.mysql.jdbc.Driver");
            System.out.println("数据库驱动加载成功 !");
            
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

部分引用其他博主,侵删

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值