Java反射类的使用

1.反射的概念:运行时动态查询类的能力。

反射机制可以用来:

  • 在运行时分析类的能力
  • 在运行时检查对象,例如,编写一个适用于所有类的方法。
  • 实现泛型数组操作代码。
2.Class类

在程序运行期间,Java运行时系统始终为所有的对象维护一个运行时候类型标识。这个信息会跟踪每个对象所属的类。

3.获取Class对象的三种方式:
  1. 通过静态方法:Class.forName(className),其中className为类的全限定名:包名+类名。例如:“java.util.Random”
public static void main(String[] args) throws ClassNotFoundException {
	//定义要加载的类全限定名
	String className = "java.util.Random";
	//获取Class对象
	Class cl = Class.forName(className);
}	

2.通过类.class来创建Class对象

public static void main(String[] args){
	//调用Random类的class来创建class对象
		Class cl = Random.class;
}

3.通过类对象.getClass()来创建Class对象

public static void main(String[] args){
	//创建random对象
	Random random = new Random();
		
	//从对象中获取class
	Class cl = random.getClass();
}

常用反射还是第一种,利用全限定名进行加载对象。

4.定义用于说明反射的两个自定义类

Employee类,描述员工的基本信息

public class Employee {
	private String name;
	private double salary;
	private LocalDate hireDay;
	
	public Employee() {
		
	}
	public Employee(String name, double salary, int year, int month, int day) {
		this.name = name;
		this.salary = salary;
		this.hireDay = LocalDate.of(year, month, day);
	}
	public String getName() {
		return name;
	}

	public double getSalary() {
		return salary;
	}
	public void setSalary(double salary) {
		this.salary = salary;
	}
	public LocalDate getHireDay() {
		return hireDay;
	}
	@Override
	public String toString() {
		return "Employee [name=" + name + ", salary=" + this.getSalary() + ", hireDay=" + hireDay + "]";
	}	
}

Manager类,继承自Employee类

public class Manager extends Employee {
	private double bonus;
	
	public Manager() {
		
	}
	public Manager(String name, double salary, int year, int month, int day) {
		super(name, salary, year, month, day);
		this.bonus = 0;
	}

	public double getBonus() {
		return bonus;
	}

	public void setBonus(double bonus) {
		this.bonus = bonus;
	}
	
	@Override
	public double getSalary() {
		return this.bonus + super.getSalary();
	}
}
5.反射操作:

通过forName创建Class对象,后调用构造器实例化对象,然后在强转为指定类型的对象。

public static void main(String[] args) throws Exception{
		//要使用反射加载的类名
		String className = "com.shi.refelect.Manager";
		
		//使用Class.forName()加载类
		Class cl = Class.forName(className);
		
		//调用构造器后生成实例对象,返回类型为Object。(此时的构造器是无参构造)
		Object obj = cl.getConstructor().newInstance();
		
		//为构造器传递指定类型的参数,
		Object obj2 = cl.getConstructor(String.class, double.class, int.class, int.class, int.class).newInstance("张三", 5000, 2019, 12, 25);
		
		//对返回的Object类型进行强转
		Manager manager = (Manager)obj;		
		Manager manager2 = (Manager)obj2;
		
		//输出反射生成的Manager对象
		System.out.println(manager);
		System.out.println(manager2);
	}
6.从Class类对象中获取Fields,Methods, Constractors.
public static void main(String[] args) throws Exception{
		//要使用反射加载的类名
		String className = "com.shi.refelect.Manager";
		
		//使用Class.forName()加载类
		Class cl = Class.forName(className);
		
		//返回类中的公共字段,包括超类中的公共字段。返回类型为Field[]。 此时类中没有定义公共字段,fields为空
		Field[] fields = cl.getFields();
		System.out.println("包含超类的公共字段: " + Arrays.toString(fields));
		
		//返回类中你定义的字段,不限于公共字段。不包括超类
		fields = cl.getDeclaredFields();
		System.out.println("不包括超类的字段: "+Arrays.toString(fields));
		
		//返回类中的公共方法,包括超类中的公共方法。返回类型为Method[]。
		Method[] method = cl.getMethods();
		System.out.println("包含超类的公共方法: "+Arrays.toString(method));
		
		//返回类中你定义的方法,不限于公共方法。不包括超类
		method = cl.getDeclaredMethods();
		System.out.println("不包含超类的方法: "+Arrays.toString(method));
		
		//返回类中的公共构造器,包括超类中的构造器
		Constructor[] constructor = cl.getConstructors();
		System.out.println("包含超类的公共构造方法: "+Arrays.toString(constructor));
		
		//返回类中的构造器,不包括超类的构造器
		constructor = cl.getDeclaredConstructors();
		System.out.println("不包含超类的构造方法: "+Arrays.toString(constructor));
		
	}
