注解的含义:
- Annotation的作用:不是程序本身,可以对程序做出解释;可以被其他程序(比如:编译器等)读取,注解可以用来修饰类、方法、变量、参数等,可以用来检查代码质量、约束开发者的编程风格、提高代码的可读性和可维护性(检查、约束)。
- 格式:以“@注释名”在代码中存在,还可以在后面添加一些参数值
- 使用范围:可以附加在package、class、method、filed等上面,相当于给他们添加了额外的辅助信息,可以通过反射机制编程实现对这些元数据的访问
内置注解:
@Override: 定义在java.lang.Override中,此注解只适用于修饰方法,表示一个方法声明打算重写超类中的另外一个方法声明。
@Deprecated:定义在Java.lang.Deprecated中,此注解可以用于修饰方法,属性,类,表示不鼓励程序员使用这样的元素(通常事因为它很危险或者存在更好的选择),但是可以此方法可以运行。
@SuppressWarnings:定义在Java.lang.SuppressWarnings中,用来抑制编译时的警告信息(后面要有参数才能正确使用),例如:
@SuppressWarnings("all"); @SuppressWarnings("unchecked"); @SuppressWarnings("unchecked","deprecation");
元注解:
作用:负责注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型作说明。
类型:@Target ,@Retention, @Documented ,@Inherited (这些类型和他们所支持的类在Java。狼。annotation包中可以找到。)
@Target:用于描述注解的使用范围(即被描述的代码可以用在那些地方) @Retention:表示需要在说明级别保存该注解信息,用于描述注解的生命周期(Runtime>class>source) @Document:说明该注解将被包含在Javadoc 中 @Inherited:说明子类可以继承父类中的该注解
格式:
@Target(value ={ElementType.METHOD,ElementType.TYPE})
@Retention(value=RetentionPolicy.RUNTIME)
自定义注解:
- 用法:使用@interface自定义注解时,自动继承java.lang.annotation.Annotation接口
- 归纳:
- @interface用来声明一个注解,格式:public @interface 注解名{定义内容}
- 其中的每一个方法实际上是声明一个配置参数
- 方法的名称就是参数的名称
- 返回值类型就是参数的类型(返回值只能是基本类型,Class,String,enum)
- 可以通过default来声明参数的默认值
- 如果只有一个参数成员,一般参数名为value
- 注解元素必须要由值,定义注解元素时,经常使用空字符串0作为默认值
- 代码如下:
package com.st.test;
//测试自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class Test03 {
//注解可以显示赋值,如果没有默认值(default 数值),我们就必须给注解赋值
@MyAnnotation2(name=”李明” ,schools ={“湖南大学”,”清华大学”} )
public void test(){}
//如果自定义的注解只有一个值的时候可以使用value表示,在方法注解表示的时候可以直接省略value
@MyAnnotation3(“李明”)
public void test2(){}
}
@Target(value={ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
//注解的参数:参数类型+参数名();
String name() ; //赋值为李明
int age() default 0;
int id() default -1; //如果默认值为-1,则代表不存在
String[] schools();
}
@Target(value={ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3{
String value();
}
java反射
特点:Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制获得此类似动态语言的特性。Java的动态性让在编程的时候更加灵活!
反射:被视为是动态语言的关键,反射机制允许程序在执行期间借助于’Reflection API’获取任何类的内部信息,并直接操作任意对象的内部属性及方法
Class c=Class.forName("java.lang.String")
加载完类之后,在堆内存的方法中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,通过镜子看到类的结构,所以形象的称为:反射
对比:
- 正常的方式:先引用需要的“包类”名称——> 通过new实例化——> 取得实例化对象
- 反射方式: 实例化对象——> getClass()方法——> 得到完整的“包类”名称。
- 反射机制在运行时提供的功能:
- 判断任意一个对象所属的类
- 可构造任意一个类的对象
- 可判断任意一个类所具有的成员变量和方法
- 可获取泛型信息
- 可调用任意一个对象的成员变量和方法
- 可处理注解
- 生成动态代理(AOP)
创建对象的五种方式: new、newInstance、clone、反序列化、反射。
代码:
package com.st.reflection; public class Test002 { public static void main(String[] args) throws ClassNotFoundException { //通过反射获取类的Class对象 Class c1=Class.forName("com.st.reflection.User"); System.out.println(c1); //查看他们是不是属于同一个类,就可以查看他们的哈希一不一样 Class c2=Class.forName("com.st.reflection.User"); Class c3=Class.forName("com.st.reflection.User"); Class c4=Class.forName("com.st.reflection.User"); //结果是一样的 //一个类在内存中只有一个Class对象,一个类被加载之后,类的整个结构都会被封装在Class对象中 System.out.println(c2.hashCode()); System.out.println(c3.hashCode()); System.out.println(c4.hashCode()); } } //实体类:pojo entity 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; } public String getName() { return name; } public int getId() { return id; } public int getAge() { return age; } public void setName(String name) { this.name = name; } public void setId(int id) { this.id = id; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", id=" + id + ", age=" + age + '}'; } }
获取Class类的实例
若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高
Class clazz =Person.class;
已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
Class clazz=Class.forName("demo01.Student");
已知某个类的实例,调用实例的getClass()方法获取Class对象
Classclazz=person.getClass();
内置基本数据类型可以用类名.TYPE
还可以利用ClassLoader
综合示例:
package com.st.reflection; //测试Class 类的创建方式有哪些 public class Test003 { 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.st.reflection.Student"); System.out.println(c2.hashCode()); //方式三:通过类名。class 获得 Class<Student> c3 = Student.class; System.out.println(c3.hashCode()); //方式四:基本内置类型的包装类都有一个Type属性 Class c4=Integer.TYPE; System.out.println(c4.hashCode()); //获取父类类型 Class c5=c1.getSuperclass(); System.out.println(c5); } } class Person{ public 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对象
- class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类。
- interface:接口
- []:数组(多维)
- enum:枚举
- annotation:注解@interface
- primitive type:基本数据类型
- void