1.反射与Class类
-
Java本是静态语言,但反射提供了动态语言的特性,通过反射可以获得任意类的所有结构,并可以任意操作类内部的属性和方法 -
类加载完毕后,堆空间中会出现唯一的Class对象,这个对象clazz包含了该类的所有结构 -
Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的 -
通过反射的方式获取对象效率远远不如直接new,当且仅当不能直接new对象的时候用反射创建对象,在主流框架中大量使用了反射
2.Class对象获取
一个类的Class对象无论用什么方式获取多少次,都是唯一的
new 目标类().getClass()
-
不建议这样使用,已经可以直接new了就不要再反射获取对象了 -
new Student()的同时也会在堆空间产生全局唯一的Student类对象 Student stu1 = new Student();//这一new 产生一个Student对象,一个Class对象。 Class stuClass = stu1.getClass();//获取Class对象 System.out.println(stuClass.getName());
目标类.class;
这种方法也不推荐,需要额外在调用处导入目标类的包,依赖过强
//第二种方式获取Class对象
Class stuClass2 = Student.class;
forName()方法——最常用
一般都第三种,一个字符串可以传入也可写在配置文件中等多种方法。
//第三种方式获取Class对象
try {
Class stuClass3 = Class.forName("com.fanshe.Student");//全类名路径
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
基本数据类型和包装类
包装类.TYPE属性 相当于 基本数据类型.class属性
Class<Integer> c1 = int.class;
Class<Integer> c2 = Integer.TYPE;
System.out.println(c1==c2);//true
源码 @SuppressWarnings(“unchecked”) public static final Class TYPE = (Class) Class.getPrimitiveClass(“int”);
3.Class类常用方法
3.1静态方法
获取目标类的Class对象
3.2非静态方法
对于:Class c1 = Class.forName(“com.zjh.User”);
获取目标类实例
c1.newInstance()
获取目标类全类名路径
c1,getName()
获取父类的Class对象
c1.getSuperClass().getSuperClass()....可以一直链路向上调用
获取类的方法Method对象,invoke激活
不加Declared的getMethods()包括父类的方法
先获取Method对象(无参可以不填or填null),然后invoke调用方法
Class c1 = Class.forName("filter.User");
Method tell = c1.getMethod("tell", String.class);
Object content = tell.invoke(new User(), "说话内容");
System.out.println(content);//null无返回值
获取类的构造器
没有形参的就是获取所有,注意是否为s结尾复数,形参列表是Class对象; 没有Declared的就是只获取public修饰的
- 批量的方法:返回数组
public Constructor[] getConstructors():所有"公有的"构造方法 public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有) - 单个的方法,并调用:
public Constructor getConstructor(**Class… parameterTypes **):获取单个的"公有的"构造方法: public Constructor getDeclaredConstructor(Class… parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
调用时使用使用newInstance()
Class c1 = Class.forName("filter.User");
Constructor constructor = c1.getConstructor(String.class, int.class);
Object u = constructor.newInstance("牛逼", 12);
System.out.println(u);
获取类的属性
没有形参的就是获取所有,注意是否为s结尾复数,形参是String类型即指定获取某属性; 没有Declared的就是只获取public修饰的
- 批量的:
Field[] getFields():获取所有的"公有属性",包括父类 Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有; - 获取单个的:
public Field getField(String fieldName):获取某个"公有的"字段; public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)
————————————————————————————————————
如果使用getField(“name”)会由于私有属性抛java.lang.NoSuchFieldException: name
如果使用 Field name =c1.getDeclaredField(“name”);但是如果不 name.setAccessible(true); 就会抛异常 java.lang.IllegalAccessException
获取类的加载器
类的加载器分为:
c1.getClassLoader()
4.反射获取注解信息
4.1自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyValue {
//给字段赋值
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyTable {
//表名
String value();
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyController {
//URL
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyColumn {
//字段名绑定
String value();
}
4.2待绑定的Bean
@MyTable("table_people")
public class PeopleBean {
@MyValue("zjh")
@MyColumn("xx_name")
private String name;
@MyValue("18")
@MyColumn("xx_age")
private int age;
@Override
public String toString() {
return "PeopleBean{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
4.3测试
@MyController("/com/baidu/www")
public class MyTest {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.获取当前URL
Class<MyTest> c1 = MyTest.class;
MyController anno1 = c1.getAnnotation(MyController.class);
String value1 = anno1.value();
System.out.println("当前URL是:" + value1);
//2.反射获取PeopleBean,并用@value对其赋值
Class c2 = Class.forName("filter.PeopleBean");
PeopleBean people= (PeopleBean)c2.newInstance();
//3.PeopleBean直接获取的注解只有@MyTable
Annotation[] annotations = c2.getDeclaredAnnotations();
System.out.println("类级别的注解数:"+annotations.length);//1
//4.获取类中所有不包括父类的属性
Field[] fields = c2.getDeclaredFields();
for (Field f : fields) {
//@MyColumn绑定的字段信息
MyColumn column = f.getDeclaredAnnotation(MyColumn.class);
System.out.println(f.getName() + "绑定的表字段是:" + column.value());
//@MyValue赋值操作
MyValue Myvalue = f.getAnnotation(MyValue.class);
String toValue = Myvalue.value();
f.setAccessible(true);
//对@MyValue目标绑定数据类型进行判断并赋值
if(f.getType().getName().equals("int")){//判断属性是否是int类型
f.set(people, Integer.parseInt(toValue));
}else{
f.set(people, toValue);
}
}
System.out.println(people);
}
}
|