一. 反射
a. 类的加载时机
i. 创建类的实例
ii. 调用类的静态变量,或者为静态变量赋值
iii. 调用类的静态方法
iv. 使用某个类的子类
v. 直接使用java.exe命令来运行某个主类
vi. 使用反射强制加载某个类,并生成class对象
b. 类加载器
i. 类加载器:是负责将磁盘上的某个class文件读取到内存并生成Class的对象。
ii. Java中有三种类加载器
1) 启动类加载器(Bootstrap ClassLoader):用于加载系统类库<JAVA_HOME>\bin目录下的class,例如rt.jar。
2) 扩展类加载器(Extension ClassLoader):用于加载扩展类库<JAVA_HOME>\jre\lib\ext目录下的class。
3) 应用程序类加载器(Application ClassLoader):用于加载我们自定义类的加载器
iii. 双亲委派机制
1) 当某个类加载器需要加载一个类时,它并不是直接去加载,而把加载的需要交给父级类加载器,最终请求会达到到达启动类加载器,启动类加载判断是否可以加载该类,如果加载不了再交给扩展类加载器,扩展类加载判断是否可以加载,如果加载不了,再交给应用程序类加载器.
iv. 双亲委派机制的好处
1) 确保了一个类只加载一次
c. 反射
i. 反射就是在程序运行时获取一个类的Class对象(字节码文件对象),解剖它,取出其中的各种成员,使用这些成员
ii. 作用:
1) 开发"IDEA"等之类的IDE
2) 学习各种框架的设计和底层原理: Spring,SpringMVC,Mybatis,...
iii. 反射中万物皆对象的概念
1) Class对象 某个字节码文件
Field对象 某个成员变量
Method对象 某个成员方法
Constructor对象 某个构造方法
newInstance 创建对象
invoke 调用/执行
iv. 体验一下反射的语法
1) 创建对象:
a) 正常语法: new 构造方法(参数);
b) 反射语法: 构造方法对象.newInstance(参数);
2) 调用方法:
a) 正常语法: 对象名.成员方法名(参数);
b) 反射语法: 成员方法对象.invoke(对象名,参数);
v. 反射的第一步获取字节码文件对象
代码演示
public class GetClass02 {
public static void main(String[] args) throws ClassNotFoundException {
//获取一个类的Class对象的三种方式
//1.通过类的一个静态成员class
Class dogClass = Dog.class;
System.out.println(dogClass);
//2.通过该类的一个对象,获取该类的class对象
Dog dog = new Dog();
Class dogClass1 = dog.getClass();
System.out.println(dogClass1);
//3.通过反射强制加载该类,并获取该类的Class对象
Class dogClass3 = Class.forName("demo_class01.Dog");
System.out.println(dogClass3);
System.out.println(dogClass == dogClass1);
System.out.println(dogClass == dogClass3);
System.out.println(dogClass1 == dogClass3);
}
}
vi. Class对象中的三个方法
1) public String getName();
2) public String getSimple();
3) public Object newInstance();
代码演示
public class ClassMethod01 {
public static void main(String[] args) throws Exception{
Class dogClass = Dog.class;
//1.获取全限定类名
System.out.println(dogClass.getName());
//打印结果:demo_class01.Dog
//2.获取类名
System.out.println(dogClass.getSimpleName());
//打印结果:Dog
//3.创建Class对象所代表的那个类的对象,底层实际上使用Dog的无参构造
Object o = dogClass.newInstance();
//打印结果:Dog{name='null', age=0}
System.out.println(o);
}
}
vii. 通过反射获取构造方法&&使用构造方法创建对象
1) 反射获取构造方法
a) public Constructor getConstructor(Class…parameterTypes);获取单个"public"构造
b) public Constructor getDeclaredConstructor(class…parameterTypes);获取单个"任意修饰"构造
c) public Constructor[] getConstructors();获取所有"public"构造
d) public Constructor[] getDeclaredConstructors();获取所有"任意修饰"构造
2) 使用构造方法创建对象
a) 语法:构造方法对象.newInstance(参数);
b) 私有构造必须先设置暴力权限,然后才能正常使用,否则抛出IllegalAccessException异常
viii. 通过反射获取成员方法&&调用成员方法
1) 反射获取成员方法
a) public Method getMethod(String name,Class...args);获取"public"方法
b) public Method getDeclaredMethod(String name,Class...args);获取"任意修饰"方法
c) public Method[] getMethods(); 获取所有"public"方法,包括父类继承的
d) public Method[] getDeclaredMethods(); 获取所有"任意修饰"方法,不包含父类继承的
2) 调用成员方法
a) 格式:成员方法对象.invoke(对象名,参数);
b) 私有成员方法不能直接调用,必须先设置暴力访问权限,否则抛出IllegalAccessException异常
二. 注解
a. 介绍
i. 注解是JDK1.5的新特性(注解,增强for,泛型,可变参数)
ii. 注解相当一种标记,是类的组成部分,可以给类携带一些额外的信息
iii. 标记(注解),可以用在各种地方(包,类,构造方法,普通方法,成员变量,局部变量,...)
iv. 注解,主要是给编译器或者JVM看的,用于完成某些特定的功能
b. 作用
i. 给程序带入一些参数
ii. 编译检查
iii. 给框架使用,作为框架的配置文件
c. 常见的注解介绍
i. @author: 用来标识作者名
@version: 用于标识对象的版本号
@Override: 用于标识该方法是重写的
@deprecated: 用于标识过期的API
@Test: 用于单元测试的注解
d. 自定义注解(Annotation)
i. 自定义类: public class 类名
自定义接口: public interface 接口
自定义枚举: public enum 枚举名
自定义注解: public @interface 注解名
e. 给自定义注解添加属性
i. 格式:
public @interface 注解名{
//注解内部只有属性,没有别的!!
数据类型 属性名();
数据类型 属性名() [default 默认值];
}
ii. 注解中并不是所有数据类型都可以的!!!
只能是以下三大类型:
1) 八大基本类(byte,short,char,int,long,float,double,boolean)
2) String,Class,注解类型,枚举类
3) 以上12具体数据类型的数组
f. 使用注解时的注意事项
i. 使用格式:
@注解名(属性名=属性值,属性名=属性值)
ii. 注意:
1) 使用注解时保证注解的每个属性都必须有值(有默认值我们可以不再赋值,没有默认值我们必须赋值)
2) 如果是数组需要使用{}把值括起来,如果数组的值只有一个,那么大括号可以省略
iii. 特殊属性名value
1) 如果注解中"只有一个属性",并且名字叫做"value",那么使用时可以直接写属性的值,省略属性名
2) 如果注解中有value之外的其他属性,那么其他属性都有默认值,且使用注解时只给value赋值,那么直接写属性的值,省略属性名.
g. 注解的注解--元注解
i. @Target 元注解
1) 作用:用来标识注解使用的位置,如果没有标识,那么我们的注解在各种地方都可以使用
2) 取值:必须使用ElementType枚举下的值:
TYPE,类,接口
FIELD, 成员变量
METHOD, 成员方法
PARAMETER, 方法参数
CONSTRUCTOR, 构造方法
LOCAL_VARIABLE, 局部变量
3) 代码演示
//使用元注解修饰我们定义的注解
@Target({ElementType.FIELD,ElementType.METHOD})
public @interface MyAnno {
}
//使用我们定义的注解
@MyAnno//报错
public class Demo {
@MyAnno
private int age;
@MyAnno
private String name;
@MyAnno//报错
public Demo() {
}
@MyAnno//报错
public Demo(@MyAnno int age,@MyAnno String name) {
this.age = age;
this.name = name;
}
@MyAnno
public void show(@MyAnno int age){//报错
@MyAnno//报错
String name = "张三";
System.out.println(age);
}
}
ii. Retention元注解
1) 作用:用来标识我们注解的生命周期
2) 取值:必须是RetentionPolicy枚举中的下面三个值之一
a) SOURCE表示我们的注解只在源码阶段存在,编译成字节码文件后删除
b) CLASS表示我们的注解在源码阶段和字节码阶段存在,加载到内存后删除
c) RUNTIME表示我们的注解在源码阶段,字节码阶段,运行时都存在(永远不删除)
Java反射入门
最新推荐文章于 2024-11-13 20:43:20 发布