1、反射的概念和作用
反射是Java的一个重要特征。反射是指在运行时动态加载类(获取Class对象)、获取类信息(如获取字段,方法,构造器等信息)、生成对象、操作对象的属性或方法。
Java中反射需要用到 java.lang.Class 和 java.lang.reflect包下面的类。
2、类加载的方式
类加载相当于Class对象的加载,类在第一次运行时才加载到JVM
反射可以提供运行时的类信息,并且这个类可以在运行时才加载进来,甚至在编译时该类的.class文件不存在也可以加载进来
类加载有以下几种方式
(1)Class.forName(类的权限定名即“包名.类名”)
(2)类名.Class
(3)对象名.getClass()
3、获取类信息
Class类的方法:
public String getName() 返回类的名称:“包名.类名”
public Field getField(String name) 获取所有public字段信息
public Field[] getDeclaredFields() 获取所有字段信息
public Method[] getMethods() 获取所有public的Method对象
public Method[] getDeclaredMethod() 获取所有定义的Method对象
public Constructor[] getConstructors() 获取所有public的Constructor对象
public Constructor[] getDeclaredConstructors() 获取所有已定义的Constructor对象
4、利用反射创建对象的方式
(1)获取Class对象clazz,调用clazz对象的newInstance()方法创建对象; 该方法要求相应的类中必须有无参数的构造方法
(2)获取Class对象clazz,调用clazz对象的getConstructors()方法获取所有的构造器数组。选择数组中特定的构造器对象,调用构造器对象的newInstance(xx,xxx)方法,传入构造器所需的参数创建对象
5、获取对象属性,调用对象方法
public class Student {
public String height;
private double weight;
public Student(){}
public Student(String height, double weight) {
super();
this.height = height;
this.weight = weight;
}
public void print(){
System.out.println("调用print方法...");
}
public char getSex(int num){
return num==1?'m':'f';
}
}
public class Test {
public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class clazz = Student.class;
Student obj = (Student) clazz.newInstance();
//获取public属性
Field f1 = clazz.getField("height");
f1.set(obj, "173");
System.out.println(f1.get(obj));;
//获取private属性
Field f2 = clazz.getDeclaredField("weight");
f2.setAccessible(true);
f2.set(obj, 56);
System.out.println(f2.get(obj));
//获取方法
Method m1 = clazz.getMethod("print");
m1.invoke(obj);
//获取带参数方法
Method m2 = clazz.getMethod("getSex", int.class);
char a = (char) m2.invoke(obj, 1);
System.out.println("性别:"+a);
}
}
6、反射的应用
(1)反射的一个简单应用-- 简单工厂设计模式中
简单工厂设计模式是工厂方法模式的缩小版,先介绍工厂方法模式
(i)工厂方法模式:工厂方法模式是一个创建型设计模式,他的定义是“定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法时一个类的实例化延迟到其子类。”
简单地说,是可以动态的实例化某个接口下的任何实现类。工厂方法模式应用了反射的设计思想。
(a)组成: AbstractFactory,ConcreateFactory, Product, ConcreateProduct1,ConcreateProduct2…
(b)代码:
//抽象工厂
public abstract class AbstractFactory {
public abstract <T extends Product>T createProduct(Class<T> clazz);
}
//具体工厂
public class ConcreateFactory extends AbstractFactory {
@Override
public <T extends Product> T createProduct(Class<T> clazz) {
Product product = null;
try {
product = (Product) Class.forName(clazz.getName()).newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return (T)product;
}
}
//待生产的产品抽象类
public abstract class Product {
public void method1(){
//具体方法
}
//抽象方法
public abstract void method2();
}
//被生产的具体产品1
public class ConcreateProduct1 extends Product {
@Override
public void method2() {
System.out.println("我是concreteProduct1...");
}
}
//被生产的具体产品2
public class ConcreateProduct2 extends Product {
@Override
public void method2() {
System.out.println("我是concreteProduct2...");
}
}
//场景类
public class Client {
public static void main(String[] args) {
AbstractFactory factory = new ConcreateFactory();
ConcreateProduct1 product1 = factory.createProduct(ConcreateProduct1.class);
product1.method2();
ConcreateProduct2 product2 = factory.createProduct(ConcreateProduct2.class);
product2.method2();
}
}
(c)优点及应用
优点:
(1)具有良好的封装性、代码结构清晰;
(2)对象创建是有条件约束的(需要传入class对象,或类的权限定名称字符串)
(3)解耦合:降低了调用方和被调用方的耦合
应用
(1)根据不同的数据库,JDBC可以加载不同的驱动
(2)spring中的IOC
(ii)简单工厂设计模式是工厂方法设计模式的缩小版,主要区别是无需抽象工厂,直接提供一个具体地工厂,且提供静态的创建产品的方法
代码如下:
//具体地工厂,提供一个静态的用于创建产品的方法
public class ConcreateFactory {
public static <T extends Product>T createProduct(Class<T> clazz){
Product product = null;
try {
product = (Product) Class.forName(clazz.getName()).newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return (T)product;
}
}
//场景类
public class Client {
public static void main(String[] args) {
ConcreateProduct1 product1 = ConcreateFactory.createProduct(ConcreateProduct1.class);
product1.method2();
ConcreateProduct2 product2 = ConcreateFactory.createProduct(ConcreateProduct2.class);
product2.method2();
}
}
(2)spring框架中的依赖注入和控制反转
spring框架中,用了工厂方法来完成控制反转的功能,而工厂方法应用了反射,故spring中也应用了反射机制。