一、注解
1、元注解
元注解用来解释其他注解
- @Target 描述注解的范围
- @Retention 注释信息的级别,注解的生命周期
- @Documented 该注释将被包含在javadoc中
- @Inherited 子类可以继承父类中该注解
2、内置注解
一些已经写好了的注解
- @Override 重写
- @Deprecated 不推荐程序员使用,但是可以使用或者存在更好的方式
- @SuppressWarnings(“all”) 用来抑制编译时所有的警告信息(参数有7种可以填,自行百度)
3、自定义注解
(此处填多个元注解,如:@Target({ElementType.TYPE,ElementType.METHOD}))
@interface MyAnnotation{
函数体(如:String name() default "";)//类型 参数名() default 默认值
(int类型参数默认值如果为-1,则表示不存在)
}
4、反射读取注解
类对象.getAnnotations()
可以返回一个Annotation[],包括这个对象的所有注解(是对象的注解,不包括它属性的注解)。可以加参数,参数为某个注解名.class
,返回一个Annotation对象,可以调用这个对象的某个字段获取这个注解的某个参数的值。如:
注解名 annotation = (注解名)c.getAnnotation(注解名.class);
String value = annotation.value();
c为用了这个注解的类的某个实例化对象
二、反射
反射是Java成为准动态语言的关键,它使Java动态获取属性成为可能。但是这也会使程序的运行变慢。
普通方式执行速度>关闭安全检测执行速度>反射方式执行速度
1、Class类
获得类的n种方式
这里自定义了一个Person类用来列举Class的4种获取方式
//先实例化一个person对象
Person person = new Student();
//方式一:通过对象获得
Class c1 = person.getClass();
System.out.println(c1.hashCode());
//方式二:forname获得
Class c2 = Class.forName("zxt.Reflection.Student");
System.out.println(c2.hashCode());
//方式三:通过 类名.class获得
Class c3 = Student.class;
System.out.println(c3.hashCode());
//方法四:基本内置类型的包装类都有一个Type属性
Class c4 = Integer.TYPE;
System.out.println(c4.hashCode());
所有类型的Class
Class c1 = Object.class;//对象
Class c2 = Comparable.class;//接口
Class c3 = String[].class;//一维数组
Class c4 = int[][].class;//二维数组
Class c5 = Override.class;//注解
Class c6 = ElementType.class;//枚举类型
Class c7 = Integer.class;//基本数据类型
Class c8 = void.class;//空类型
Class c9 = Class.class;//Class本身
打印这9个对象:
class java.lang.Object
interface java.lang.Comparable
class [Ljava.lang.String;
class [[I
interface java.lang.Override
class java.lang.annotation.ElementType
class java.lang.Integer
void
class java.lang.Class
2、类加载机制
我们写的.java文件会被编译器编译成.class文件,当某个类被需要后,jvm就会加载对应的.class文件,并创建对象加载到jvm的内存中。
并不是代码写出来就都会被加载,举个例子理解一下:
public class Test {
static {
System.out.println("main类被加载");
}
public static void main(String[] args) throws ClassNotFoundException {
System.out.println(Son.b);//子类调用父类的变量,不会加载子类
Son[] array = new Son[5];//数组只被声明,不会加载类
System.out.println(Son.M);//常量在常量池里,不会加载类
}
}
class Father {
static int b = 2;
static {
System.out.println("父类被加载");
}
}
class Son extends Father {
static {
System.out.println("子类被加载");
m = 300;
}
static int m = 100;
static final int M = 1;
}
输出结果是:
main类被加载
父类被加载
2
1
双亲委派机制
当在上层加载器中已存在与自己写的同名的类,会使用已存在的类。比如:自己写了一个Java.lang.String,无法正常使用,会使用根加载器里的。
获取类加载器
Class类型的对象的getClassLoader()
方法,可以知道这个对象是谁加载的。
如:
Class aClass = Class.forName("com.Reflection.Test01");
System.out.println(aClass.getClassLoader());
打印:
sun.misc.Launcher$AppClassLoader@18b4aac2
3、重要方法
这些比较特殊,单独拎出来
调用对象 | 方法 | 说明 |
---|---|---|
类对象或构造器 | newInstance() | 实例化对象 |
方法对象 | invoke(对象,…args) | 激活某个方法,先传入调用这个方法的对象,再传入调用这个方法要传的参数列表 |
属性对象 | set(对象,字段) | 修改某个对象的某个属性,先传要修改属性的对象,再传修改后的值 |
方法 | 说明 |
---|---|
getName() | 获得包名 + 类名 |
getSimpleName() | 获得类名 |
getFields() | 获得公有属性 |
getDeclaredFields() | 获得所有定义过的属性(包括私有) |
getDeclaredField(String name) | 根据属性名获取属性 |
getMethods() | 获得本类及父类的所有公有方法 |
getDeclaredMethods() | 获得本类的所有公有方法 |
getMethod(String name,…parameterTypes) | 根据方法名获取指定方法(第二个参数是获取的方法的参数类型) |
getDeclaredConstructor() | 获取某个Class对象的构造器,参数列表为构造器参数的Class |
setAccessible(true) | 关闭某个对象的安全检测,使私有属性可以被操作 |
getGenericParameterTypes() | 获取泛型信息 |
上一篇 GUI图形界面化编程