Java之路:反射机制

1、认识反射

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法,这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

Java反射机制主要提供了以下功能:在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法。

根据对象找到类:

import java.util.Date;

public class ReflectionDemo1 {
	public static void main(String[] args) throws Exception {
		Date date = new Date();
		Class<?> cls = date.getClass();	// 通过Java反射机制得到类的包名
		System.out.println(cls);
	}
}

【结果】
在这里插入图片描述

在本程序之中使用的getClass()方法是由Object类所定义的:public final Class<?>getClass();,此方法返回的对象类型为Class,而Class是反射操作的源头。但是如果要想取得Class类的实例化对象在Java之中有三种方式:

方式一:利用Object类的getClass()方法,但是要求必须先产生指定类的对象才可以,几乎不用。
Date date = new Date(); Class<?> cls = date.getClass() ; System.out.println(cls);
方式二:利用“类.class”的形式取得Class类的对象,在Hibernate上使用。
Class<?> cls = java.util.Date.class; System.out.println(cls);
方式三:利用Class类提供的一个方法完成,在系统架构中使用:
Class<?> cls = Class.forName("java.util.Date"); System.out.println(cls);

package com.xy.test2;	// 包名
class Book {
	private String title;
	private double price;

	public void setTitle(String title) {
		this.title = title;
	}

	public void setPrice(double price) {
		this.price = price;
	}
	
	@Override
	public String toString() {
		return "Book[title = " + title + ", price = " + price + "]";
	}
}
public class ReflectionDemo2 {
	@SuppressWarnings("deprecation")
	public static void main(String[] args) throws Exception {
		Class<?> cls = Class.forName("com.xy.test2.Book");	// 用(包名.类名)访问
		Book book = (Book)cls.newInstance();	// 实例化一个对象
		book.setPrice(79.8);
		book.setTitle("Java开发实践经典");
		System.out.println(book);
	}
}

【结果】
在这里插入图片描述

现在可以发现如果要想实例化对象可以有两种形式,一种是通过关键字new,另外一种是通过反射机制完成。
如果要想更好地观察出这两种方式的特点,最好的做法就是通过工厂设计模式完成验证。

interface Book {
	public String getTitle();
}

class MathBook implements Book {
	@Override
	public String getTitle() {
		return "数学类图书";
	}
}
class Factory {
	public static Book getInstance(String className) {
		if("mathbook".equals(className)) {
			return new MathBook();
		}
		return null;
	}
}
public class ReflectionDemo3 {
	public static void main(String[] args) throws Exception {
		Book book = Factory.getInstance("mathbook");
		System.out.println(book.getTitle());
	}
}

【结果】
在这里插入图片描述

这个时候,如果要想增加新的子类,则一定要修改工厂类。因为工厂类之中需要使用关键字new实例化,所以在这种情况下,发现关键字new依然会造成耦合,那么如果说现在使用的是反射机制呢?

使用反射机制的工厂模式

package com.xy.test2;
interface Book {
	public String getTitle();
}

class MathBook implements Book {
	@Override
	public String getTitle() {
		return "数学类图书";
	}
}
class ComputerBook implements Book {
	@Override
	public String getTitle() {
		return "计算机类图书";
	}
}
class Factory {
	@SuppressWarnings("deprecation")
	public static Book getInstance(String className) {
		Book book = null;
		try {
			book = (Book)Class.forName(className).newInstance();
		}
		catch(Exception e) {
			e.printStackTrace();
		}
		return book;
	}
}
public class ReflectionFactory {
	public static void main(String[] args) throws Exception {
		Book book = Factory.getInstance("com.xy.test2.ComputerBook");	// 用(包名.类名)访问
		System.out.println(book.getTitle());
	}
}

【结果】
在这里插入图片描述

不管有多少个子类,工厂类都可以使用,这就是反射机制所带来的好处,而在日后的开发之中,如果发现有时候需要写出完整的“包.类”,就表示此处使用了反射机制。

反射的其他操作

在之前已经学习了反射机制进行对象实例化的操作过程,但是不要忘记,在之前的类中所提供的都是无参构造方法。

如果此时类中没有提供无参构造方法,只提供了有参构造方法,则就必须明确地调用指定的构造方法才可以通过反射实例化对象。

public Constructor<T> getConstructor(Class<?>... parameterTypes) throws 
NoSuchMethodException, SecurityException;

//在Constructor类之中提供有一个实例化对象方法。

public T newInstance(Object... initargs) throws
InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException

调用构造方法取得实例化对象,如下例:

package com.xy.test2;

import java.lang.reflect.Constructor;

class Book {
	private String title;
	private double price;

	public Book(String title, double price) {
		super();
		this.title = title;
		this.price = price;
	}
	
	@Override
	public String toString() {
		return "Book[title = " + title + ", price = " + price + "]";
	}
}
public class ReflectionDemo4 {
	public static void main(String[] args) throws Exception {
		Class<?> cls = Class.forName("com.xy.test2.Book");	// 用(包名.类名)访问
		Constructor<?> cons = cls.getConstructor(String.class, double.class);
		Book book = (Book)cons.newInstance("Java开发经典实践", 79.8);	// 实例化一个对象
		System.out.println(book);
	}
}

【结果】
在这里插入图片描述

很明显,此时类之中还是提供无参构造方法会更加方便一些,这一点就是在简单Java类之中要求提供无参构造的关键因素。

在之前针对于属性的操作明确给出了要求,利用setter、getter设置和取得,而且对于setter、getter要求其必须按照指定的格式编写。而之所以存在这样的要求,也是因为反射机制的原因。

//此时可以使用Class类的如下方法取得方法的对象。
public Method getMethod(String name, Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException;
//取得了Method类的对象之后可以利用以下方法进行方法的反射调用。
public Object invoke(Object obj, Object... args) throws IllegalAccessException,
IllegalArgumentException, InvocationTargetException;
package com.xy.test2;

import java.lang.reflect.Method;

class Book {
	private String title;

	public void setTitle(String title) {
		this.title = title;
	}

	public String getTitle() {
		return title;
	}
}
public class ReflectionDemo5 {
	public static void main(String[] args) throws Exception {
		String filedName = "title";	// 要操作的属性
		String titleValue = "Java开发实践经典";
		Class<?> cls = Class.forName("com.xy.test2.Book");
		Object obj = cls.newInstance();	// 产生对象可以分配堆内存
		Method setMethod = cls.getMethod("set" + initcap(filedName), String.class);
		Method getMethod = cls.getMethod("get" + initcap(filedName));
		setMethod.invoke(obj, titleValue);	// 对象.setTitle()调用
		System.out.println(getMethod.invoke(obj)); 	// 对象.getTitle()调用
	}
	public static String initcap(String str) {
		return str.substring(0, 1).toUpperCase() + str.substring(1);
	}
}

【结果】
在这里插入图片描述

发现有了反射之后,只要有Object对象,以及要操作的属性名称就可以直接利用反射完成了,这个就是setter、getter命名标准的定义由来。

框架开发原理 = 反射机制 + XML解析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值