目录
1.注解
2.反射初步
(1)概述:
(2)class类
ps:实体类和之前的略有不一样,实体类就是一个拥有Set和Get方法的类。实体类通常总是和数据库之类的(所谓持久层数据)联系在一起。这种联系是借由框架(如Hibernate)来建立的。
//class类的创建方法
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Student();
System.out.println("这是:" + person.name);
//方式一:通过对象获得
Class c1 = person.getClass();
System.out.println(c1.hashCode());
//方法二:forname获得
Class<?> c2 = Class.forName("com.example.Student");
System.out.println(c2.hashCode());
//方法三:通过类名
Class c3=Student.class;
System.out.println(c3.hashCode());
//方法四:基本内置类型的包装类有一个type属性,但仅仅局限于基本内置类型
Class<Integer> type = Integer.TYPE;
}
}
class Person {
public String name;
public double height;
public Person() {
}
public Person(String name, double height) {
this.name = name;
this.height = height;
}
/**
* 获取
*
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
*
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
*
* @return height
*/
public double getHeight() {
return height;
}
/**
* 设置
*
* @param height
*/
public void setHeight(double height) {
this.height = height;
}
public String toString() {
return "Person{name = " + name + ", height = " + height + "}";
}
}
class Student extends Person {
public Student() {
name = "学生";
}
}
class Teacher extends Person {
public Teacher() {
name = "老师";
}
}
//还有个getsuperclass获得父类类型
结果:
(3)class对象的类型
PS:选择然后按alt键可以整体竖着复制
测试:
比如下面,两个长度不一样的int数组,只有都是一维数组,那么就都只有一个class
3.反射的底层和用法分析
(1)类的加载
链接里面的解析这一步:
例子:
这是为什么捏?先方法区加载类的字节码,然后堆里面创建Class类对象,然后栈里面进入main方法,然后继续调用......
链接阶段m默认初始化为0,然后new A ,要对A的这个对象做初始化,所以把赋值和静态代码块合并起来,所以实际上,顺序是这样的m=300;m=100;最后m就是等于100
(2)类的初始化
主动加载这几种方法比较常见,下面展示一下被动引用:
这里调用父类里面的static int b=2,所以只加载Main和父类
这里什么都没干,就只是main加载了,不加载son类
M是父类里面的常量
那么常量不会引起父类或子类的加载
就一个main
(3)类加载器
缓存为了提高效率
null意思是根加载器加载的。
扩充:
双亲委派机制,保证安全性,比如你写了一个java.lang.String,他会一直找到根加载器,如果在这里找到了系统也有一个Java.lang.String,那么他就不会用你自己写的,你自己写就根本用不了,以保证安全和效率
(4)获得类运行时的结构
测试:
(5)动态创建对象执行方法
法二:
我们已经可以通过反射得到方法、字段、构造器,也可以通过他们创建对象、调用方法、操作属性。
注意,反射是比较慢的:
(6)反射泛型
这里test01(Map<>,list<>){
},然后这里.class获得class对象然后getMethod获取方法,再用Type【】泛型接受参数类型
收到map和list,然后我们还向知道map,list里面具体是什么,就需要用instance of判断这些泛型是不是这个方法的参数类型,如果是再强转,使用geractualtype,用Type【】接受参数类型返回值,从而知道所有的
然后下面考察的是返回值类型,都是一样的逻辑
(7)获取注解信息
最后我亲手试一遍:
//练习反射操作注解
public class Test2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class<?> c1 = Class.forName("com.example.Test2");
//通过反射获得注解
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//注解的英文就是annotation
//获取指定的注解的value值
Taketake take = c1.getAnnotation(Taketake.class);
String value=take.value();
System.out.println(value);
//获得类的指定注解
Field f =c1.getDeclaredField("name");
Fielddo annotation = f.getAnnotation(Fielddo.class);
System.out.println(annotation.columnName());
System.out.println(annotation.length());
System.out.println(annotation.type());
}
}
@Taketake("student_db")
class Student {
@Fielddo(columnName = "name_db", type = "varchar", length = 3)
private String name;
@Fielddo(columnName = "age_db", type = "int", length = 10)
private String age;
public Student() {
}
public Student(String name, String age) {
this.name = name;
this.age = age;
}
/**
* 获取
*
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
*
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
*
* @return age
*/
public String getAge() {
return age;
}
/**
* 设置
*
* @param age
*/
public void setAge(String age) {
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
//类名的注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Taketake {
String value();
}
//属性的注解:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Fielddo {
String columnName();
String type();
int length();
}
以后可能会在类里面定义一些注解,然后通过反射框架读取然后生成相应的信息。假设数据库里有一张表,我们可以通过定义和这个表对应的类型,然后通过注解生成一些数据库的语言进行增删改查