注解和反射
注解
Annotation。对程序做出解释,可以被其他程序读取。
格式:
@注解名(value=“xxx”)
在哪里使用?
package、class、method、field
内置注解
@Override //表示一个子类重写超类的一个方法
@Deprecated //不鼓励程序员使用
@SuppressWarnings //用来抑制编译时的警告
元注解
作用:负责注解其他注解。用来提供对其他annotation类型作说明。
@Target //用来描述注解的使用范围
@Retention //表示再什么级别保存该注解信息(SOURCE < CLASS < RUNTIME)
@Documeneted //说明该注解被包含在javadoc中
@Inherited //说明子类可以继承父类中的该注解
自定义注解
使用@interface自定义注解时,自动继承了Annotation接口
注:
@interface 用来声明一个注解,其中的每一个方法实际就是声明了一个配置参数
方法的名称就是参数的名称,并且返回值类型就是参数的类型[只能是基本类型、Class、String、enum]
可以通过default来声明默认值。
如果只有一个参数成员,则一般命名为 value
注解元素必须有值,因此时常使用空字符串 或 0 来作为 默认值
eg:
//自定义注解
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
//注解的参数:参数类型+参数名() 如果不设置默认值,则使用时必须赋值
String name() default "";
int age() default 0;
int id() default -1;
}
//使用
@MyAnnotation(name = "注解测试",age = 10,id = 1)
public class Test {
public static void main(String[] args) throws IOException {
}
}
反射
Reflection.反射机制允许程序在执行期间借助于Reflection API来取得任何类的内部信息,并可以直接操作任意对象的内部属性及方法。
原理:
加载完类后,堆内存的方法区回产生Class类型的对象[一个类只有一个Class对象],这个对象包含了完整的类的结构信息。而我们可以通过这个对象看到类的结构、
正常:
导包->通过new实例化->取得实例化对象
反射:
实例化对象->getClass()->取得该类
应用:
在运行时,判断任意对象的所属类、任意类的对象、一个类所具有的成员变量和方法、获取泛型信息、调用任意对象的成员变量和方法、处理注解
生成动态代理等…
优缺点:
优:可以实现动态创建对象和编译,增强灵活性
缺:影响性能。
获得反射对象
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Class c1 = Class.forName("javaEE.Student");
System.out.println(c1); //class javaEE.Student
//通过多个对象的hasCode => 一个类在内存中只有一个Class对象
System.out.println(c1.hashCode());//1067040082
System.out.println(Class.forName("javaEE.Student").hashCode());//1067040082
}
}
class Student{
private String name;
private int id;
private int age;
public Student() {
}
public Student(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
获得Class类
static ClassforName(String name) //返回指定类名name的Class对象
Object newInstance() //通过缺省构造函数,返回Class对象的一个实例
getName() //返回此CLass对象所表示的实体(类、接口、数组类、void)的名称
Class getSuperClass() //返回当前对象的父类的Class对象
Class[] getInterfaces() //获取当前对象的接口
ClassLoader getClassLoader() //返回该类的类加载器
Constructor[] getConstructors() //返回一个包含某些Constructor对象的数组
Method getMethod(String name,Class..T) //返回一个Method对象,该对象形参类型为paramType
Field[] getDeclaredFields() //返回Field对象的一个数组
eg:
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Student();
System.out.println("This is"+person.name);
//1.
Class c1 = person.getClass();
System.out.println(c1.hashCode()); //1325547227
//2.
Class c2 = Class.forName("javaEE.Student");
System.out.println(c2.hashCode()); //1325547227
//3.
Class c3 = Student.class;
System.out.println(c3.hashCode()); //1325547227
//4.基本类型的包装类都有一个Type属性
Class c4 = Integer.TYPE;
System.out.println(c4);
//
Class c5 = c1.getSuperclass();
System.out.println(c5); //class javaEE.Person
}
}
class Person{
String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
class Student extends Person{
public Student(){
this.name="学生";
}
}
class Teacher extends Person{
public Teacher(){
this.name = "老师";
}
}
注:
只要类型和维度一致,便是用一个Class
类加载器
作用:作为方法去中类数据的访问入口
类缓存:一旦类被加载至类加载器中,它将维持加载一段时间,直至JVM回收掉它。
eg:
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
//获取系统类的加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader); //jdk.internal.loader.ClassLoaders$AppClassLoader@15db9742
//获取拓展类加载器 ->是 系统类加载器的父类
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent); //jdk.internal.loader.ClassLoaders$PlatformClassLoader@3f99bd52
//获取根加载器 ->是 拓展类加载器的父类
ClassLoader parent1 = parent.getParent();
System.out.println(parent1); //null 根加载器无法获取
}
}
创建运行时 类的对象
通过反射获取运行时 类的完整结构
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Class c1 = Class.forName("javaEE.User");
//获取类的名字
System.out.println(c1.getName()); //javaEE.User 包名+类名
System.out.println(c1.getSimpleName()); //User 类名
//获取类的属性
/*
//getFields只能找到public属性
Field[] fields = c1.getFields();
*/
Field[] fields = c1.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
/*
private java.lang.String javaEE.User.name
private int javaEE.User.id
private int javaEE.User.age
*/
}
//获取类的方法
Method[] methods = c1.getMethods();
for (Method method : methods) {
System.out.println(method); //获得本类及其父类的public方法
}
methods = c1.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method); //获取本类的方法
}
}
}
class User{
private String name;
private int id;
private int age;
public User() {
}
public User(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
动态创建对象的方法
eg:
public class Test {
public static void main(String[] args) throws Exception {
//获得Class 对象
Class c1 = Class.forName("javaEE.User");
//构造对象
User user = (User)c1.newInstance(); //本质调用了类的无参构造器
System.out.println(user);//User{name='null', id=0, age=0}
//通过构造器构造对象
Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
Object tom = constructor.newInstance("Tom", 1, 20);
System.out.println(tom);//User{name='Tom', id=1, age=20}
//通过反射调用普通方法
Method setName = c1.getDeclaredMethod("setName", String.class);
setName.invoke(user,"Jerry");
System.out.println(user.getName());//Jerry
//通过反射操作属性
Field name = c1.getDeclaredField("name");
//IllegalAccessException由于是私有的属性,直接调用会报错
name.setAccessible(true);//暴力反射,允许访问该私有属性
name.set(user,"Lucy");
System.out.println(user.getName()); //Lucy
}
}
反射操作泛型
ParamrterizedType //表示一种参数化类型
GenericArrayType //表示元素类型时参数化类型或数组类型
TypeVariable //各种类型变量的公共父接口
WildcardType //代表一种通配符类型表达式
eg:
public class Test {
public void param(Map<String,User> map,List<User> list){
System.out.println("param");
}
public Map<String,User> paramDemo(){
System.out.println("paramDemo");
return null;
}
public static void main(String[] args) throws Exception {
Method param = Test.class.getMethod("param", Map.class, List.class);
Type[] genericParameterTypes = param.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
System.out.println("gen:"+genericParameterType);
if (genericParameterType instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}//for
/*
gen:java.util.Map<java.lang.String, javaEE.User>
class java.lang.String
class javaEE.User
gen:java.util.List<javaEE.User>
class javaEE.User
*/
Method paramDemo = Test.class.getMethod("paramDemo");
Type genericParameterTypes1 = paramDemo.getGenericReturnType();
if (genericParameterTypes1 instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) genericParameterTypes1).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}//for
}//if
/*
class java.lang.String
class javaEE.User
*/
}
}
反射操作注解
getAnnotations
getAnnotation
eg:
public class Test {
public static void main(String[] args) throws Exception {
Class c1 = Class.forName("javaEE.Student");
//通过反射获得注解
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation); //@javaEE.Table(value="db_student")
}
//获取注解value的值
Table table = (Table) c1.getAnnotation(Table.class);
String value = table.value();
System.out.println(value); //db_student
//获得类指定的注解
Field name = c1.getDeclaredField("name");
TableField tableField = name.getAnnotation(TableField.class);
System.out.println(tableField.columnName()); //db_name
System.out.println(tableField.type()); //varchar
System.out.println(tableField.length());//8
}
}
@Table("db_student")
class Student{
@TableField(columnName = "db_id",type = "int",length = 10)
private int id;
@TableField(columnName = "db_age",type = "int",length = 10)
private int age;
@TableField(columnName = "db_name",type = "varchar",length = 8)
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 + '\'' +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table{
String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface TableField{
String columnName();
String type();
int length();
}