全文目录
一. 注解
注解(Annotation):不是程序本身,可以对程序做出解释,也可以被其他程序读取。
注解格式:@注释名,也可以添加一些参数,如:@SuppressWarnings(value="unchecked")
1. 内置注解
常用的三种内置注解:
① @Override : 重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。只能修饰方法。
② @Deprecated : 标记过时方法。所标注内容,不再被建议使用。可以修饰方法、属性、类。
③ @SuppressWarnings : 让编译器对"它所标注的内容"的某些警告保持静默。可以修饰类、方法。
2. 元注解
元注解的作用就是负责注解其他注解,即修饰其他的注解。
常用的四种元注解:
① @Retention : 标识这个注解怎么保存,是只在代码中(SOURSE),还是编入class文件中(CLASS),
或者是在运行时可以通过反射访问(RUNTIME)。如@Retention(RetentionPolicy.SOURCE)。
SOURSE<CLASS<RUNTIME
② @Documented : 标记这些注解将被包含在用户文档(JavaDoc)中。
③ @Inherited : 标记子类可以继承父类的注解。
④ @Target : 标记这个注解的使用范围。如@Target(value=ElementType.METHOD)。
TYPE 意味着,它能标注"类、接口(包括注释类型)或枚举声明"。
FIELD 意味着,它能标注"字段声明"。
METHOD 意味着,它能标注"方法"。
PARAMETER 意味着,它能标注"参数"。
CONSTRUCTOR 意味着,它能标注"构造方法"。
LOCAL_VARIABLE 意味着,它能标注"局部变量"。
3. 自定义注解
使用@Interface自定义注解,自动继承了java.lang.annotation.Annotation接口。
其中的每一个方法实际上是声明了一个配置参数,方法的名称就是参数的名称,返回值类型就是参数的类型。
可以通过default来声明参数的默认值
如果只有一个参数成员,一般声明参数名为value
注解元素必须有值
自定义注解举例:
public class Demo1DefineAnnotation {
@MyAnnotation1(name = "张三") // 每个参数如果没有默认值必须赋值
public void test1() {}
@MyAnnotation2("张三") // 当注解中只有一个参数且参数名为value,写的时候可以省略参数名
public void test2(){}
}
@Inherited // 表示被这个注解修饰的类的子类可以继承父类的注解
@Documented // 表示注解可以被保存到JavaDoc中
@Target({ElementType.TYPE,ElementType.METHOD}) // 表示这个注解MyAnnotation1可以修饰类和方法
@Retention(RetentionPolicy.RUNTIME) // 表示这个注解MyAnnotation1可以保存到程序运行时
@interface MyAnnotation1{ // 自定义注解
String name(); // 注解的参数,不是方法
int age() default 0; // 设置age的默认值为0
}
@interface MyAnnotation2{ // 自定义注解
String value(); // 当只有一个参数成员,一般声明参数名为value
}
二. 反射
Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
加载完类之后,在堆内存的方法区中就产生了一个不变的Class类型(类)的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构,这个对象就像一面镜子,通过这个镜子看到类的结构,所以我们形象的称之为反射。
Class对象是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的Class对象。
1. 获取Class对象的方式:
① 通过对象获得:Class c1 = person.getClass()
② 通过forName获得:Class c2 = Class.forName(“Annotation.Student”)
③ 通过类名.class获得:Class c3 = Student.class
④ 通过基本内置类型的包装类的Type属性:Class c4 = Integer.TYPE
// 获取Class对象的方式
public class TestReflection {
public static void main(String[] args) throws ClassNotFoundException {
Student student = new Student();
// 方法一:通过对象获得
Class c1 = student.getClass();
System.out.println(c1+"\t"+c1.hashCode());
//方拾二:forName获得
Class c2 = Class.forName("Annotation.Student");
System.out.println(c2+"\t"+c2.hashCode());
//方式三:通过类名.class获得
Class c3 = Student.class;
System.out.println(c3+"\t"+c3.hashCode());
//方式四:基本内置类型的包装类都有一个Type属性
Class c4 = Integer.TYPE;
System.out.println(c4);
}
}
class Student {}
结果:
class Annotation.Student 460141958
class Annotation.Student 460141958
class Annotation.Student 460141958
int
同一个类只有一个Class对象
2. Class类的常用方法:
static Class forName(String name):返回指定类名name的Class对象
Object newInstance():返回一个Class对象的实例
String getName():返回此Class对象所表示的类的名称(包名+类名)
String getSimpleName():返回此Class对象所表示的类的名称(类名)
Class getSuperClass():返回当前Class对象的父类的Class对象
Class[] getInterfaces():获取被当前Class对象实现的接口
ClassLoader getClassLoader():获取该类的类加载器
Constructor[] getConstructors():获得本类的所有构造函数的对象数组
Method getMethod(String name, Class<?>... parameterTypes):返回指定名称和参数类型对象的public方法对象(包括继承父类的,但不包括构造方法)
Method[] getMethods():获得类中的所有public方法(包括继承父类的,但不包括构造方法)
Method getDeclaredMethod(String name, Class<?>... parameterTypes):返回本类指定名称和参数类型对象的方法对象(不包括继承的和构造方法)
Method[] getDeclaredMethods():获得本类的所有方法(不包括继承父类的和构造方法)
Field getField(String name):返回这个类中指定的属性(包括继承的),这个属性必须是public
Field[] getFields():返回这个类中所有(包括继承的)声明的属性对象数组,这个字段必须是public
Field getDeclaredField(String name):返回这个类中指定的属性(不包括继承的)
Field[] getDeclaredFields():返回这个类中所有(不包括继承的)声明的属性的对象数组
// Class对象的常用方法
public class Demo4Reflection {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class c1 = Class.forName("Annotation.Teacher"); //获取Class对象
// 获得类的名字
System.out.println(c1.getName()); // Annotation.Teacher
System.out.println(c1.getSimpleName()); // Teacher
System.out.println("================================");
// 获得类的属性
System.out.println(c1.getField("name")); // 获得指定的public属性
System.out.println("---------------------------------");
Field[] fields = c1.getFields(); // 获得所有的包括继承的public属性
for (Field field:fields) {
System.out.println(field+"\t");
}
System.out.println("---------------------------------");
System.out.println(c1.getDeclaredField("age")); // 获得指定的声明的属性
System.out.println("---------------------------------");
fields = c1.getDeclaredFields(); // 获得所有的不包括继承的属性
for (Field field:fields) {
System.out.println(field);
}
System.out.println("================================");
// 获得类的方法
System.out.println(c1.getMethod("setName",String.class)); // 获得指定名称和参数类型对象的方法,包括继承的
System.out.println("---------------------------------");
Method[] methods = c1.getDeclaredMethods(); // 获得所有的不包括继承的方法
for (Method method:methods) {
System.out.println(method);
}
System.out.println("================================");
//获得类的构造器
Constructor[] constructors = c1.getConstructors(); // 获得本类所有的构造器
for (Constructor constructor:constructors) {
System.out.println(constructor);
}
System.out.println("---------------------------------");
constructors = c1.getDeclaredConstructors(); // 获得本类所有的构造器
for (Constructor constructor:constructors) {
System.out.println(constructor);
}
System.out.println("---------------------------------");
// 获得指定的构造函数
System.out.println(c1.getConstructor(String.class,int.class,int.class,String.class));
}
}
class Person{
public String name;
private int id;
public Person() {
}
public Person(String name, int id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
class Teacher extends Person {
private int age;
String sex;
public Teacher() {
}
public Teacher(String name, int id, int age, String sex) {
super(name, id);
this.age = age;
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
结果:
Annotation.Teacher
Teacher
================================
public java.lang.String Annotation.Person.name
---------------------------------
public java.lang.String Annotation.Person.name
---------------------------------
private int Annotation.Teacher.age
---------------------------------
private int Annotation.Teacher.age
java.lang.String Annotation.Teacher.sex
================================
public void Annotation.Person.setName(java.lang.String)
---------------------------------
public int Annotation.Teacher.getAge()
public java.lang.String Annotation.Teacher.getSex()
public void Annotation.Teacher.setSex(java.lang.String)
public void Annotation.Teacher.setAge(int)
================================
public Annotation.Teacher()
public Annotation.Teacher(java.lang.String,int,int,java.lang.String)
---------------------------------
public Annotation.Teacher()
public Annotation.Teacher(java.lang.String,int,int,java.lang.String)
---------------------------------
public Annotation.Teacher(java.lang.String,int,int,java.lang.String)
3. 哪些类型有Class对象
class类、interface接口、[]数组、enum枚举、annotation注解、基本数据类型、void 等
public class TestReflection {
public static void main(String[] args) {
Class c1 = Object.class; // 类
Class c2 = Comparable.class; // 接口
Class c3 = String[].class; // 一维数组
Class c4 = int[][].class; // 二维数组
Class c5 = Override.class; // 注解
Class c6 = ElementType.class; // 枚举
Class c7 = Integer.class; // 基本数据类型
Class c8 = void.class; // void
Class c9 = Class.class; // Class
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);
System.out.println(c5);
System.out.println(c6);
System.out.println(c7);
System.out.println(c8);
System.out.println(c9);
int[] a = new int[10];
int[] b = new int[5];
// 只要元素类型和维度一致,就是同一个Class
System.out.println(a.getClass().hashCode()+" "+b.getClass().hashCode());
}
}
结果:
class java.lang.Object
interface java.lang.Comparable
class [Ljava.lang.String;
class [[I
interface java.lang.Override
class java.lang.annotation.ElementType
class java.lang.Integer
void
class java.lang.Class
460141958 460141958
4. 类的加载过程
① 编译:代码首先被编译成二进制字节码文件(.class文件)
② 加载:将class文件字节码内容加载到内存中,并将静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的Class对象
③ 链接:将Java类的二进制代码合并到JVM的运行状态之中的过程
- 验证:确保加载的类信息符合JVM规范,没有安全方面的问题
- 准备:为类变量(static)分配内存并设置类变量默认初始值
- 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)
④ 初始化:执行类构造器方法的过程,类构造器方法是由编译期自动收集类中的所有类变量(static)的赋值动作和静态代码块的语句合并产生的(类构造器是构造类信息的,不是构造该类对象的构造方法)。初始化一个类的时候,当发现其父类还没有初始化,需要先初始化其父类。
5. 类加载器
类加载器的作用是把类装载到内存中,即将class文件字节码内容加载到内存中,并将静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的Class对象。
类加载器有三种:
- 引导(根)类加载器(Bootstap Classloader):是JVM自带的类加载器,负责Java平台核心库,用来加载核心类库,无法直接获取
- 扩展类加载器(Extension Classloader):
- 系统类加载器(System Classloader):是最常用的加载器
Bootstap Classloader > Extension Classloader > System Classloader
// 类加载器
public class ClassLoader {
public static void main(String[] args) throws ClassNotFoundException {
// 获取系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
// 获取系统类加载器的父类加载器-->拓展类加载器
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent);
// 获取拓展类加载器的父类加载器-->根加载器
ClassLoader parent1 = parent.getParent();
System.out.println(parent1); // 无法直接获得,输出null
// 测试当前类是哪个类加载器加载的
ClassLoader classLoader = Class.forName("Annotation.ClassLoader").getClassLoader();
System.out.println(classLoader);
// 测试JDK内置的类是哪个加载器加载的
classLoader = Class.forName("java.lang.Object").getClassLoader(); // 根加载器
System.out.println(classLoader);
}
}
结果:
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@1b6d3586
null
sun.misc.Launcher$AppClassLoader@18b4aac2
null
双亲委派机制:
当一个类要被加载时,首先会在System ClassLoader中检查是否加载过,如果有那就无需再加载了。
如果没有,那么会拿到父加载器,父类中同理也会先检查自己是否已经加载过,如果没有再往上。
注意这个类似递归的过程,直到到达Bootstrap classLoader之前,都是在检查是否加载过,并不会选择自己去加载。
直到BootstrapClassLoader,已经没有父加载器了,这时候开始考虑自己是否能加载了。
如果自己无法加载,会下沉到子加载器去加载,一直到最底层,如果没有任何加载器能加载,就会抛出ClassNotFoundException。
一般自定义的类都由System ClassLoader加载
6. 有Class对象能做什么
① 通过反射动态的创建对象和调用方法与属性
// 通过反射动态的创建对象
// 通过反射调用方法和属性
public class Demo7 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Class c1 = Class.forName("Annotation.User"); // 获得Class对象
// 通过反射创建一个实例对象
User user = (User) c1.newInstance(); // 相当于调用无参构造器
System.out.println(user.toString());
// 通过构造器创建实例对象
Constructor constructor = c1.getDeclaredConstructor(int.class,String.class,int.class);
user = (User) constructor.newInstance(10101,"张三",18);
System.out.println(user.toString());
// 通过反射调用方法
Method setName = c1.getDeclaredMethod("setName", String.class); // 获得本类的指定方法setName
setName.invoke(user,"李四"); // invoke:激活
System.out.println(user);
// 通过反射操作属性
Field name = c1.getDeclaredField("name");
// 不能直接操作private属性,需要关闭程序的安全检测
name.setAccessible(true); // 关闭安全检测
name.set(user,"王五"); // 相当于 user.name = "王五"
System.out.println(user.getName());
}
}
class User{
private int id;
private String name;
private int age;
public User() {
}
public User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{id="+this.id+",name="+this.name+",age="+this.age+"}";
}
}
结果:
User{id=0,name=null,age=0}
User{id=10101,name=张三,age=18}
User{id=10101,name=李四,age=18}
王五
Method、Field、Constructor对象都有setAccessible()方法,作用是启动和禁用访问安全检查的开关
关闭安全检查setAccessible(true)能提高反射执行的效率
② 获取注解信息
// 通过反射获取注解信息
public class Demo10 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c1 = Class.forName("Annotation.User2");
//通过反射获得注解
Annotation[] annotations = c1.getAnnotations(); // 获得所有的注解
for (Annotation annotation:annotations) {
System.out.println(annotation);
}
//获得注解的参数值
ClassAnnotation classAnnotation = (ClassAnnotation) c1.getAnnotation(ClassAnnotation.class); // 获得指定的注解
String value = classAnnotation.value();
System.out.println(value);
//获得指定属性的注解
Field id = c1.getDeclaredField("id"); // 获得指定的属性
FieldAnnotation fieldAnnotation = id.getAnnotation(FieldAnnotation.class);
System.out.println(fieldAnnotation);
System.out.println(fieldAnnotation.name());
System.out.println(fieldAnnotation.type());
System.out.println(fieldAnnotation.Length());
}
}
@ClassAnnotation("User2")
class User2{
@FieldAnnotation(name = "id",type = "int",Length = 10)
private int id;
@FieldAnnotation(name = "name",type = "String",Length = 5)
private String name;
@FieldAnnotation(name = "age",type = "int",Length = 10)
private int age;
public User2() {
}
public User2(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User2{id="+this.id+",name="+this.name+",age="+this.age+"}";
}
}
// 类的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface ClassAnnotation{ // 自定义注解
String value(); // 参数
}
// 属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldAnnotation{
String name(); // 参数:属性名字
String type(); // 参数:属性类型
int Length(); // 参数:属性长度
}
结果:
@Annotation.ClassAnnotation(value=User2)
User2
@Annotation.FieldAnnotation(name=id, type=int, Length=10)
id
int
10