史上最全讲解:JAVA中的反射

史上最全讲解:JAVA中的反射

反射概述

反射机制:将类中的各个部分部分封装成其他的对象(构造方法对象们,方法对象们,属性们)
JAVA代码在计算机中经历的三个阶段:
在这里插入图片描述
反射的过程:
1.source源代码阶段:
java文件包括三大部分:成员属性,构造方法,成员方法.被编译成class字节码文件,此时.java文件和.class文件还是存在于硬盘上,没有被加载进内存
2.Class类对象阶段:
类加载器,ClassLoader将.class文件加载到内存上.Class类对象专门描述.class字节码文件的(java中一切皆对象),可以将Class类理解为一般的普通类,比如String类,自定义的Person类,它也具有一般类该具有的特性.
三大部分:成员属性封装成为Field对象,成员方法封装成为Method对象,构造方法封装成为Constructor对象
3.runtime运行时阶段:
new对象 就会在堆内存中生成相应的对象.
同一个字节码文件.class文件在一次程序运行过程中只能够被加载一次,一个类对应的Class类对象只有一个
不论哪一种方式获取的类对象都是同一个
**
实例对象就通过Class对象来创建的
如果说类是对对象的抽象和集合的话,那么Class类就是对类的抽象和集合。

反射发生在程序运行时期!
简单案例介绍: 想要实现一个类中的方法,但是目前
不确定**是哪个类,比如:有一个Teacher类里面有一个teach方法,还有一个Student类,里面有一个study方法,想调用Teacher类里面的teach方法,再调用Student类里面的study方法,那么在一个main方法中必须先创建一个Teacher类的对象teacher调用teach方法,再将其注释掉,再创建一个Student类的对象,调用study方法 .

package com.shsxt.reflector;

public class ReflectDemo03 {
	public static void main(String[] args) {
		Teacher02 teacher = new Teacher02();
		teacher.teach();
		//Student02 student = new Student02();
		//student.study();
	}
}
 class Student02 {
	 public static void study(){
		 System.out.println("学习");
	 }
 }
 class Teacher02 {
	 public static void teach(){
		 System.out.println("教书");
	 }
 }

反射的好处:
1.可以在程序运行过程中操作这些对象
2.解耦
利用反射解决上述问题:可以将类名和方法名放在properties配置文件中

  • 使用反射的步骤:
    1.获取Class类对象
    2.根据Class类对象获取构造方法创建对象
    3.根据创建的对象获取方法(私有和公有)
    4.根据创建的对象获取属性(私有和公有)

获取Class类对象

一旦加载类,就会存在一个当前类的Class对象,Class只有一个,存着这个类的所有内容如果一旦获取到一个类的Class对象,就能够对这个进行任何操作

  • Class.forName(包名+类名);在源文件阶段将class文件加载进内存
  • 类名.class Class类对象阶段
  • 对象.getClass(); 运行时阶段 new完对象后获取对象对应的类的Class类对象
package com.shsxt.reflector;

public class ReflectDemo01 {
	public static void main(String[] args) throws ClassNotFoundException {
		//类名.class
		Class cls1 = String.class;
		//对象.getclass
		Class cls2 = "哈哈哈哈".getClass();
		//Class.forname("报名+类名")
		Class cls3 = Class.forName("java.lang.String");
		Class cls4 = int.class;
		System.out.println(cls4);//int
		Class cls5 = Integer.class;
		System.out.println(cls1==cls2);//true
		System.out.println(cls1==cls3);//true
		System.out.println(cls4==cls5);//false
		System.out.println(cls1.getSuperclass());//父类的包名+类名 class java.lang.Object
		System.out.println(int.class==Integer.class);//false
		System.out.println(int.class==Integer.TYPE);//true

	}
}

获取构造方法

