注解
注解(Annotation)不是程序本身,可以对程序做出解释(这和注释comment没什么区别)。
注解可以被其他程序读取。
内置注解
@Override //重写的注解
public String toString(){
return super.toString();
}
@Deprecated //不推荐程序员使用,或者存在更好的方式,但是可以使用。
public void test(){
System.out.println("这段代码不推荐使用");
}
@SuppressWarnings() //镇压警告,需要参数
元注解
元注解(meta-annotation)负责注解其他注解的注解,Java中定义了4个标准的元注解类型,用来提供对其他注解类型作说明。
@Target //描述注解的使用范围
@Retention //表示需要在什么级别保存该注释信息,描述注解的生命周期(SOURCE<CLASS<RUNTIME)
@Documented //说明该注解将被包含在javadoc中
@Inherited //说明子类可以继承父类中的该注解
自定义注解
使用@interface自定义注解,自动继承java.lang.annotation.Annotation接口。
-
@interface用来声明一个注解,格式:public @interface 注解名{定义内容}
-
其中的每一个方法实际上是声明了一个配置参数
-
方法的名称就是参数的名称
-
返回值类型就是参数的类型(返回值只能是基本类型,Class,String,enum)
-
可以通过default声明参数的默认值
-
如果只有一个参数成员,一般参数名为value
-
注解元素必须要有值,定义注解元素时,经常使用空字符串0作为默认值
//自定义一个注解格式
@Target(value = ElementType.METHOD)//在方法中生效
@Retention(value = RetentionPolicy.RUNTIME)//表示在运行时也生效(任何时生效)
@Documented
@Inherited
public @interface MyFirstAnnotation{
//注解的参数 : 参数类型 + 参数名();
String name() default "";
int age() default 0;
int id() default -1;//默认-1,代表不存在
}
//使用时必须需要提供无默认值的参数
@MyFirstAnnotation(name = "lee",age = 18,id = 10086)
public void test1(){}
反射
反射(Reflection)使Java有一定的动态性,可以利用反射机制获得类似动态语言的特性,使程序更灵活。
反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。使用反射提高程序的通用性。
通过统一的语法
创建对象获取对象。
类加载
Class:在JVM(虚拟机)加载完,Class文件以后,会给每个类生成唯一的一个Class对象。该Class对象是该类所有实例(对象)共享的一个对象,Class对象包含了与类有关的信息,在Class对象中会把属性以及方法都单独封装成一个对象。
三个步骤:
-
加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象。
-
链接:将Java类的二进制代码合并到JVM的运行状态之中的过程。
验证:确保加载的类信息符合JVM规范,没有安全问题。
准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配。
解析:虚拟机常量池内的符合引用(常量名)替换为直接引用(地址)的过程。
-
初始化:到了此阶段,才真正开始执行类中定义的java程序代码,用于执行该类的静态初始器和静态初始块,如果该类有父类,优先对其父类进行初始化。
使用步骤
-
获取class对象
一个类在内存中只有一个Class对象。
一个类被加载后,类的整个结构都会被封装在class对象中。
//通过类的对象获取 Animal animal = new Animal(); Class animalClass1 = animal.getClass(); //通过类名.class获取 Class animalClass2 = Animal.class; //通过forName限定性类名获取 String className = "包名.类名" Class animalClass3 = Class.forName(className); //通过反射创建一个类的实例 object obj = animalClass3.newInstance;
-
操作对象里面的属性
Field[] fs1 = animalClass3.getFields();//获取所有的公共属性 Field[] fs2 = animalClass3.gerDeclaredFields();//获取所有属性
-
根据属性名称获取属性
Field[] ageField = animalClass3.gerDeclaredFields("age"); ageField.setAccessible(true);//取消安全检查,允许获取私有的属性值 ageField.setInt(obj,999); int age = ageField.getInd(obj);//获取 System.out.println(age);
-
操作对象里面的方法
Method[] ms = animalClass3.getMethods();//获取所有的公共方法 Method[] ms = animalClass3.getDeclaredMethods();//获取所有方法 Method eatMethod = animalClass3.getMethod("eat",int.class,String.class); eatMethod.invoke(obj,20,"lee"); Class<?>[] pcType = eatMethod.getParameterTypes();
实例
/*反射实例*/
public void r1(){
String personStr = "com.example.bean.Person";//对象类型属性
try {
Class personClass = Class.forName(personStr);
Object obj = personClass.newInstance();
String parKey = "name";
String parValue = "张三";
//通过字符串拼接创建set方法
String setParKey = "set"+parKey.substring(0,1).toUpperCase()+parKey.substring(1);
Method setNameMethod = personClass.getMethod(setParKey,parValue.getClass());
setNameMethod.invoke(obj,parValue);
//通过字符串拼接创建get方法
String getParKey = "get"+parKey.substring(0,1).toUpperCase()+parKey.substring(1);
Method getNameMethod = personClass.getMethod(setParKey,parValue.getClass());
Object result = getNameMethod.invoke(obj);
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}