1、反射
Java的反射机制是在运行的状态中,对于任意的一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,能够调用它的任意一个属性和方法,这种动态获取的信息以及动态调用对象的方法的功能成为java语言的反射机制。
简单一句话,反射技术可以对类进行解剖。
为什么要对类进行解剖?应用场景是什么。
我们能随便对已经发布的一个类的代码做出改动吗?如果没有源码怎么办?
被反射的类一般都需要具备特定的规则,反射才有意义。反射技术的出现大大提高了程序的可扩展性。
通过Class类的forName()方法获取
package com.aishang.day14;
public class Demo {
public static void main(String[] args) throws ClassNotFoundException {
// 只要知道类名即可,不需使用该类和对象,有利于扩展
// 需要传入一个字符串,就是全限定类名(全限定类名:包名+类名)
// 你写的类名不一定对,所以抛异常
Class<?> clazz = Class.forName("com.aishang.day14.Person");
System.out.println(clazz);
}
}
2、对象实例的获取
传统创建对象的方式new
如果不知道这个类,那么就需要用反射
通过class类中的newInstance()创建
package com.aishang.day14;
public class Demo {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
// 只要知道类名即可,不需使用该类和对象,有利于扩展
// 需要传入一个字符串,就是全限定类名(全限定类名:包名+类名)
// 你写的类名不一定对,所以抛异常
Class<?> clazz = Class.forName("com.aishang.day14.Person");
Object obj = clazz.newInstance(); //相当于创建对象,默认调用了构造方法
// 以上过程相当于: Person p =new Person();
System.out.println(obj);//Person [name=null, age=0]
}
}
获取所有构造方法
package com.aishang.day14;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Demo {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.aishang.day14.Person");
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> c : constructors) {
System.out.println(c);
}
}
}
调用非默认的构造器
之前我们是通过new的方式,创建对象时进行调用构造方法
Person person = new Person("tom",18);
现在使用反射方式,通过构造方法创建对象
- 调用的无参构造
package com.aishang.day14;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Demo {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.aishang.day14.Person");
Constructor<?> constructor = clazz.getConstructor();
Object obj = constructor.newInstance();
System.out.println(obj);
}
}
- 调用有参构造
package com.aishang.day14;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Demo {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.aishang.day14.Person");
// 指定参数
Constructor<?> constructor = clazz.getConstructor(String.class,int.class);
Object obj = constructor.newInstance("tom",18);
System.out.println(obj);
}
}
只能获取公有构造方法,把一个构造方法改成私有
package com.aishang.day14;
public class Person {
private String name;
private int age;
private Person() {
System.out.println("Person 构造方法运行");
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
public static void show() {
System.out.println("static show run");
}
public String eate(String a, int b) {
String res = a + b;
System.out.println("function param:" + a + "." + b);
return res;
}
private void privateShow() {
System.out.println("private show run...");
}
}
Class<?> clazz = Class.forName("com.aishang.day12.Person");
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
这时只能获取公有的构造方法
获取所有构造方法
package com.aishang.day14;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Demo {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.aishang.day14.Person");
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
//这个方法会返回制定参数类型的所有构造器,包括public的和非public的,当然也包括private的。
for (Constructor<?> c : constructors) {
System.out.println(c);
}
}
}
把构造方法全部私有,接着通过有参构造创建对象
package com.aishang.day14;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Demo {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.aishang.day14.Person");
Constructor<?> c = clazz.getDeclaredConstructor(String.class,int.class);
Object obj = c.newInstance("tom",18);
System.out.println(obj);
}
}
报错:无效访问异常,因为构造方法私有。
通过私有构造方法创建对象,需要取消访问权限
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.aishang.day14.Person");
Constructor<?> c = clazz.getDeclaredConstructor(String.class,int.class);
c.setAccessible(true);
Object obj = c.newInstance("tom",18);
System.out.println(obj);
}
3、字段获取
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.aishang.day14.Person");
// Field[] fields = clazz.getFields();获取的是公有的
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
}
获取指定字段
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.aishang.day14.Person");
Field age = clazz.getDeclaredField("age");
System.out.println(age);
}
成员变量赋值:通过反射,使成员变量映射到对象上
package com.aishang.day16;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class Demo1 {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.aishang.day16.Person");
Object obj = clazz.newInstance();
Field name = clazz.getDeclaredField("name");
name.setAccessible(true);
Field age = clazz.getDeclaredField("age");
age.setAccessible(true);
name.set(obj, "jerry");
age.set(obj, 18);
System.out.println(obj);
System.out.println(name.get(obj));
}
}
4、获取方法
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.aishang.day14.Person");
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method);
}
}
获取指定方法
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.aishang.day14.Person");
Method m = clazz.getDeclaredMethod("eate", String.class,int.class);
System.out.println(m);
}
调用方法
package com.aishang.day14;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Demo {
public static void main(String[] args) throws Exception {
/*
* Person p = new Person(); p.eate("tom",18);
*/
Class<?> clazz = Class.forName("com.aishang.day14.Person");
Constructor<?> c = clazz.getDeclaredConstructor();
c.setAccessible(true);
Object obj = c.newInstance();
Method m = clazz.getDeclaredMethod("eate", String.class, int.class);
//调用方法,反射到对象上
m.invoke(obj, "tom", 18);
}
}
调用无参方法
package com.aishang.day14;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Demo {
public static void main(String[] args) throws Exception {
/*
* Person p = new Person(); p.eate("tom",18);
*/
Class<?> clazz = Class.forName("com.aishang.day14.Person");
Constructor<?> c = clazz.getDeclaredConstructor();
c.setAccessible(true);
Object obj = c.newInstance();
Method m = clazz.getDeclaredMethod("eate", String.class, int.class);
//调用方法,反射到对象上
Object invoke = m.invoke(obj, "tom", 18);
Method m1 = clazz.getDeclaredMethod("privateShow");
m1.setAccessible(true);
m1.invoke(obj);
}
}
调用静态方法:静态没有对象,但是参数要求必须映射上,所以可以用null代替
public static void main(String[] args) throws Exception {
/*
* Person p = new Person(); p.eate("tom",18);
*/
Class<?> clazz = Class.forName("com.aishang.day15.Person");
Method m = clazz.getMethod("show");
m.invoke(null);
// 没有参数可以用null代替 m.invoke(null, null);
}