个人理解反射可以不通过new这个关键字产生一个指定的类,并可以调用成员变量,普通方法,构造方法等。
首先看一个代码例子
import java.util.Date;
/**
* 反射取得实例化对象的三种方式
* @author 76519
*
*/
public class TestDemo1 {
public static void main(String[] args) {
//方式一 需要先实例化类 再反射
Date date = new Date();
//此处的泛型 只能是 "?"
Class<?> dts = date.getClass();
//System.out.println(dts);
System.out.println(dts.getName());
//方式二 不需要实例化 但需要引入包----import java.util.Date;
Class<?> dts2 = Date.class;
System.out.println(dts2.getName());
//方式三 不需要实例化操作 也无需引入包
try {
//根据类名称(全路径名) 反射到类
Class<?> dts3 = Class.forName("java.util.Date");
System.out.println(dts3.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//总结:
//除了方式一会产生实例化对象之外 其他两种都不会产生实例化对象
}
}
从例子中可以看出,获取一个反射后的对象有三种方式:
|-实例化对象.getClass(); 此方法需要先实例化对象 并导入类的路径 也就是需要先new
|-对象.class;//无需实例化对象 但必须导入类的路径
|-Class.forName("类的全路径"); 无需导入类的路径,因为此时forName中写的就是全路径(包名.类名)
取得一个反射后的类后,可以通过实例化操作,获得此类的操作权。
例子:取得实例化对象
/**
* 取得实例化对象就意味着取得了一个 指定类 的 操作权
* @author 76519
*
*/
public class TestDemo {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("java.util.Date");//使用字符串描述使用的类
//反射出的对象 采取 newInstance() 进行实例化
Object obj = cls.newInstance();//实例化对象,等价于:new java.util.Date
System.out.println(obj);
//Object类型 向下 转型
Date date = (Date) obj;
System.out.println(date.getTime());
}
}
Thu Aug 23 10:48:38 CST 2018
1534992518173
上面是运行结果,newInstance()方法是java.lang.Class的方法,专用于反射类的实例化对象的创建。返回的是一个Object类型,直接打印Object类型的变量是调用了他的toString(),也就是打印的时间。下面的getTime()方法是java.util.Date的方法,Object中不存在,所以需要向下转型。
此处的代码有个很严重的细节问题,就是"被反射"的类中必须有无参构造(或无参构造不是public修饰的!),下面看个没有无参构造时产生的问题
例子:没有无参引发的血案
class Humen{
private String userName;
private int age;
//无参构造
//public Humen() {}
//有参构造
public Humen(String userName,int age) {
this.userName = userName;
this.age=age;
}
@Override
public String toString() {
return "Humen [userName=" + userName + ", age=" + age + "]";
}
}
/**
* 无参的重要性
* @author 76519
*/
public class TestDemo3 {
public static void main(String[] args) throws Exception{
Class<?> humenCls = Humen.class;
//当没有无参构造时
//java.lang.NoSuchMethodException: refelect.第二天.Humen.<init>()
System.out.println(humenCls.newInstance());
}
}
运行下,出现如下问题:
Exception in thread "main" java.lang.InstantiationException: refelect.Humen
at java.lang.Class.newInstance(Unknown Source)
at refelect.TestDemo3.main(TestDemo3.java:29)
Caused by: java.lang.NoSuchMethodException: refelect.Humen.<init>()
at java.lang.Class.getConstructor0(Unknown Source)
... 2 more
有人会说到,如果没有无参构造,就不能实例化我获取的反射的类了么,答案是 不是! 有无参构造函数只是说实例化获取到的反射的类更加简单容易,下面我们看下没有无参构造的情况下,如何获取我们反射得到的类的实例化对象。
import java.lang.reflect.Constructor;
class Humen{
private String userName;
private int age;
//无参构造
//public Humen() {}
//有参构造
public Humen(String userName,int age) {
this.userName = userName;
this.age=age;
}
@Override
public String toString() {
return "Humen [userName=" + userName + ", age=" + age + "]";
}
}
/**
* 无参的重要性
* @author 76519
*/
public class TestDemo3 {
public static void main(String[] args) throws Exception{
Class<?> humenCls = Humen.class;
//当没有无参构造时
//java.lang.NoSuchMethodException: refelect.第二天.Humen.<init>()
//System.out.println(humenCls.newInstance());
//解决思路
//通过获取反射对象中的构造方法 实例化对象 --- 此处使用的方法是根据 指定类型获得指定的构造方法
Constructor<?> cons = humenCls.getConstructor(String.class,int.class);
//获取构造的对象 并 进行实例化
System.out.println(cons.newInstance("香蕉不拿拿先生",25));
}
}
这个方法是获取其他的有参构造方法,通过
java.lang.Class.getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
Class对象的getConstructor(Class<?>... parameterTypes)获取指定的构造方法,其中使用到了一个"可变参数"的类型,其实传递的就是一个参数类型的数组,可以是没有,1个或多个参数。
通过获取到指定的构造方法对象后,调用
java.lang.reflect.Constructor.newInstance(Object... initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
java.lang.reflect.Constructor的newInstance()进行获取反射的实例化对象!
相对于有无参构造函数来说,此方法太麻烦,所以开发中需要写类的无参构造-----我琢磨到这时,才发现无参构造的重要性。
通过以上的方法,我们现在可以利用反射获取到类的对象了,并通过调用其中的构造方法获取实例化对象。
注意:任何该类中的 普通方法 调用,都必须通过先实例化对象,再进行调用普通方法哦。
暂时先说在这吧,后续会继续做出总结