获取运行时类的完整结构
- Field、Method、Constructor、Superclass、Interface、Annotation
public class Test1 {
public static void main(String[] args) throws Exception {
Thread thread=new Thread();
Class c1=thread.getClass();
System.out.println(c1.getName());
System.out.println(c1.getSimpleName());
System.out.println("-----------------------------------------");
Field[] field1=c1.getFields();
for (Field f :field1) {
System.out.println(f);
}
Field[] field2=c1.getDeclaredFields();
for (Field f :field2) {
System.out.println(f);
}
Field tid=c1.getDeclaredField("tid");
System.out.println(tid);
System.out.println("--------------------");
Method[] methods=c1.getMethods();
for (Method method:methods) {
System.out.println("1"+method);
}
methods=c1.getDeclaredMethods();
for (Method method:methods) {
System.out.println("2"+method);
}
System.out.println("-------------------------");
Constructor[] constructors=c1.getConstructors();
for (Constructor c :constructors) {
System.out.println("#"+c);
}
constructors=c1.getDeclaredConstructors();
for (Constructor c :constructors) {
System.out.println("$"+c);
}
c1.getDeclaredConstructor(String.class);
}
}
有了Class对象能做什么
- 创建类的对象
- 调用Class对象的newInstance()方法
- 必须要有一个无参数的构造器
- 类的构造器的访问权限要够
- 通过获取Class对象的构造器创建
- 通过Class对象的getDeclaredConstructor()方法获取本类指定参数类型的构造器(上一节有讲)
- 向构造器传入一个对象数组,其中包含此构造器所需要的各个参数
- 通过Constructor实例化对象
- 调用普通方法
- 获取和修改属性
public class Test2 {
public static void main(String[] args) throws Exception {
Class c=String.class;
String s1=(String) c.newInstance();
Constructor constructor=c.getDeclaredConstructor(String.class);
String s2= (String) constructor.newInstance("123");
System.out.println(s2);
Method method= c.getMethod("equals", Object.class);
boolean b=(boolean)method.invoke(s2, "123");
System.out.println(b);
Field hash=c.getDeclaredField("hash");
hash.setAccessible(true);
System.out.println(s2.hashCode());
hash.set(s2,1);
System.out.println(s2.hashCode());
}
}
- 注意:其中setAccessible(true)方法调用后会关闭对应属性、方法的安全检查,但会改善反射调用的效率问题
public class Test3 {
public static void main(String[] args) throws Exception {
test1();
test2();
test3();
}
public static void test1(){
String s="123";
long startTime=System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
s.hashCode();
}
long endTime=System.currentTimeMillis();
System.out.println("直接调用消耗了"+(endTime-startTime)+"ms");
}
public static void test2() throws Exception {
String s="123";
Method hashCode= s.getClass().getDeclaredMethod("hashCode",null);
long startTime=System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
hashCode.invoke(s,null);
}
long endTime=System.currentTimeMillis();
System.out.println("反射调用消耗了"+(endTime-startTime)+"ms");
}
public static void test3() throws Exception {
String s="123";
Method hashCode= s.getClass().getDeclaredMethod("hashCode",null);
hashCode.setAccessible(true);
long startTime=System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
hashCode.invoke(s,null);
}
long endTime=System.currentTimeMillis();
System.out.println("关闭检查消耗了"+(endTime-startTime)+"ms");
}
}
- 反射操作泛型
- Java采用泛型擦除的机制来引入泛型,Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换的问题,但是,一旦编译完成,所有和泛型有关的类型全部擦除。
- 为了通过反射操作这些类型,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型。
类型 | 说明 |
---|
ParameterizedType | 表示一种参数化类型,比如Collection< String > |
GenericArrayType | 表示一种元素类型是参数化类型或者类型变量的数组类型 |
TypeVariable | 是各种类型变量的公共父接口 |
WildcardType | 代表一种通配符类型表达式 |
public class Test4 {
public void test1(Map<String,Integer> map, List<Integer> list){
System.out.println("test1");
}
public Map<String,Integer> test2(){
System.out.println("test2");
return null;
}
public static void main(String[] args) throws Exception {
Method method = Test4.class.getMethod("test1", Map.class, List.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
System.out.println("#"+genericParameterType);
if (genericParameterType instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(" "+actualTypeArgument);
}
}
}
method =Test4.class.getMethod("test2",null);
Type genericReturnType = method.getGenericReturnType();
System.out.println("#"+genericReturnType);
if (genericReturnType instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(" "+actualTypeArgument);
}
}
}
}
- 反射操作注解
- 练习ORM——Object Relationship Mapping–>对象关系映射
- 利用注解和反射完成类和表结构的映射关系
public class Test5 {
public static void main(String[] args) throws Exception {
Class c1 = Class.forName("Day9.Student");
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
MyTable annotation =(MyTable)c1.getAnnotation(MyTable.class);
System.out.println(annotation.value());
Field name = c1.getDeclaredField("name");
MyField annotation1 = name.getAnnotation(MyField.class);
System.out.println(annotation1.columnName());
System.out.println(annotation1.type());
System.out.println(annotation1.length());
}
}
@MyTable("db_student")
class Student{
@MyField(columnName ="db_id",type = "int",length =10)
private int id;
@MyField(columnName ="db_age",type = "int",length =10)
private int age;
@MyField(columnName ="db_name",type = "varchar",length =3)
private String name;
public Student() {
}
public Student(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface MyTable{
String value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyField{
String columnName();
String type();
int length();
}