一、反射
运行
过程中对类进行解剖并操作
类中的方法,属性,构造方法等成员。反射操作的统一步骤:
2.1 得到Class
//1.得到类的Class对象:类名.class
Class clazz = Person.class;
//1.得到类的Class对象:对象.getClass()
Person person = new Person();
Class clazz = person.getClass();
//1.得到类的Class对象:Class.forName()
Class clazz = Class.forName("com.itheima._01reflect.Person");
//获取全限定类名
String name = clazz.getName();
System.out.println("全限定类名是:" +name);
//获取简单类名
String simpleName = clazz.getSimpleName();
System.out.println("简单类名是:" + simpleName);
//生成类的实例对象
Object object = clazz.newInstance();
System.out.println(object);
2.2 得到并操作Constructor(反射) class软件包 java.lang
生成一个类的实例对象,不是通过普通的new方式,而是通过反射
/**
* 反射调用Person的无参构造(public),得到一个Person对象
*/
@Test
public void test1() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取类的Class对象
Class<Person> clazz = Person.class;
//获取到构造方法:无参构造,public
Constructor<Person> constructor = clazz.getConstructor();
//生成类实例对象
Person person = constructor.newInstance();
System.out.println(person);
}
/**
* 反射调用Person的有参构造(private),得到一个Person对象
*/
@Test
public void test2() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取Class对象
Class<Person> clazz = Person.class;
//获取到构造方法:有参构造,private
Constructor<Person> constructor = clazz.getDeclaredConstructor(String.class, Integer.class);
//暴力反射
constructor.setAccessible(true);
//生成类实例对象
Person person = constructor.newInstance("老王", 45);
System.out.println(person);
}
2.3 得到并操作Method(反射)
(自己的和父类的)
Person person1 = new Person();
//获取方法Method对象
Method method = clazz.getMethod("eat", String.class);
//反射调用方法
Object result = method.invoke(person1, "榴莲");
/**
* 反射调用Person的eat方法:public,有参String
* Person person1 = new Person();
* Person person2 = new Person();
*
* person1.eat("..");
*/
@Test
public void test1() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Person person1 = new Person();
Person person2 = new Person();
//获取Class对象 ctrl+alt+v
Class<Person> clazz = Person.class;
//获取方法Method对象
Method method = clazz.getMethod("eat", String.class);
//反射调用方法
Object result = method.invoke(person1, "榴莲");
System.out.println("方法执行的返回值:" + result);
}
/**
* 反射调用Person的sleep方法,private,有参String
*/
@Test
public void test2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Person person1 = new Person();
Person person2 = new Person();
//获取Class对象
Class<Person> clazz = Person.class;
//获取到方法Method对象
Method method = clazz.getDeclaredMethod("sleep", String.class);
//设置允许暴力反射
method.setAccessible(true);
//反射调用method方法
Object result = method.invoke(person2, "老王");
System.out.println("方法执行的返回值:" + result);
}
2.4 得到并操作Field(反射)
/*
* 反射获取所有的属性值
*/
@Test
public void test1() throws IllegalAccessException {
Person person1 = new Person();
person1.setName("坤坤");
person1.setAge(18);
Person person2 = new Person();
person2.setName("凡凡");
person2.setAge(24);
//获取Class对象
Class<Person> clazz = Person.class;
//获取所有的属性Field
Field[] fields = clazz.getDeclaredFields();
//循环遍历
for (Field field : fields) {
field.setAccessible(true);
//获取每个属性的值
Object value = field.get(person1);
//输出属性名称和属性值 // name 坤坤
String fieldName = field.getName(); // age 18
System.out.println("属性名:" + fieldName + ", 属性值:" + value);
}
}
/**
* 反射设置Person的所有属性值
* 给name属性设置值:晗晗
* 给age属性设置值:26
*/
@Test
public void test2() throws NoSuchFieldException, IllegalAccessException {
Person person = new Person();
//获取Class对象 注意getClass
Class<? extends Person> clazz = person.getClass();
//给name设置属性值:晗晗
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(person, "晗晗");
//给age设置属性值:26
Field ageField = clazz.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(person, 26);
System.out.println(person); //Person[name='晗晗' , age='26']
}
1.7.2 编写一个工厂方法可以根据配置文件产任意类型的对象。
例如有配置文件stu.properties,存储在项目的src文件夹下,内容如下:
根据配置文件信息创建一个学生对象
class=com.itheima._02test1.Student //stu.properties文件内容
name=jack
gender=\u7537
age=21
/**
* 根据配置文件里的信息,生成指定的对象
*/
public class DemoFactory {
public static void main(String[] args) throws Exception {
//1.读取配置文件 流读取文件
Properties properties = new Properties();
InputStream inputStream = DemoFactory.class.getClassLoader().getResourceAsStream("stu.properties");
properties.load(inputStream);
//2.从配置文件里得到类名,生成类的实例对象
String className = properties.getProperty("class");
Class<?> clazz = Class.forName(className);
Object object = clazz.newInstance();
//3.反射设置属性值:可以获取clazz里所有的field,也可以获取配置文件里所有的key
Set<String> names = properties.stringPropertyNames();
for (String fieldName : names) {
if ("class".equals(fieldName)) { //不获取class属性名
continue;
}
String fieldValue = properties.getProperty(fieldName); //三个属性值
//获取Field对象
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
//设置field的属性值
Class<?> fieldType = field.getType(); //属性类型 string string integer
if (fieldType == Integer.class) {
field.set(object, Integer.parseInt(fieldValue));
}else{
field.set(object, fieldValue);
}
}
//4.把设置好的实例对象,输出显示
System.out.println(object);
}
}
//使用beanUtils省略上面代码 第3步
BeanUtils.setProperty(object, fieldName, fieldValue);
BeanUtils.setProperty(student, "age", "20");
1. BeanUtils简介 封装上面工厂方法
案例演示
1. 什么是注解
1.1 注解简介
1.2 注解作用和JDK里常见的注解
压制警告
,idea/eclipse不会显示警告信息现在不能完全代替
2. 自定义注解
2.1 注解的定义语法
@元注解
public @interface 注解名{
属性类型 属性名称() default 默认值;
}
int age() default 18; // 年龄
2.2 元注解
public class Demo02MyAnnotationTest {
public static void main(String[] args) throws NoSuchMethodException {
//获取Class对象
Class<Demo02MyAnnotationTest> clazz = Demo02MyAnnotationTest.class;
//获取method1的方法对象
Method method = clazz.getMethod("method1", String.class);
//判断方法上是否有指定的注解 保留在什么阶段
boolean b = method.isAnnotationPresent(Demo02MyAnnotation.class);
System.out.println("method1方法上是否有注解Demo02MyAnnotation:" + b); //true 或false
}
2.2 属性
3. 注解的使用
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Demo02MyAnnotation {
String str()
int number()
} 写法 @Demo02MyAnnotation(str = "hello, world", number = 10)
4. 注解的解析(了解)
使用反射获取注解的数据 案例
模拟Junit测试的@Test 案例