什么是反射机制?了解java中的反射机制

2、反射机制(比较简单,因为只要会查帮助文档,就可以了。)

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

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

2.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;
			}
		}

3、关于JDK中自带的类加载器:(聊一聊,不需要掌握,知道当然最好!)
3.1、什么是类加载器?
专门负责加载类的命令/工具。
ClassLoader

3.2、JDK中自带了3个类加载器
	启动类加载器:rt.jar
	扩展类加载器:ext/*.jar
	应用类加载器:classpath

3.3、假设有这样一段代码:
	String s = "abc";
	
	代码在开始执行之前,会将所需要类全部加载到JVM当中。
	通过类加载器加载,看到以上代码类加载器会找String.class
	文件,找到就加载,那么是怎么进行加载的呢?

		首先通过“启动类加载器”加载。
			注意:启动类加载器专门加载:C:\Program Files\Java\jdk1.8.0_101\jre\lib\rt.jar
			rt.jar中都是JDK最核心的类库。
		
		如果通过“启动类加载器”加载不到的时候,
		会通过"扩展类加载器"加载。
			注意:扩展类加载器专门加载:C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext\*.jar


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

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

1、回顾反射机制

1.1、什么是反射机制?反射机制有什么用?
	反射机制:可以操作字节码文件
	作用:可以让程序更加灵活。

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

1.3、反射机制相关的主要的类?
	java.lang.Class
	java.lang.reflect.Method;
	java.lang.reflect.Constructor;
	java.lang.reflect.Field;

1.4、在java中获取Class的三种方式?
	第一种:	 
		Class c = Class.forName("完整类名");
	第二种:
		Class c = 对象.getClass();
	第三种:
		Class c = int.class;
		Class c = String.class;

1.5、获取了Class之后,可以调用无参数构造方法来实例化对象

	//c代表的就是日期Date类型
	Class c = Class.forName("java.util.Date");

	//实例化一个Date日期类型的对象
	Object obj = c.newInstance();

	一定要注意:
		newInstance()底层调用的是该类型的无参数构造方法。
		如果没有这个无参数构造方法会出现"实例化"异常。

1.6、如果你只想让一个类的“静态代码块”执行的话,你可以怎么做?
	Class.forName("该类的类名");
	这样类就加载,类加载的时候,静态代码块执行!!!!
	在这里,对该方法的返回值不感兴趣,主要是为了使用“类加载”这个动作。

1.7、关于路径问题?

	String path = Thread.currentThread().getContextClassLoader()
					  .getResource("写相对路径,但是这个相对路径从src出发开始找").getPath();	

	String path = Thread.currentThread().getContextClassLoader()
					  .getResource("abc").getPath();	//必须保证src下有abc文件。

	String path = Thread.currentThread().getContextClassLoader()
					  .getResource("a/db").getPath();	//必须保证src下有a目录,a目录下有db文件。
	
	String path = Thread.currentThread().getContextClassLoader()
					  .getResource("com/bjpowernode/test.properties").getPath();	
					  //必须保证src下有com目录,com目录下有bjpowernode目录。
					  //bjpowernode目录下有test.properties文件。

	这种方式是为了获取一个文件的绝对路径。(通用方式,不会受到环境移植的影响。)
	但是该文件要求放在类路径下,换句话说:也就是放到src下面。
	src下是类的根路径。

	直接以流的形式返回:
	InputStream in = Thread.currentThread().getContextClassLoader()
							.getResourceAsStream("com/bjpowernode/test.properties");

1.8、IO + Properties,怎么快速绑定属性资源文件?

	//要求:第一这个文件必须在类路径下
	//第二这个文件必须是以.properties结尾。
	ResourceBundle bundle = ResourceBundle.getBundle("com/bjpowernode/test");
	String value = bundle.getString(key);

2、今日反射机制的重点内容
2.1、通过反射机制访问对象的某个属性。


import com.bjpowernode.java.bean.Student;

import java.lang.reflect.Field;

/*
必须掌握:
    怎么通过反射机制访问一个java对象的属性?
        给属性赋值set
        获取属性的值get
 */
