java的反射机制
所谓的"反"就是指可以利用对象找到对象的出处,在Object类里面提供有一个方法:
• 取得Class对象:public final Class<?> getClass();
Class类对象实例化:
java.lang.Class是一个类, 这个类是反射操作的源头,即:所有的反射都要从此类开始进行,而最关键的是这个类有三种实例化方式
• 调用Object类中的getClass()方法: Class<?> clazz = new Date().getClass();
• 调用"类.class" : Class<?> clazz = Date.class;
• 调用类Class提供的一个方法: Class<?> clazz = Class.forName("java.util.Date");
反射实例化对象:
先有Class对象
• 实例化对象方法: public T newInstance()
class Book{
public Book() {
System.out.println("********** Book类的无参构造方法 **********");
}
@Override
public String toString() {
return "这是一本书";
}
}
public class TestClazz {
public static void main(String[] args)throws Exception {
Class<?> clazz = Class.forName("com.feng.Clazz.Book");
Object o = clazz.newInstance();
}
}
在任务的开发中, new 是造成耦合的最大元凶,一切的耦合都起源于new
工厂设计模式:每增加一个类就要去修改工厂类,如果随时都可能增加子类?
interface Fruit{
public void eat();
}
class Apple implements Fruit{
public void eat(){
System.out.println("吃苹果。。。");
}
}
class Orange implements Fruit{
public void eat(){
System.out.println("吃橘子。。。");
}
}
class Factory{
public static Fruit getInstance(String name){
if ("apple".equals(name)){
return new Apple();
} else if ("orange".equals(name)){
return new Orange();
}
return null;
}
}
public class TestFactoryPattern {
public static void main(String[] args) {
Fruit fruit = Factory.getInstance("apple");
fruit.eat();
}
}
解决办法: 做反射
interface Fruit{
public void eat();
}
class Apple implements Fruit{
public void eat(){
System.out.println("吃苹果。。。");
}
}
class Orange implements Fruit{
public void eat(){
System.out.println("吃橘子。。。");
}
}
class Factory{
public static Fruit getInstance(String name) throws Exception{
Fruit f = (Fruit)Class.forName(name).newInstance();
return f;
}
}
public class TestFactoryPattern {
public static void main(String[] args) throws Exception {
Fruit fruit = Factory.getInstance("com.feng.factory.Orange");//全类名
fruit.eat();
}
}
使用反射调用构造:
在之前所编写的代码中, 实际上发现都默认使用了类中的无参构造方法,如果类中不提供无参的构造方法呢?
类中不存在无参构造
class Book{
private String title;
private double price;
public Book(String title, double price) {
this.title = title;
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"title='" + title + '\'' +
", price=" + price +
'}';
}
}
由于类中不存在无参构造方法,下面的程序是错误的
public class TestClazz {
public static void main(String[] args)throws Exception {
Class<?> clazz = Class.forName("com.feng.Clazz.Book");
Object o = clazz.newInstance(); //相当于使用new调用无参构造实例化对象
Book book = (Book) o;
System.out.println(book);
}
}
Exception in thread "main" java.lang.InstantiationException: com.feng.Clazz.Book at java.lang.Class.newInstance(Class.java:427) at com.feng.Clazz.TestClazz.main(TestClazz.java:33) Caused by: java.lang.NoSuchMethodException: com.feng.Clazz.Book.<init>() at java.lang.Class.getConstructor0(Class.java:3082)
所以在这种情况下,只能够调用有参构造方法:
• 在Class类中, 有一种方法可以取得全部构造: public Constructor<T>[] getConstructors()
• 在Class类中, 有一种方法可以取得指定参数(参数为类型)顺序的构造: public Constructor<T> getConstructor(Class<?> ..parameterTypes)
以上两个方法返回的都是“java.lang.reflect.Constructor”类的对象,在这个类中提供有一个明确传递有参构造内容的实例化对象方法:
• public T newInstance(Object...initargs) // 参数是具体的入参
class Book{
private String title;
private double price;
public Book(String title, double price) {
this.title = title;
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"title='" + title + '\'' +
", price=" + price +
'}';
}
}
public class TestClazz {
public static void main(String[] args)throws Exception {
Class<?> clazz = Class.forName("com.feng.Clazz.Book");
Constructor<?> constructor = clazz.getConstructor(String.class, double.class);
Object b = constructor.newInstance("java开发", 20.2);
System.out.println(b);
}
}
反射调用方法:
方法的调用: 一个类产生实例化对象之后才可以调用。实例化对象的三种方式:
在Class类里面提供有以下取得类中Method的操作:
• 取得一个类中的全部方法: public Method[] getMethods();
• 取得一个类中的指定方法: public Method getMethod(Sting methodName, Class<?> ....parameterType) // parameterType: 参数类型
以上的两个操作返回的是Method类的对象, 在这个类里面,重点关注一个方法“
• public Object invoke(Object obj, Object...args)
obj: 实例化对象
args: 参数内容
利用反射调用方法:
class Book{
private String title;
public Book() {
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
public class TestClazz {
public static void main(String[] args)throws Exception {
//要操作的成员
String fieldName = "title";
Class<?> clazz = Class.forName("com.feng.Clazz.Book");
//必须给出实例化对象
Object obj = clazz.newInstance();
Method setMethod = clazz.getMethod("set" + initCap(fieldName), String.class);
Method getMethod = clazz.getMethod("get" + initCap(fieldName));
//等价于:Book类对象.setTitle("Java开发")
setMethod.invoke(obj, "Java开发");
System.out.println(getMethod.invoke(obj));
}
public static String initCap(String str){
return str.substring(0,1).toUpperCase() + str.substring(1);
}
}
此时完全看不见具体的操作类型,也就是利用反射可以实现任意类的指定方法的调用
反射调用成员:
类中的属性一定要在本类实例化对象之后才可以分配内存空间。在Class类里面提供取得成员的方法
• 取得全部员: public Field[] getDeclaredFields();
• 取得指定成员: public Field getDeclaredField(String name);
参数name : 成员的名称
返回的类型是Field类, 在这个类里面有两个重要的方法:
• 取得属性内容: public Object get(Object obj);
参数obj: 实例化对象
• 设置属性内容: public void set(Object obj, Object value);
参数obj: 实例化对象
参数value: 参数内容
在AccessibleObject类下面:(jdk1.8之后修改)
• Executable: 下面继承了Constructor、 Method
• Field :
在这个类里面提供有一个方法:
• 设置是否封装: public void setAccessible(boolean flag)
反射调用属性:
class Book{
private String title;
}
public class TestClazz {
public static void main(String[] args)throws Exception {
Class<?> clazz = Class.forName("com.feng.Clazz.Book");
Object obj = clazz.newInstance();//必须给出实例化对象
Field field = clazz.getDeclaredField("title");
//封装取消应该设置在赋值之前
field.setAccessible(true);
field.set(obj, "Java开发");
System.out.println(field.get(obj));
}
}
构造方法和普通方法也同样可以取消封装,只不过很少这样去做,而且对于属性的访问还是建议使用setting和getting方法完成;
总结:
1. 实例化对象的方式又增加了一种反射
2. 反射调用类结构只是开始

浙公网安备 33010602011771号