Java不注解是程序本身 ,但可以对程序作出解释.(这一点和注释(comment)没什么区别) , 可以被其他程序(比如:编译器等)读取
定义格式
注解是以"@注释名"在代码中存在的 , 还可以添加一些参数值 , 例如@SuppressWarnings(value=“unchecked”).
使用场景
可以附加在package , class , method , field 等上面 , 相当于给他们添加了额外的辅助信息, 我们可以通过反射机制编程实现对这些元数据的访问
内置注解
元注解
元注解的作用就是负责注解其他注解 , Java定义了4个标准的meta-annotation类型,他们被用来 提供对其他annotation类型作说明
自定义注解
使用 @interface自定义注解时 , 自动继承了java.lang.annotation.Annotation接口
@ interface用来声明一个注解 , 格式 : public @ interface 注解名 { 定义内容 }
其中的每一个方法实际上是声明了一个配置参数.
方法的名称就是参数的名称.
返回值类型就是参数的类型 ( 返回值只能是基本类型,Class , String , enum ).
可以通过default来声明参数的默认值 .
如果只有一个参数成员 , 一般参数名为value
注解元素必须要有值 , 我们定义注解元素时 , 经常使用空字符串,0作为默认值 .
import java.lang.annotation.*;
@MyAnnotation
public class Test1 {
//有默认值可以不写,无默认值的要赋值
@MyAnnotation(name = "张",age = 18,schools = "邮电大学",classs = "电子")
public void test(){}
//只有一个参数时,默认使用value()做参数名,使用时可以省略参数名
@MyAnnotation2("西邮")
public void test2(){}
}
@Target(value = {ElementType.METHOD,ElementType.TYPE,ElementType.FIELD}) //作用域
@Retention(RetentionPolicy.RUNTIME)//运行时级别
@Documented//生成Doc文档
@Inherited //子类可以继承父类的注解
@interface MyAnnotation{
//参数类型 参数名
String name() default "";
int age() default 0;
int id() default -1; //-1表示不存在
String classs() default "";
String[] schools() default {"西开","西邮"};
}
@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
String value();
}
动态语言
静态语言
Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动态性, 我们可以利用反射机制获得类似动态语言的特性。Java的动态性让编程的时候更 加灵活
类的加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化
加载
就是指将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一Class对象
连接
验证 是否有正确的内部结构,并和其他类协调一致
准备 负责为类的静态成员分配内存,并设置默认初始化值
解析 虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程
初始化
JVM进行类的初始化
执行类构造器()方法的过程。类构造器()方法是由编译期自动收集类中所有类变量的赋值动作和静态 代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造该类对象的构造器)
当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化
虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步
类的加载过程
类加载器
负责将.class文件加载到内在中,并为之生成对应的Class对象
类加载器的组成
System ClassLoader 系统类加载器
负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径
Extension ClassLoader 扩展类加载器
负责JRE的扩展目录中jar包的加载,在JDK中JRE的lib目录下ext目录
Bootstrap ClassLoader 根类加载器
也被称为引导类加载器,负责Java核心类的加载,用C++编写
案例
public class TestClassLoader {
public static void main(String[] args) throws ClassNotFoundException {
//1.获得系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
//2.获得系统类加载器的父类加载器---扩展类加载器
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent);
//3.扩展类加载器的父类---根加载器(最底层 c++编写)
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);
//4.测试当前类是哪个加载器加载的
ClassLoader classLoader = Class.forName("org.westos.Test0607.TestClassLoader").getClassLoader();
System.out.println(classLoader);
//5.测试Object类是哪个加载器加载的
ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();
System.out.println(classLoader1);
//系统类加载器可以加载类的路径
String property = System.getProperty("java.class.path");
System.out.println(property);
}
}
运行结果:
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
Class类
Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass方法自动构造
获取Class类的实例
若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高
Class personClass = Person.class;
已知某个类的实例,调用该实例的getClass()方法获取Class对象
Person person = new Person();
Class personClass = person.getClass();
已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取, 可能抛出ClassNotFoundException
public static void main(String[] args) throws ClassNotFoundException {
Class aClass = Class.forName("org.westos.homework0406.Person");
}
内置基本数据类型可以直接用类名.Type 获取Class对象
Class integerClass = Integer.TYPE;
有Class对象的类型
import java.lang.annotation.ElementType;
public class TestReflection3 {
public static void main(String[] args) {
Class
Class对象获取构造方法并使用
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Test10 {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class personClass = Person.class;
//获取所有构造方法
Constructor>[] constructors = personClass.getDeclaredConstructors();
for (Constructor> constructor : constructors) {
System.out.println(constructor);
}
//获取空参构造方法
Constructor constructor = personClass.getConstructor(null);
System.out.println(constructor);
//获取有参构造
Constructor constructor1 = personClass.getConstructor(String.class);
System.out.println(constructor1);
//通过获取到的构造方法创建对象
//Object obj = con.newInstance(null);
Person person = constructor.newInstance();
System.out.println(person);
}
}
//输出:
public org.westos.Test0607.Person()
public org.westos.Test0607.Person(java.lang.String)
public org.westos.Test0607.Person()
public org.westos.Test0607.Person(java.lang.String)
Person{name='null'}
通过反射获取私有构造方法
AccessibleObject 类是 Field、Method 和 Constructor 对象的父类。它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力。
对于公共成员、默认(打包)访问成员、受保护成员和私有成员,在分别使用 Field、Method 或 Constructor 对象来设置或获取字段、调用方法,或者创建和初始化类的新实例的时候,会执行访问检查。常用方法如下:
public void setAccessible(boolean flag) throws SecurityException
参数值为 true
则指示反射的对象在使用时应该取消 Java 语言访问检查。参数值为 false
则指示反射的对象应该实施 Java 语言访问检查。
获取私有构造方法,步骤如下
获取到Class对象
获取指定的构造方法
暴力访问, 通过setAccessible(boolean flag)方法
通过构造方法类Constructor中的方法,创建对象
案例
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Test11 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InvocationTargetException {
//1,获取到Class对象
Class c = Class.forName("org.westos.Test0607.Person");//包名.类名
//2,获取指定的构造方法
//private Person(String name, int age)
Constructor con = c.getDeclaredConstructor(String.class);
//3,暴力反射
con.setAccessible(true);//取消 Java 语言访问检查
//4,通过构造方法类中的功能,创建对象
Object obj = con.newInstance("小明");
System.out.println(obj);
}
}
//运行结果:
Person{name='小明'}
通过反射获取成员变量并使用
在反射机制中,把类中的成员变量使用类Field表示。可通过Class类中提供的方法获取成员变量:
返回一个成员变量
public Field getField(String name) 获取指定的 public修饰的变量
public Field getDeclaredField(String name) 获取指定的任意变量
返回多个成员变量
public Field[] getFields() 获取所有public 修饰的变量
public Field[] getDeclaredFields() 获取所有的 变量 (包含私有)
案例
import java.lang.reflect.Field;
public class Test12 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException {
//获取Class对象
Class c = Class.forName("org.westos.Test0607.Animal");
//获取成员变量
//Field[] fields = c.getFields();
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("-----------------");
//一个变量
//public int name;
Field field = c.getDeclaredField("age");
System.out.println(field);
}
}
//运行结果
private java.lang.String org.westos.Test0607.Animal.name
private int org.westos.Test0607.Animal.age
-----------------
private int org.westos.Test0607.Animal.age
import java.lang.reflect.Field;
public class Test13 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
//通过放射获取对象
Class> c = Class.forName("org.westos.Test0607.Animal");
Object o = c.newInstance();
//反射获取成员变量
Field name = c.getDeclaredField("name");
Field age = c.getDeclaredField("age");
//取消 Java 语言访问检查
name.setAccessible(true);
age.setAccessible(true);
//赋值
name.set(o,"旺财");
age.set(o,3);
System.out.println(o.toString());
}
}
//运行结果
Animal{name='旺财', age=3}
通过反射获取成员方法并使用
在反射机制中,把类中的成员方法使用类Method表示。可通过Class类中提供的方法获取成员方法:
返回获取一个方法:
public Method getMethod(String name, Class>… parameterTypes)
获取public 修饰的方法
public Method getDeclaredMethod(String name, Class>… parameterTypes)
获取任意的方法,包含私有的
参数1: name 要查找的方法名称; 参数2: parameterTypes 该方法的参数类型
返回获取多个方法:
public Method[] getMethods() 获取本类与父类中所有public 修饰的方法
public Method[] getDeclaredMethods() 获取本类中所有的方法(包含私有的)
public Object invoke(Object obj, Object… args)
执行指定对象obj中,当前Method对象所代表的方法,方法要传入的参数通过args指定。
案例
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test14 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取Class对象
Class> c = Class.forName("org.westos.Test0607.Animal");
//获取构造方法
Constructor> constructor = c.getConstructor(String.class,int.class);
//获取对象
Object o = constructor.newInstance("小黄",3);
//获取指定方法
Method getAge = c.getDeclaredMethod("getAge",null);
//执行找到的方法
Object invoke = getAge.invoke(o, null);
System.out.println(invoke);
}
}
//运行结果
3
反射操作泛型
Java采用泛型擦除的机制来引入泛型 , Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换问题 , 但是 , 一旦编译完成 , 所有和泛型有关的类型全部擦除
为了通过反射操作这些类型 , Java新增了 ParameterizedType , GenericArrayType , TypeVariable 和 WildcardType 几种类型来代表不能被归一到Class类中的类型但是又和原 始类型齐名的类型
ParameterizedType : 表示一种参数化类型,比如Collection
GenericArrayType : 表示一种元素类型是参数化类型或者类型变量的数组类型
TypeVariable : 是各种类型变量的公共父接口
WildcardType : 代表一种通配符类型表达式
public Class> getReturnType() 返回一个 Class 对象,该对象描述了此 Method 对象所表示的方法的正式返回类型
public Type getGenericReturnType()
返回表示由此 Method 对象所表示方法的正式返回类型的 Type 对象。
如果返回类型是参数化类型,则返回的 Type 对象必须实际反映源代码中所用参数的实际类型。
如果返回类型是类型变量或参数化类型,则创建它。否则将解析它。
public Type getActualTypeArguments 获得真实的类型参数
案例
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
//测试反射获取泛型
@SuppressWarnings("all")
public class Test08 {
//带有泛型参数的方法
public void test01(Map map, List list) {
System.out.println("test01");
}
//带有泛型返回值的方法
public Map test2() {
System.out.println("test02");
return null;
}
public static void main(String[] args) throws Exception {
//获得指定方法的泛型信息
Method method = Test08.class.getDeclaredMethod("test01", Map.class, List.class);
//获得泛型参数类型信息
Type[] t = method.getGenericParameterTypes();
for (Type type : t) {
System.out.println("#" + type);
if (type instanceof ParameterizedType) {
//getActualTypeArguments 获得真实的类型参数
Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println("真实的泛型类型:" + actualTypeArgument);
}
}
}
//获得返回值泛型信息
Method method2 = Test08.class.getMethod("test2", null);
//获得泛型参数类型信息
//getGenericReturnType获得泛型返回值信息
Type genericReturnType = method2.getGenericReturnType();
if (genericReturnType instanceof ParameterizedType) {
//getActualTypeArguments 获得真实的类型参数
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println("真实的返回值泛型类型:" + actualTypeArgument);
}
}
}
}
//输出:
#java.util.Map
真实的泛型类型:class java.lang.String
真实的泛型类型:class com.kuang.reflection.User
#java.util.List
真实的泛型类型:class com.kuang.reflection.User
真实的返回值泛型类型:class java.lang.Integer
真实的返回值泛型类型:class com.kuang.reflection.User
反射操作注解
import java.lang.annotation.*;
//使用反射读取注解
/*
1.定义注解
2.在类中使用注解
3.使用反射获取注解
*/
public class Test8 {
public static void main(String[] args) throws Exception{
//通过反射获取注解信息
Class> c = Class.forName("org.westos.Test0607.student2");
Annotation[] annotations = c.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//通过注解的value方法获得注解的值
Table annotation = c.getAnnotation(Table.class);
System.out.println(annotation.value());
java.lang.reflect.Field id = c.getDeclaredField("id");
System.out.println(id);
//获得字段的注解
Field annotation1 = id.getAnnotation(Field.class);
//获得注解的参数信息
System.out.println(annotation1.columnName());
System.out.println(annotation1.length());
System.out.println(annotation1.type());
}
}
//学生实体类
@Table("db_student")
class student2{
@Field(columnName = "id",type = "int",length = 10)
private int id;
@Field(columnName = "db_age",type = "int",length = 3)
private int age;
@Field(columnName = "db_name",type = "varchar",length = 20)
private String name;
public student2() {
}
public student2(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "student2{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
//表名---类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table{
String value();
}
//字段类的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Field{
//参数类型 参数名
String columnName();//列名
String type();//类型
int length();//长度
}
//输出:
@org.westos.Test0607.Table(value=db_student)
db_student
private int org.westos.Test0607.student2.id
id
10
int