注解Annotation
什么是注解
annotation的作用
和注释(comment)没什么区别,可以对程序作出解释
被其他程序(如编译器)读取
格式
@注释名
@注释名( 参数 = ”参数值“ )
使用位置
package, class, method, field等,给他们添加额外的信息
通过反射机制对元数据进行访问 ? 待看
内置注解
@Override 修辞方法,表示重写超类中的另一个方法声明
@Deprecated 修辞方法、类、属性 不鼓励使用
@SuppressWarnings 抑制编译时的警告信息
@SuppressWanings("all")
@SuppressWanings("unchecked")
@SuppressWanings("value = {"unchecked", "deprecation"}")
public class nativeAnnovation extends Object{ // 这里的extends Object 可以不写
@Override // 这里的注解时自己加上的,编译器没有默认加上
public String toString(){
System.out.println("toString");
return "toString";
}
@SuppressWarnings("all")
public void wanings(){
System.out.println("注释中抑制了警告");
}
}
元注解
注解其他注解,四个meta-annotation对去其他annotation进行注解
四个类型
@target 注解的使用方位
@Retention 注解的生命周期 (SOURCE < CLASS < RUNTIME)
@Document 注解将被包含在javadoc
@Inherited 注解是否可被子类继承
import java.lang.annotation.*;
public class yuanAnnotationTest {
@MyAnotation
public void run(){
System.out.println("测试元注解");
}
}
@Target(value = {ElementType.METHOD, ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@Inherited
@Documented
@interface MyAnotation{}
自定义注解
@interface自定义注解
分析
@interface用来声明一个注解,格式 public @interface 注解名{定义内容}
定义内容中的格式: 返回类型 方法名() defaults 默认值 方法名就是参数名称
如果只有一个参数成员,一般参数名为value
注解元素必须有值,0作为默认值
public class yuanAnnotationTest {
@MyAnotation
public void run(){
System.out.println("测试元注解");
}
@MyAnotation2(age = 19, name = "hi")
public void run2(){
}
}
@Target(value = {ElementType.METHOD, ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@Inherited
@Documented
@interface MyAnotation{}
@interface MyAnotation2{
String name() default "Dw";
int age() default 18;
int id() default -1;
String[] schools() default {"hello", "NEU"};
}
反射读取注解
import java.lang.annotation.*;
import java.lang.reflect.Field;
public class annovationReflect {
public static void main(String[] args) {
try {
// 反射,获得类的全部信息 ====> ClassNotFoundException
Class clazz = Class.forName("com.baidu.annovationTest.Student");
// 获得类的注解
// @com.baidu.annovationTest.TableKuang(value="db_student")
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation: annotations){
System.out.println(annotation);
}
// 获得注解的value 这里是“getAnnotation”, 非“getAnnotations”
// db_student
TableKuang table = (TableKuang)clazz.getAnnotation(TableKuang.class);
System.out.println(table.value());
// 获得类指定注解的值 reflect中的Field
// db_name-->varchar
Field name = clazz.getDeclaredField("name"); // java.lang.NoSuchFieldException
FieldKuang fieldKuang = name.getAnnotation(FieldKuang.class);
System.out.println(fieldKuang.columnName() + "-->" + fieldKuang.type());
}catch (ClassNotFoundException e){
e.printStackTrace();
}catch (java.lang.NoSuchFieldException e ){
e.printStackTrace();
}
}
}
/*
这个类中,有三个参数id name age, 每个参数注解为FieldKuang,内容是(列名,类型,长度)
重写了toString方法,输出Student{id name age}
*/
@TableKuang("db_student") // 假设数据表名为db_student
class Student{
@FieldKuang(columnName = "db_id", type = "int", length = 10)
private int id;
@FieldKuang(columnName = "db_name", type = "varchar", length = 10)
private String name;
@FieldKuang(columnName = "db_age", type = "int", length = 10)
private int age;
// 构造函数
public Student(){}
public Student(int id, String name, int age){
this.id = id;
this.name = name;
this.age = age;
}
// get和set函数
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString(){
return "Student{" + "id = " + id + " name = " + name + "age = " + age + "}";
}
}
// 注解:表名,只有一个参数时建议用value
@Target(value = ElementType.TYPE)
@Retention(value = RetentionPolicy.RUNTIME)
@interface TableKuang{
String value();
}
// 注解: 列
@Target(value = ElementType.FIELD)
@Retention(value = RetentionPolicy.RUNTIME)
@interface FieldKuang{
String columnName(); // 列名
String type(); // 类型
int length(); // 长度
}
反射机制
1. 静态语言vs动态语言(指编程语言)
动态语言
运行时自身结构可以被改变:函数、对象、代码等: Object-C, C#, JS, PHP, Python
functiontest(){
varx="var a = 3; var b = 5; alert(a + b)";
eval(x);
}
静态语言:
运行时结构不变的语言:Java, C, C++
Java具有一定的动态性,利用反射可以实现动态语言特性,更加灵活
2. Java Reflection
Reflection允许程序在运行过程中,通过Reflection API获取类的内部信息,操作对象内部属性和方法。
加载完类后,在堆中会有个类的对象,通过这个对象可以看到类的内部结构,像镜子一样,所以叫reflection。该对象类型为:Class类型。
一个类只产生一个Class对象,下面代码可以看出来
importstaticjava.lang.Class.*;
publicclassreflectionTest {
publicstaticvoidmain(String[] args) throwsClassNotFoundException {
// 一个类只对应一个Class对象,所以bookClass和Bookclass1指向的是同一个
// 284720968
Class<?>bookClass=forName("com.baidu.reflectionTest.Book");
System.out.println(bookClass.hashCode());
// 284720968
Class<?>bookClass1=forName("com.baidu.reflectionTest.Book");
System.out.println(bookClass1.hashCode());
}
}
classBook{
}
反射提供的功能
运行时:
判断兑现所属的类
构造任意类的对象
判断类的成员变量和方法
获取泛型信息
调用对象的成员变量和方法
处理注释
生成动态代理
反射的优缺点
优点:灵活,动态创建变量和编辑
缺点:速度慢,是一种解释动作,速度慢于直接执行相同的操作
3. 反射相关的主要API
java.lang.Class : 代表一个类
java.lang.reflect.Method: 代表类的方法
java.lang.reflect.Field: 代表类的成员变量
java.lang.reflect.Constructor: 代表类的构造器
4. Class类
class使用实例
Object类定义了一个getClass()方法,被所有子类继承:
publicfinalClassgetClass(); // 返回Class类,java反射的源头
Class本身是一个类,reflection的根源
Class对象由系统创建,一个加载的类在JVM中只有唯一的一个Class对象,对应加载到JVM中的.class文件
类的实例会记住自己是哪个Class实例所生成的
Class可以完整的得到类所有被加载的结构
publicclassreflectionTest {
publicstaticvoidmain(String[] args) throwsClassNotFoundException {
// 获得class的方法一: .class 或者 .TYPE
// 通过类.class获得类, 对于内置基本类型,还可以通过.TYPE获得类
Classclazz4=Integer.TYPE;
System.out.println(clazz4); // int
Classclazz5=Integer.class;
System.out.println(clazz4); // int
Classclazz6=Book.class;
System.out.println(clazz6); // class com.baidu.reflectionTest.Book
// 获得class的方法二: 类对象.getClass()
Bookstudent=newBook();
Classclazz7=student.getClass();
System.out.println(clazz7); // class com.baidu.reflectionTest.Book
// 获得class的方法三: Class.forName("类的具体位置")
Classclazz8=Class.forName("com.baidu.reflectionTest.Book");
System.out.println(clazz8); // class com.baidu.reflectionTest.Book
}
}
classBook{
}
Class类常用方法
publicstaticvoidmain(String[] args) throwsClassNotFoundException {
Classclazz1=Class.forName("com.baidu.reflectionTest.Book");
System.out.println(clazz1); // class com.baidu.reflectionTest.Book
// .getName() 返回此Class对象所表示的实体名称
System.out.println(clazz1.getName()); // com.baidu.reflectionTest.Book
// .getSuperclass() 返回当前Class对象的父类Class对象
ClasssuperClazz=clazz1.getSuperclass();
System.out.println(superClazz.getName()); // java.lang.Object
/*
Class[] .getInterfaces() 当前Class对象的接口
ClassLoader getClassLoader() 类加载器
Constructor[] getConstructors() 返回包含某些Constructor对象的数组
getMethod(String name, Class..T) Method对象
Field[] getDeclaredFields() 返回Field对象的数组
*/
}
哪些类型可以有Class对象?
类:外部类、成员内部类,静态内部类、局部内部类、匿名内部类等
interface:接口
[]: 数组
enum:枚举
annotation:注解
primitive type: 基本数据类型
void
5. Java内存分析
若类未被加载,则:
类的class文件读入内存,创建一个java.lang.class对象
链接:将类的二进制数据合并到jre
初始化:JVM对类进行初始化