一、什么是反射?反射就是可以不用通过 new 对象的方式来获的对象。
第一种方式
public class 鞠婧祎 {
public static void main(String[] args) {
Class<?> cls = 鞠婧祎.class;
鞠婧祎 kiku = (鞠婧祎) cls.newInstance();
}
}
第二种方式
public class 刘亦菲 {
public static void main(String[] args) {
String className = "com.yifei.刘亦菲";
Class<?> cls = Class.forName(className);
刘亦菲 yi = (刘亦菲) cls.newInstance();
}
}
第三种方式
public class 陈钰琪 {
public static void main(String[] args) {
String className = "com.yukee.陈钰琪";
Class<?> cls = Class.forName(className);
Constructor<?> constructor = cls.getConstructor();
陈钰琪 yukee = (陈钰琪) constructor.newInstance();
}
}
第四种方式
public class 景甜 {
public static void main(String[] args) {
String className = "com.tian.景甜";
Class<?> cls = Class.forName(className);
Constructor<?> constructor = cls.getDeclaredConstructor();
景甜 tian = (景甜) constructor.newInstance();
}
}
二、它们之间的区别
- 第一种与第二种的 newInstance:只能调用目标对象非私有的无参构造方法(即非 private),如果构造方法的修饰符非 public,那么 newInstance 必须遵守访问控制符的访问权限,否则会抛出异常
- 第三种的 newInstance:可以获取无参、也可以获取有参的构造方法,构造方法的修饰符必须是 public,否则会抛出异常
- 第四种的 newInstance:可以获取无参、也可以获取有参的构造方法,这种方式是可以获取目标对象类的私有属性(方法和变量),它还可以不用遵守访问控制符的访问权限
- 注意:如果获取有参构造方法,则 newInstance 方法必须传参,反之则亦然
- 访问控制符的访问权限可以查看此篇文章:Java 里 private,protected,private,default 的区别
三、基于上述第三、四种方式扩展获取有参的构造方法,两者很类似
第三种方式
public class 林允儿 {
public 林允儿(String name) {
System.out.println("姓名:" + name);
}
public 林允儿(String name, int age) {
System.out.println("姓名:" + name + ",年龄:" + age);
}
public static void main(String[] args) {
String className = "com.yoona.林允儿";
Class<?> cls = Class.forName(className);
Constructor<?> constructor = cls.getConstructor(String.class);
林允儿 yoona = (林允儿) constructor.newInstance("你需要传入的参数值");
Constructor<?> constructor = cls.getConstructor(String.class, int.class);
林允儿 yoona = (林允儿) constructor.newInstance(new Object[] {"林允儿", 18});
}
}
第四种方式
public class 徐艺洋 {
public 徐艺洋(String name) {
System.out.println("姓名:" + name);
}
public 徐艺洋(String name, int age) {
System.out.println("姓名:" + name + ",年龄:" + age);
}
public static void main(String[] args) {
String className = "com.yiyang.徐艺洋";
Class<?> cls = Class.forName(className);
Constructor<?> constructor = cls.getDeclaredConstructor(String.class);
徐艺洋 yiyang = (徐艺洋) constructor.newInstance("徐艺洋");
Constructor<?> constructor = cls.getDeclaredConstructor(String.class, int.class);
徐艺洋 yiyang = (徐艺洋) constructor.newInstance(new Object[] {"徐艺洋", 18});
}
}
- 私有属性对于类外是不可见的,通过反射可以获取到,但是可能会破坏单例模式,解决方案:做个标记记录次数,当第二次调用私有构造方法的时候抛出异常即可
四、通过反射获取指定方法(包含私有)
public class 程潇 {
public void
public static void main(String[] args) {
String className = "com.xiao.程潇";
Class<?> cls = Class.forName(className);
Constructor<?> con = cls.getConstructor();
Constructor<?> con = cls.getDeclaredConstructor();
程潇 xiao = (程潇) con.newInstance();
Method method = cls.getMethod("程潇");
Method method = cls.getDeclaredMethod("程潇");
Method method = cls.getMethod("程潇", String.class);
Method method = cls.getDeclaredMethod("程潇", String.class);
Object o = method.invoke(xiao);
Object o = method.invoke(xiao, "程潇");
}
}
五、通过反射获取变量(包含私有)
public class 周洁琼 {
public void
public static void main(String[] args) {
String className = "com.jieqiong.周洁琼";
Class<?> cls = Class.forName(className);
Constructor<?> con = cls.getConstructor();
Constructor<?> con = cls.getDeclaredConstructor();
周洁琼 zjq = (周洁琼) con.newInstance();
Field field = cls.getField("name");
Field field = cls.getDeclaredField("name");
Object o = field.get(zjq);
}
}
六、拓展
- cls.getConstructors(),获取所有修饰符为 public 的构造方法,返回一个 Constructor 数组
- cls.getDeclaredConstructors(),获取所有的构造方法,包含私有的,返回一个 Constructor 数组
- cls.getMethods(),获取所有的 public 的普通方法,返回一个 Method 数组。
- cls.getDeclaredMethods(),获取所有的普通方法,包含私有的,返回一个 Method 数组。
- cls.getFields(),获取所有的 public 成员变量,返回一个 Field 数组。
- cls.getDeclaredFields(),获取所有的成员变量,包含私有的,返回一个 Field 数组。