7.Field在反射中的应用
public static void main(String[] args) throws Exception {
		
		//要获取类的全限定名
		String className = "com.shi.refelect.Manager";
		
		//利用反射加载类
		Class cl = Class.forName(className);
		
		//获取Manager类的字段,(可以是私有的,不包括其超类的字段)
		Field field = cl.getDeclaredField("bonus");
		
		//设置字段是可访问的,不然会报错
		field.setAccessible(true);
		
		//创建一个Manager类对象
		Manager manager = new Manager("张三", 5000, 2018, 12, 23);
		
		//通过field字段获取manager的bonus字段值,其返回类型为Object
		Object obj = field.get(manager);
		
		//把字段值转换为double后输出字段值	结果是0,因为bonus字段没有显式的赋值
		System.out.println((double) obj);

		//通过field字段设置manager的bonus字段值
		field.set(manager, 500);
		
		//此时的bonus字段值为500
		System.out.println(manager.getBonus());
}

上面Field.getDeclaredField()能获取 private 和 public 字段 ,其中获取 private字段需要设置field.setAccessible(true); 公共字段可以不用设置field.setAccessible(true);当要获取超类的字段值时,使用:

Field field = cl.getField(字段名);

但是只能获取超类的公共字段,不能获取其其他类型的字段。

8.Method在反射中的应用
public static void main(String[] args){
		//要获取类的全限定名
		String className = "com.shi.refelect.Manager";
		
		//利用反射加载类
		Class cl = Class.forName(className);

		//获取有指定参数的方法
		//获取公共的带参数的method,指定方法名和参数类型
		Method method = cl.getMethod("setBonus", double.class);
		
		//若setBonus()为私用的则用下面这种形式调用。
//		Method method = cl.getDeclaredMethod("setBonus", double.class);
//		method.setAccessible(true);
		
		//为方法传递对象和参数。
		method.invoke(manager, 2000);
		
		//输出结果	bonus = 2000
		System.out.println(manager.getBonus());
		
		
		//获取没有参数的方法
		//获取公共无参的method,指定方法名,参数类型为null
		Method m = cl.getMethod("getBonus", null);
		
		//在指定对象上执行方法,返回类型为Object
		Object target = m.invoke(manager, null);
		
		//进行强转后输出其内容,target = 2000
		System.out.println((double) target);
}

Method.getMethod() 可以获取对象包括超类的公共方法,Method.getDeclaredMethod() 可以获取对象的任何方法(不包括超类对象的任何方法)。

  • 获取带参数的方法时,需要指定方法名和参数所属的类对象:Method method = cl.getMethod(“setBonus”, double.class); 指定 setBonus(double bonus) 方法。调用时需要传递指定对象和参数:method.invoke(manager, 2000); 意思为:执行 manager.setBonus(2000) 操作;
  • 获取不带参数而有返回值的方法时,指定方法名和null参数。Method m = cl.getMethod(“getBonus”, null); 说明此方法没有参数。执行时需要:Object target = m.invoke(manager, null); 在指定对象上执行,且有返回值的话要使用Object对象来进行接收。
9.Constrator在反射中的应用
public static void main(String[] args){
	//要获取类的全限定名
		String className = "com.shi.refelect.Manager";
		
		//利用反射加载类
		Class cl = Class.forName(className);
		
		//获取反射类对象的无参构造
		Constructor con = cl.getConstructor();
		//使用无参构造来生成实例对象
		Object obj2 = con.newInstance();
		//判断对象是否为Manager类
		if (obj2 instanceof Manager) {
			System.out.println("反射成功");
		}
		
		//获取反射类对象的有参构造
		Constructor con2 = cl.getConstructor(String.class, double.class, int.class, int.class, int.class);
		//在实例化对象时进行传参,返回值为Object类型
		Object obj3 = con2.newInstance("李四", 8000, 2017, 12, 25);
		
		//若属于Manager类对象则进行强转
		if (obj3 instanceof Manager) {
			obj3 = (Manager) obj3;
		}
		//输出反射生成的类对象
		System.out.println(obj3);
}
  • 无参构造,Constructor con = cl.getConstructor(); 不指定任何参数的构造器,实例化时也不需要进行传参: Object obj2 = con.newInstance(); 反射生成的类都是Object类型的。
  • 有参构造:Constructor con2 = cl.getConstructor(String.class, double.class, int.class, int.class, int.class); 指定参数类型的构造器,实例化时需要传递相对应类的参数值:Object obj3 = con2.newInstance(“李四”, 8000, 2017, 12, 25); 构造成功时,通过 instanceof 来进行判断,若属于manager类则可以进行强转。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值