public class ReflectTest07 {
    public static void main(String[] args) throws Exception{

        // 我们不使用反射机制,怎么去访问一个对象的属性呢?
        Student s = new Student();

        // 给属性赋值
        s.no = 1111; //三要素:给s对象的no属性赋值1111
                    //要素1:对象s
                    //要素2:no属性
                    //要素3:1111

        // 读属性值
        // 两个要素:获取s对象的no属性的值。
        System.out.println(s.no);

        // 使用反射机制,怎么去访问一个对象的属性。(set get)
        Class studentClass = Class.forName("com.bjpowernode.java.bean.Student");
        Object obj = studentClass.newInstance(); // obj就是Student对象。(底层调用无参数构造方法)

        // 获取no属性(根据属性的名称来获取Field)
        Field noFiled = studentClass.getDeclaredField("no");

        // 给obj对象(Student对象)的no属性赋值
        /*
        虽然使用了反射机制,但是三要素还是缺一不可:
            要素1:obj对象
            要素2:no属性
            要素3:2222值
        注意:反射机制让代码复杂了,但是为了一个“灵活”,这也是值得的。
         */
        noFiled.set(obj, 22222); // 给obj对象的no属性赋值2222

        // 读取属性的值
        // 两个要素:获取obj对象的no属性的值。
        System.out.println(noFiled.get(obj));

        // 可以访问私有的属性吗?
        Field nameField = studentClass.getDeclaredField("name");

        // 打破封装(反射机制的缺点:打破封装,可能会给不法分子留下机会!!!)
        // 这样设置完之后,在外部也是可以访问private的。
        nameField.setAccessible(true);

        // 给name属性赋值
        nameField.set(obj, "jackson");
        // 获取name属性的值
        System.out.println(nameField.get(obj));
    }
}

2.2、通过反射机制调用对象的某个方法。

import com.bjpowernode.java.service.UserService;

import java.lang.reflect.Method;

/*
重点:必须掌握,通过反射机制怎么调用一个对象的方法?
    五颗星*****

    反射机制,让代码很具有通用性,可变化的内容都是写到配置文件当中,
    将来修改配置文件之后,创建的对象不一样了,调用的方法也不同了,
    但是java代码不需要做任何改动。这就是反射机制的魅力。
 */
public class ReflectTest10 {
    public static void main(String[] args) throws Exception{
        // 不使用反射机制,怎么调用方法
        // 创建对象
        UserService userService = new UserService();
        // 调用方法
        /*
        要素分析:
            要素1:对象userService
            要素2:login方法名
            要素3:实参列表
            要素4:返回值
         */
        boolean loginSuccess = userService.login("admin","123");
        //System.out.println(loginSuccess);
        System.out.println(loginSuccess ? "登录成功" : "登录失败");

        // 使用反射机制来调用一个对象的方法该怎么做?
        Class userServiceClass = Class.forName("com.bjpowernode.java.service.UserService");
        // 创建对象
        Object obj = userServiceClass.newInstance();
        // 获取Method
        Method loginMethod = userServiceClass.getDeclaredMethod("login", String.class, String.class);
        //Method loginMethod = userServiceClass.getDeclaredMethod("login", int.class);
        // 调用方法
        // 调用方法有几个要素? 也需要4要素。
        // 反射机制中最最最最最重要的一个方法,必须记住。
        /*
        四要素:
        loginMethod方法
        obj对象
        "admin","123" 实参
        retValue 返回值
         */
        Object retValue = loginMethod.invoke(obj, "admin","123123");
        System.out.println(retValue);
    }
}

2.3、通过反射机制调用某个构造方法实例化对象。


import com.bjpowernode.java.bean.Vip;

import java.lang.reflect.Constructor;

/*
比上一个例子(ReflectTest11)重要一些!!!

通过反射机制调用构造方法实例化java对象。(这个不是重点)
 */
public class ReflectTest12 {
    public static void main(String[] args) throws Exception{
        // 不使用反射机制怎么创建对象
        Vip v1 = new Vip();
        Vip v2 = new Vip(110, "zhangsan", "2001-10-11", true);

        // 使用反射机制怎么创建对象呢?
        Class c = Class.forName("com.bjpowernode.java.bean.Vip");
        // 调用无参数构造方法
        Object obj = c.newInstance();
        System.out.println(obj);

        // 调用有参数的构造方法怎么办?
        // 第一步:先获取到这个有参数的构造方法
        Constructor con = c.getDeclaredConstructor(int.class, String.class, String.class,boolean.class);
        // 第二步:调用构造方法new对象
        Object newObj = con.newInstance(110, "jackson", "1990-10-11", true);
        System.out.println(newObj);

        // 获取无参数构造方法
        Constructor con2 = c.getDeclaredConstructor();
        Object newObj2 = con2.newInstance();
        System.out.println(newObj2);
    }
}

2.4、通过反射机制获取父类以及父类型接口。


/*
重点:给你一个类,怎么获取这个类的父类,已经实现了哪些接口?
 */
public class ReflectTest13 {
    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[] interfaces = stringClass.getInterfaces();
        for(Class in : interfaces){
            System.out.println(in.getName());
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值