反射是各类框架实现的核心,框架开发原理=反射机制+xml解析。

一、反射机制含义

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

二、反射机制四种功能

1.类

(1)判断任意一个对象是否属于某个类(找到对象对应的类);

Date date = new Date();
		Class<?>classs = date.getClass();
		System.out.println(classs);

运行结果:class java.util.Date

(2)运行时构造某个类的一个对象。

tip:实例化对象由两种方式:一种关键字new,另一种反射实现

public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException{

		Class<?>cls = Class.forName("Book");
		Book book = (Book) cls.newInstance();
		book.setName("云边有个小卖部");
		book.setPrice(20.00);
		System.out.println(book);
}

class Book{
	private String name;
	private double price;

	public String getName() {
		return name;
	}

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

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	@Override
	public String toString() {
		return "Book{" +
				"name='" + name + '\'' +
				", price=" + price +
				'}';
	}
}

运行结果:Book{name='云边有个小卖部', price=20.0}

2.对象

(3)判断任意一个对象具有的属性和方法;

(4)运行时调用任意一个对象的方法。

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

public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException{

		Class<?>cls3 = Class.forName("Book");
		String fieldName1 = "name";
		String fieldName2 = "price";
		String nameValue = "语文";
		Double priceValue = 30.00;
		Object obj = cls3.newInstance();
		Method  setMethod1 = cls3.getMethod("set"+ initcap(fieldName1),String.class);
//		System.out.println(initcap(fieldName1));
		Method  setMethod2 = cls3.getMethod("set"+ initcap(fieldName2),double.class);
		Method 	getMethod1 = cls3.getMethod("get"+ initcap(fieldName1));
		Method 	getMethod2 = cls3.getMethod("get"+ initcap(fieldName2));
		setMethod1.invoke(obj,nameValue);
		setMethod2.invoke(obj,priceValue);
		System.out.println(getMethod1.invoke(obj));
		System.out.println(getMethod2.invoke(obj));
}

class Book{
	private String name;
	private double price;

	public String getName() {
		return name;
	}

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

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

运行结果:语文    30.0

三、反射机制好处

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

下面通过传统的工厂模式说明反射机制的好处。

代码实例:

public class Test2 {
    public static void main(String[] args) {
        Books bk = Factory.getInstance("MathBook");
        System.out.println(bk.getName());
        Books bkk = Factory.getInstance("EnglishBook");
        System.out.println(bkk.getName());
    }
}
interface Books{
    public String getName();
}

class MathBook implements Books{

    @Override
    public String getName() {
        return "数学书";
    }
}
class YuwenBook implements Books{


    @Override
    public String getName() {
        return "语文书";
    }
}
class EnglishBook implements Books{


    @Override
    public String getName() {
        return "英语书";
    }
}
class Factory{
    public static Books getInstance(String className){
        if ("MathBook".equals(className)) {
            return new MathBook();
        }else if ("YuwenBook".equals(className)) {
            return new YuwenBook();
        }
        return null;
    }
}

}

运行结果:

java 反射实际用途 java反射作用与意义_java

 可以看到如果需要添加Books的子实现类,则需要修改整个工厂类,这样会导致高耦合。

调整后工厂类代码:

class Factory2{
    public static Books getInstance(String className){
        Books books = null;
        try {
            books = (Books)Class.forName(className).newInstance();

        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return books;
    }

}

运行结果:

数学书
英语书

可见,无需修改工厂类,新增Books子类后,依旧可以正确生成子类实例。

四、有参构造和无参构造的不同反射实例化方式

无参:


Class<?>cls = Class.forName("Book"); Book book = (Book) cls.newInstance();


有参:


Class<?> cls2 = Class.forName("Fruit"); Constructor<?>cons = cls2.getConstructor(String.class,String.class); Fruit fruit = (Fruit) cons.newInstance("苹果","apple");


//反射实例化对象:只有无参构造方法,没有有参构造
		Class<?>cls = Class.forName("Book");
		Book book = (Book) cls.newInstance();
		book.setName("云边有个小卖部");
		book.setPrice(20.00);
		System.out.println(book);

		//反射实例化对象,有有参构造
		Class<?> cls2 = Class.forName("Fruit");
//		Constructor<?>cons = cls2.getDeclaredConstructor(String.class,String.class);
		Constructor<?>cons = cls2.getConstructor(String.class,String.class);
		Fruit fruit  = (Fruit) cons.newInstance("苹果","apple");
		System.out.println(fruit);

class Book{
		private String name;
		private double price;

		public String getName() {
			return name;
		}

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

		public double getPrice() {
			return price;
		}

		public void setPrice(double price) {
			this.price = price;
		}

		@Override
		public String toString() {
			return "Book{" +
					"name='" + name + '\'' +
					", price=" + price +
					'}';
		}
	}
	class Fruit{
		private String name;
		private String EnName;

		public Fruit(String name, String enName) {
			this.name = name;
			EnName = enName;
		}

		public String getName() {
			return name;
		}

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

		public String getEnName() {
			return EnName;
		}
	public void setEnName(String enName) {
		EnName = enName;
	}

	@Override
	public String toString() {
		return "Fruit{" +
				"name='" + name + '\'' +
				", EnName='" + EnName + '\'' +
				'}';
	}
}

如果存在有参构造方法,依旧使用无参时候的实现方式,会出现如下异常:

实例:

Class<?> cls2 = Class.forName("Fruit");
		Fruit fruit1 = (Fruit) cls2.newInstance();
		fruit1.setName("香蕉");
		fruit1.setEnName("bananna");
		System.out.println(fruit1);

运行结果:

java 反射实际用途 java反射作用与意义_java_02

 所以:类中提供无参构造方法会更加方便一些,这一点就是在简单Java类之中要求提供无参构造的关键因素。