Constructor getConstructor(Class<?>… parameterTypes) 获取指定公共的构造器
Constructor<?>[] getConstructors() 获取所有的公共的构造器
Constructor getDeclaredConstructor(Class<?>… parameterTypes) 任意权限的其中一个
Constructor<?>[] getDeclaredConstructors() 任意权限的所有的构造器
创建对象的两种方法:
1.没有参数的对象(即空构造方法),可以有两种方式,Class中的newInstance()方法,默认根据表示的类型中的空构造创建对象.或者使用构造器中的newInstance()方法
2.创建带参数的对象,使用constructor构造器中的newInstance(参数)方法
[注意]私有构造器需要开放权限setAccessible()

获取方法

  • 如何获取类中的方法
    Method getMethod(String name, Class<?>… parameterTypes) 公共的方法中某一个
    Method[] getMethods() 公共的方法中所有的
    Method getDeclaredMethod(String name, Class<?>… parameterTypes) 所有方法中的某一个
    Method[] getDeclaredMethods() 所有方法中的所有的
  • 调用方法
    Object invoke(Object obj, Object… args)

获取属性

  • 反射操作属性
        Field getDeclaredField(String name)
        Field[] getDeclaredFields()
        Field getField(String name)
        Field[] getFields()
  • 为属性赋值
        set(对象名,参数值)
        field.set(user,“王五”)
  • 获取属性的值
        field.get(user)
package com.shsxt.reflector;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

public class ReflectDemo02 {
	public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchFieldException, IllegalArgumentException {
		testConstructor(Student.class);
		testMethod(Student.class);
		testField(Student.class);
	}
	//操作属性
	public static void testField(Class cls) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InstantiationException{
		Field field = cls.getDeclaredField("name");
		Student stu = (Student)cls.newInstance();
		field.set(stu, "王五");
		System.out.println(field.get(stu));
	}
		
	//操作方法
	public static void testMethod(Class cls) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
		Method method = cls.getMethod("study");
		//使用成员方法 必须创建对象
		Student stu = (Student)cls.newInstance();//根据class类对象创建无参对象,需要向下转型,强制类型转换,如果带有泛型即可不用转换
		method.invoke(stu);//调用没有参数的方法
		//System.out.println(cls.newInstance());
		//method.invoke(stu, 1);//不可以这样操作 因为成员方法还有从 父类继承过来的,即有多个方法的参数为一个
		Method[] methods = cls.getMethods();
		System.out.println(Arrays.toString(methods));
		
	}
	//操作构造器
	public static void testConstructor(Class cls) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException {
		Constructor cons = cls.getConstructor(String.class);
		Constructor[] arr = cls.getDeclaredConstructors();
		for(Constructor c:arr){
			System.out.println(c);
		}
		Object obj = cls.newInstance();//通过class类对象直接创建空参对象
		System.out.println(obj);
		Student stu = (Student)cons.newInstance("hhhh");//通过构造器创建一参对象 并且需要向下转型,强制类型转换 如果创建构造器的时候给定了泛型不用类型转换
		Student stu3 = (Student)arr[0].newInstance();//通过构造器创建空参对象 需要向下转型,强制类型转换
		System.out.println(stu3);
		arr[2].setAccessible(true);
		Student stu2 = (Student)arr[2].newInstance("sss","111",123);//通过多参构造器创建多参对象 需要向下转型,强制类型转换
		arr[2].setAccessible(false);
		System.out.println(stu2);
	}
}

class Student {
	public String name;
	public String sex;
	public int age;
	private Student(String name, String sex, int age) {
		super();
		this.name = name;
		this.sex = sex;
		this.age = age;
	}
	
	public Student(String name) {
		super();
		this.name = name;
		this.sex = sex;
		this.age = age;
	}
	public Student() {
		super();
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", sex=" + sex + ", age=" + age + "]";
	}
	
	public static void study() {
		System.out.println("学习");
	}
	
	public static void sleep(int i) {
		System.out.println("我会睡觉"+i);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值