反射
反射的原理
每一个类都是大Class的一个对象,记录了其属性和方法,在加载类时,存放在class区
每个类的Class对象只有一个
通过Class对象可以用于动态创建不同对象
反射使用
获取Class对象 Class.forName
对象.getclass
类名.class
Class clazz = Class.forName(“全类名”); 点击类名复制 quick copy
newInstance(); 直接创建对象,用无参
getsuperclass;父类的Class对象 只有一个
getInterfaces ; 接口的Class对象 多个
getName 全类名
getsimplename 类名
getpackage 包名
构造方法获取 getConstructor
getDeclaredConstructors (); 所有的构造方法
c=clazz.getDeclaredConstructor (参数列表 大Class对象); 单个构造方法
Constructor c = clazz.getConstructor(String.class,int.class) //表明参数为String的有参构造
创建对象 newInstance
Object o = c.newInstance(); 虽然本质是Person类型,但返回的是Object类型
Object o = c.newInstance(”zhangsan“,15); 有参构造
access 访问 modifies 修饰符 解除私有 c.setAccessiable(true);
变量获取及赋值 getField set
getFields 所有public修饰的包括父类的
getDeclaredFields 所有变量 不包括父类的
getDeclaredField
f=clazz.getDeclaredField(变量名)
f=clazz.getDeclaredField(“name”)
f.set(o,“zhangsan”) //给对象o进行赋值
f.set(null,14) //静态变量,可以不用对象
方法获取及调用 method invoke
getMethods 所有public修饰的方法 包括父类
getDeclaredMethods 本类中所有方法
getDeclaredMethod
m=clazz.getDeclaredMethod(”方法名“,参数列表 大Class对象)
m.invoke(o) //对象o调用无参无返回值的方法m
m.invoke(o,12,15) //对象o调用两个int参数的方法m
Object o = m.invoke(o,“name”) //对象o调用一个String参数的方法m,返回类型为Object
m.invoke(null,12,4); //调用静态方法,参数为两个int,无返回值
public class Test1 {
public static void main(String[] args) throws Exception {
Class<?> c = Class.forName("fanshe.User");
User user = (User) c.newInstance();
user.setName("han");
System.out.println(user);
Constructor<?> con2 = c.getDeclaredConstructor(String.class, int.class);
User user2 = (User) con2.newInstance("hanyakun", 22);
System.out.println(user2);
Constructor<?> con3 = c.getDeclaredConstructor(String.class, int.class, String.class);
con3.setAccessible(true);
User user3 = (User) con3.newInstance("gaiku", 99, "nna");
System.out.println(user3);
Field[] declaredFields = c.getDeclaredFields();
Field age = c.getDeclaredField("age");
age.set(null, 15); // 静态变量,可以不用对象
Field name = c.getDeclaredField("name");
name.setAccessible(true);
Object ob = c.newInstance();
name.set(ob, "kk");
System.out.println(ob);
Method[] declaredMethods = c.getDeclaredMethods();
Method m = c.getDeclaredMethod("setName", String.class);
Object invoke = m.invoke(ob, "linghu");
Method m3 = c.getDeclaredMethod("getName", null);
Object invoke2 = m3.invoke(ob, null);
System.out.println(invoke2);
System.out.println(ob);
Method m2 = c.getDeclaredMethod("mkoe", null);
m2.invoke(ob, null);
}
}
class User {
private String name;
static int age = 0;
private String gender;
private User(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + ", gender=" + gender + "]";
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public User() {
super();
// TODO Auto-generated constructor stub
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public void mkoe() {
System.out.println("这是mkoe 方法");
}
}
例题
1. 在ArrayList类型中添加整型元素
思考: 范型只对编译有作用,可以使用add() 方法所在类的反射调用add方法,可以躲过编译,
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class Testtttttt {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
ArrayList<String> list = new ArrayList<>();
list.add("abb");
Class clazz = list.getClass();
Method m = clazz.getMethod("add", Object.class);
m.invoke(list, 1234);
m.invoke(list, 34);
System.out.println(list);
}
}
- 通过配置文件解偶合
需求:在子类中将Teacher类升级为SuperTeacher,但不能改动Teacher,因为改动Teacher会对程序进行大的修改,
思考:只需要将Teacher实现接口,在创建Teacher时用反射的方法,使用接口去调用方法,不需要对程序中的类进行更改
import java.io.IOException;
import java.util.Properties;
public class Test {
public static void main(String[] args) throws Exception {
//创建properties对象,从配置文件读取对应的全类名
Properties p = new Properties();
p.load(Test.class.getClassLoader().getResourceAsStream("config.properties"));
String property = p.getProperty("tea");
//得到Class对象,创建对象o;通过转型,得到接口对象,调用Teacher子类的show方法
Class clazz = Class.forName(property);
Object o = clazz.newInstance();//o本质为Teacher 即父类引用指向子类对象
Teachable teach = (Teachable) o; //将Teacher转型为接口对象,多态,调用子类的方法
//不转成teacher对象,是不想对某个类进行修改
teach.show();
}
}
interface Teachable {
void show();
}
class Teacher implements Teachable {
@Override
public void show() {
System.out.println("超级老师,能上天的那种");
}
}