(初学)JAVA的反射机制

前言:

在学习反射机制之前,我熟悉的操作是:
1、程序的运行过程
编译器,将.java文件编译成.class(二进制)文件。
运行期,jvm加载并运行.class文件。

2、对象创建的过程
编写类–>创建对象–>调用成员。
所有的上面操作都是发生在编译期。
注:这里放一个Student类,文章根据这个类来进行演示

package day10;
//学生类
public class Student {
	
	public String name;
	protected String address;
	private Integer id;
	
	
	public Student(String address, Integer id, Integer score) {
		System.out.println("三个参数的构造器");
		this.address = address;
		this.id = id;
		this.score = score;
	}
	public Student() {
		System.out.println("Student无参构造函数");
	}
	//使用成员生成构造函数
	public Student(Integer id, Integer score) {
		
		this.id = id;
		this.score = score;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public Integer getScore() {
		return score;
	}

	public void setScore(Integer score) {
		this.score = score;
	}

	private Integer score;
	
	
	//在这个类中,还可以自定义方法
	public void study(String name) {
		System.out.println("学生在学习");
	}
	
	private void song() {
		System.out.println("学生在唱歌");
	}
	
}

在之前的情况下,我们进行对象的方法调用等都是运用以下方式:

package day10;

public class Test01 {
	public static void main(String[] args) {
		//创建对象
		Student s=new Student();
		//对象调用成员(属性和方法)
		s.name="李四";
		//s.study();
		
		Student ss=new Student("江苏",10,20);
	}
}

有了对比才体现出反射的优势,好的,进入正题。

一、什么是JAVA反射机制

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性。这种动态获取信息以及动态调用对象方法的功能称为JAVA语言的反射机制。
简单来说,在JAVA中,只要知道类的名字,就可以在运行时通过反射机制获取该类的所有信息。

二、反射机制的作用

1、在运行时判断任意一个对象所属的类。
2、在运行时构造任意一个类的对象。
3、在运行时判断任意一个类所具有的成员变量和方法。
4、在运行时调用任意一个对象的方法。

三、反射机制使用场景

1、反编译(.class变为.java)
2、开发框架(反射是框架设计的灵魂),比如Spring框架。为了保证框架的通用性,框架需要根据配置文件加载不同的类或者对象(运行期间,动态加载所需的对象)SSM SSH

四、反射机制的实现

JAVA中,使用一个类需要把该类加载到虚拟机中,并生成一个Class对象,这个对象保存了该类的所有信息。反射机制的实现,就是获取这个Class对象。

4.1、Class对象获取方式

1、使用已知对象.getClass()返回Class类对象
2、使用一个已知的类的类名.class返回Class对象。
3、使用Class类的静态方法forName(),返回Class对象。

package day10;
/*
 * 演示Class对象获取方式
 * 当虚拟机加载.class文件以后,就会生成一个Class对象
 * Class对象封装一个类的所有信息
 */
public class Test02 {
	public static void main(String[] args) throws ClassNotFoundException {
		//1对象.getClass
		Student s=new Student();
		Class class1=s.getClass();
		//2类名.class
		Class class2=Student.class;
		//3Class今天方法获取Class对象
		Class class3=Class.forName("day10.Student");//括号写包名或类名,表示要用的
	}
}

测试结果:
在这里插入图片描述
(讲真这里的Class如果加个<?>会不会更好,如果有小伙伴知道的话还请指点我下)

4.2、使用反射机制创建对象的两种方式

1、调用newInstance()方法。
2、使用Constructor对象。

package day10;

import java.lang.reflect.Constructor;

/*
 * 演示Class对象获取方式
 * 当虚拟机加载.class文件以后,就会生成一个Class对象
 * Class对象封装一个类的所有信息
 * 
 * 使用Class对象,创建Student对象
 */
public class Test03 {
	public static void main(String[] args) throws Exception {
		
		//3Class今天方法获取Class对象
		Class class3 = Class.forName("day10.Student");//括号写包名或类名,表示要用的
		//因为不知道加载对象的类型,所以统一使用Object接收
		//创建Student对象的第一种方式
		Object obj1=class3.newInstance();
		System.out.println(obj1);
		System.out.println("----------");
//		//Constructor对象
//		//创建Student对象的第二种方式,获取构造器
//		Constructor constructor = class3.getConstructor();
//		Object obj2=constructor.newInstance();
//		System.out.println(obj2);
//		//如果把之前的无参构造函数注释,则报错原因是Student类中没有无参构造
		
		//Constructor对象
		//创建Student对象的第二种方式,获取构造器
		Constructor constructor = class3.getConstructor(String.class,Integer.class,Integer.class);
		Object obj2=constructor.newInstance("江苏",10,20);
		System.out.println(obj2);
		
	}
}

测试结果:
在这里插入图片描述

五、常用方法

5.1、获取构造方法

1、//获取所有的“公有的(public)”构造方法
public Constructor[] getConstructors()

2、//获取所有的构造方法(包括私有、受保护、默认、共有)
public Constructor[] getDeclaredConstructors()

3、//获取单个的“公有的(public)”构造方法
public Constructor getConstructor(Class…parameterTypes)

4、//获取“某个构造方法”可以是私有的、或者受保护、默认、共有的
public Constructor[] getDeclaredConstructors(Class…parameterTypes)

package day10;

import java.lang.reflect.Constructor;

/*
 * 演示Class对象获取方式
 * 当虚拟机加载.class文件以后,就会生成一个Class对象
 * Class对象封装一个类的所有信息
 * 
 * 使用Class对象,创建Student对象
 */
public class Test04 {
	public static void main(String[] args) throws Exception {
		
		//3Class今天方法获取Class对象
		Class class3 = Class.forName("day10.Student");//括号写包名或类名,表示要用的
		//获取Class对象中的构造函数
		Constructor[] constructors = class3.getConstructors();
		
		for(Constructor c:constructors) {
			System.out.println(c);
		}
		
		System.out.println("----------------");
		Constructor[] arr = class3.getDeclaredConstructors();
	
		for(Constructor cc:arr) {
			System.out.println(cc);
		}
		System.out.println("-------");
		//获取单个构造器
		Constructor constructor=class3.getConstructor();
		System.out.println(constructor);
		System.out.println("-------");
		//获取单个私有构造器
		Constructor constructor1=class3.getDeclaredConstructor(Integer.class,Integer.class);
		System.out.println(constructor);
		
	}
}

测试结果:
在这里插入图片描述

5.2、获取成员变量并调用

1、//获取所有属性,包括所有的公有属性
Field getFields()

2、//获取所有字段,包括:私有、受保护、默认、公有
Field[] getDeclaredFields()

3、//获取某个“公有的属性”
public Field getField(String fieldName)

4、//获取某个字段(可以是私有的)
public Field getDeclaredFields(String fieldName)

package day10;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

/*
 * 演示Class对象获取方式
 * 当虚拟机加载.class文件以后,就会生成一个Class对象
 * Class对象封装一个类的所有信息
 * 
 * 使用Class对象,创建Student对象
 */
public class Test05 {
	public static void main(String[] args) throws Exception {
		
		//3Class今天方法获取Class对象
		Class class3 = Class.forName("day10.Student");//括号写包名或类名,表示要用的
		//成员变量(只能获取共有)
		Field[] fields = class3.getFields();
		for(Field f:fields) {
			System.out.println(f);
		}
		System.out.println("--------------");
		//公有私有均可获取
		Field[] declaredFields = class3.getDeclaredFields();
		for(Field ff:declaredFields) {
			System.out.println(ff);
		}
		
		Field fff=class3.getDeclaredField("score");
		System.out.println(fff);
		
		//动态的给对象赋值
		//第一步:得到对象
		Object obj1 = class3.newInstance();
		//指定给哪个属性赋值
		Field field=class3.getField("name");
		field.set(obj1, "lisi");
		
		Student student=(Student)obj1;
		System.out.println(student.name);
	}
}

测试结果:
在这里插入图片描述

5.3、获取成员方法并调用
5.3.1、批量获取

1、//获取所有公有方法,包含父类的方法也包含Object类
public Method[] getMethods();

2、//获取所有的成员方法,包括私有的(不包括继承的)
public Method[] getDeclaredMethods();

5.3.2、单个获取

1、//获取单个公有方法
public Method getMethod(String name,Class<?>…parameterTypes)

2、//获取单个可以是任何类的方法
public Method getDeclaredMethod(String name,Class<?>…parameterTypes)

5.4、invoke方法

public Object invoke(Object obj,Object,args)
注:obj要调用的方法,args调用方法时所传递的参数。

package day10;

import java.lang.reflect.Method;

/*
 * 演示Class对象获取方式
 * 当虚拟机加载.class文件以后,就会生成一个Class对象
 * Class对象封装一个类的所有信息
 * 
 * 使用Class对象,创建Student对象
 */
public class Test06 {
	public static void main(String[] args) throws Exception {
		
		//3Class今天方法获取Class对象
		Class class3 = Class.forName("day10.Student");//括号写包名或类名,表示要用的
		//获取Class对象中的方法
		Method[] methods = class3.getMethods();
		for(Method m:methods) {
			System.out.println(m);
		}
		
		//获取单个方法name(方法名), parameterTypes(方法的参数类型)
		Method mm=class3.getMethod("study",String.class);//没有参数则后面就不用写
		System.out.println(mm);
		
		
		Object obj3=class3.newInstance();
		//方法的调用
		mm.invoke(obj3, "李思");
		//mm.invoke(class3.getDeclaredConstructor().newInstance(),"李思" );
	
	}
}

测试结果:
在这里插入图片描述

六、反射实现的案例

package reflect;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class Test02 {
	public static void main(String[] args) {
		try {
			
			Class clzz=Class.forName(getValue("className"));
			Method method=clzz.getMethod(getValue("method"));
			method.invoke(clzz.getConstructor().newInstance());
	
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
		
	}
	
	
	public static String getValue(String key) throws IOException {
		//获取Properties 对象
		Properties p=new Properties();
		FileReader r=new FileReader("user.txt");
		p.load(r);
		
		r.close();
		return p.getProperty(key);
		
		
		
		
	}

}

七、附加案例

package day10;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Properties;

//使用反射机制动态加载配置文件实现动态创建对象
public class TestReflect {
	public static void main(String[] args) throws Exception {
		Class clazz=Class.forName(getvalue("className"));
		//通过反射机制,创建User对象
		Object obj1=clazz.newInstance();
		//获取login方法
		Method method=clazz.getMethod("login", String.class);
		//调用方法
		method.invoke(obj1, "小明");
	}
	//封装一个方法,加载配置文件,根据key读取配置文件
	public static String getvalue(String key) throws FileNotFoundException{
		//Properties可以将配置文件的数据以key-value的形式读取
		Properties p=new Properties();
		String value;
		try {
			
			//读取文件
			FileReader reader=new FileReader("user.txt");
			p.load(reader);
			value=p.getProperty(key);
			reader.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return p.getProperty(key);
	}
}

package day10;
//User类
public class User {
	private String name;
	private Integer id;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	
	//自定义方法
	public void login(String name) {
		System.out.println(name+"正在登录");
	}
}

className=day10.User
method=login;

(这两行是写在user.txt)

测试结果:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值