注解
java.lang.annotation.Annotation是注解接口,只要是注解都默认实现了该接口。注解不会直接影响语句的语义,只是作为一种标记存在。
元注解
@Target : 用来限制注解的适用范围,即指定该注解可用于那些程序元素。格式为@Target(value = )
@Retention: 说明注解的保存范围。格式为@Retention(value = )
@Document : 用于指定被修饰的注解可被javadoc.exe工具提取成文档。定义类时使用该注解进 行修饰,则所有使用该注解修饰的程序元素的API文档中将包含该注解声明。
@Inherited : 用于描述一个父类的注解可以被子类所继承。如果一个注解需要被其子类所继承, 则在声明时直接使用@Inherited注解就行。
@Repeatable: 用于开发重复注解。通常是注解的值可以取多个。
@interface Persons {
Person[] value();
}
@Repeatable(Persons.class)
@interface Person{
String role default "";
}
@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan{
}
其中@Repeatable括号内的类相当于一个容器注解。
什么是容器注解呢?就是用来存放其它注解的地方。它本身也是一个注解。
类型注解: java 8 为ElementType枚举增加了TYPE_PAEAMETER和TYPE_USE两个枚举值,允许在定义枚举时使用@Target(ElementType.TYPE_USE)来修饰。除了在定义类、接口、方法和成员变量等常见的程序元素时可以使用类型注解外,还可以在创建对象、方法参数、类型转换、使用throws声明抛出异常、使用implements实现接口等位置使用类型注解。
基本注解
@Deprecated : 该注解用于表示某个程序元素已过时,不建议使用。如果在其他地方使用了此元 素,则在编译时出现警告信息。
@Override: 该注解只用于方法,用来限定必须覆盖父类中的方法,主要作用是保证方法覆盖的 正确性。
@SuppressWarnings : 该注解用于抑制警告信息的出现。该注解可以用于类型、构造方法、成 员方法、成员变量、参数以及局部变量等。其语法格式为: @SuppressWarnings("警告参数")。
@SafeVarargs :用于抑制堆污染警告。所谓堆污染是指将一个不带泛型的对象赋值给带泛型的 对象,将导致泛型对象污染。
@FunctionalInterface:用于指定某个接口必须是函数式接口,如果一个接口中只有一个抽象方 法,则该接口称为函数式接口。函数式接口是为Lambda表达式准备的, 所以允许使用Lambda表达式来创建函数式接口的实例。
自定义注解
语法格式如下:
[public]@interface注解名
{
数据类型成员变量名()[default初始值];
}
反射机制
如果创建一个对象p,对象p在编译时的类型为Person,而运行时的类型为Student,体现了类的多态。java为用户提供的反射机制能很好地解决获取程序运行中的动态信息的问题。
反射机制所需的类主要有java.lang包中的Class类java.lang.reflet包中的Constructor类、Field类、Method类和Parameter类。
Class类
JVM将产生一个java.lang.Class对象代该.class字节码文件,从该Class对象中可以获得类中的许多基本信息。Class类没有公共构造方法,其对象是JVM加载类时通过调用类加载器中的defineClass()方法创建的,因此不能显示地创建一个Class对象。
创建Class对象:
- 使用Class类的静态方法forName(String className),其中参数className表示所需类的全名。另外,forName()方法会抛出ClassNotFounfException异常,因此调用该方法必须捕获或抛出该异常
- 使用 类名.class 的语法,调用该类的class属性来获得。
- 用对象调用getClass()方法来获得该类对应的Class对象。
反射包reflect
java.lang.reflect.Executable类
getModifiers()方法返回的是以整数表示的修饰符。此时引入Modifier类,通过调用Modifier.toString(int mod)方法返回修饰符常量所对应的字符串。
java.lang.reflect.Constructor<T>类
java.lang.reflect.Method类
java.lang.reflect.Field类
java.lang.reflect.Parameter类
反射的应用
import java.lang.reflect.*;
/*
想要输出参数信息,前提是isNamePresent()方法的返回值为true,即只有当.class文件
中包含参数时,程序才会执行if语句内输出参数信息的代码,因此需要使用带参数-parameters
的javac命令进行编译
javac-parameters t01.java
*/
class Person
{
private String name;
private int age;
public Person(String name,int age)
{
this.name = name;
this.age = age;
}
public void info(String prof, int score)
{
System.out.println("我的专业:" + prof + ";入学成绩:" + score);
}
@Override
public String toString() // 覆盖父类中的toString()方法
{
return "姓名:" + this.name + "年龄:" + this.age;
}
}
public class t01
{
public static void main(String[] args)
{
Class<Person> pc = Person.class;
try {// 返回参数类型为String和int的构造方法
Constructor con = pc.getConstructor(String.class,int.class);
System.out.print("构造方法名:" + con.getName());
Class[] pt = con.getParameterTypes(); // 获取构造方法参数的类型
for(int i = 0; i < pt.length;i++)
System.out.print(",参数:" + pt[i].getName());
}
catch(NoSuchMethodException e) {
e.printStackTrace();
}
Field[] fls = pc.getDeclaredFields(); // 获取所有成员变量
for(Field f : fls)
{
int mod = f.getModifiers(); // 获取修饰符
System.out.print("\n成员变量修饰符:" + Modifier.toString(mod));
Class type = f.getType(); // 获取成员变量的类型
System.out.print(";名称:" + f.getName());
System.out.print(";类型:" + type.getName());
}
System.out.println(" ");
Method[] mds = pc.getMethods(); // 获取所有成员方法
for(Method m : mds)
{
System.out.print("方法:" + m.getName());
System.out.println(" 参数个数:" + m.getParameterCount());
Parameter[] pars = m.getParameters(); // 获取方法的参数
int index = 1;
for(Parameter p : pars)
{
if(p.isNamePresent())
{
System.out.println("----第" + (index++) + "个参数的信息----");
System.out.println("参数名:" + p.getName());
System.out.println("参数类型:" + p.getType());
System.out.println("泛型类型" + p.getParameterizedType());
System.out.println("-----------------------------------------------");
}
}
}
}
}