文章目录
反射(Reflect)
类加载
- 类在内存中的声明周期:加载→使用→卸载
类的加载过程
- 加载:将class加载到内存中
- 连接
① 验证:校验合法性/正确性(版本对不对)
②准备:准备对应的内存(方法区),创建Class对象,为类变量赋默认值,为静态常量赋初始值
③解析:把字节码中的符号引用替换为对应的直接地址引用
可以提高资源查找的速度 - 类的初始化<clinit>
- 类的初始化可能会滞后(即使类没有完成初始化,也能够使用部分资源)
类的初始化
- 那些操作会导致类的初始化
- 调用该类的main()方法,会导致该类完成初始化
- 当创建子类对象时,会先进行父类的初始化
- 使用类中静态资源时,会进行类的初始化
- 创建一个类的对象时,会进行该类的初始化
- 使用反射操作此类时,会进行该类的初始化
- 类的初始化滞后
- 当使用类中的静态常量的时候,不会触发类的初始化,因为在类的加载阶段完成了对静态常量的赋值
- 当子类使用父类extends过来的static方法时,只会对父类完成类的初始化,子类不会进行初始化
- 创建一个类型的数组时,不会触发对该类型的初始化
类加载器
-
类的加载器:加载类的
- 引导类加载器(根类加载器):加载java的核心类库:jre/rt.jar
- 扩展类加载器:负责加载jre/lib/ext扩展库
- 应用程序加载器:通过AppClassLoader加载 自己写的类
- 自定义类加载器:需要自主加载的内容
-
java系统类加载器的双亲委托模式:
先由当前类加载器查看是否加载过这个类如果没有加载过
父类加载器会查看是否加载过这个类继续向上传递
根加载器没有加载过这个类ClassNotFoundException
javalang.Class类
- Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
- 要想解剖一个类,必须先要获取到该类的Class对象。而剖析一个类或用反射解决具体的问题就是使用相关APl (1) java.lang.Class (2) java.lang.eflect.*。所以,Class对象是反射的根源。
哪些类型可以获取Class对象
所有java类型
1. 基本数据类型和void。例:int.class void.class
2. 类和接口。例:String.class Comparable.class
3. 枚举。例:ElementType.class
4. 注解。例:Override.class
5. 数组。例:int[].class
获取Class对象的四种方式
- 类型名.class:要求编辑期间已知类型
- 对象.getClass():获取对象的运行时类型
- Class.forName(类型全名称):可以获取编译期间未知的类型
class的作用
package com.z.reflect.clazz;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class ClassTest {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
Class aClass = Class.forName("com.z.reflect.clazz.Cat");
//获取当前类中的属性
// Field[] fields = aClass.getFields();//只能拿到public的属性
Field[] fields = aClass.getDeclaredFields();//获取所有的属性
for (Field field:fields){
System.out.println(Modifier.toString(field.getModifiers())+" ====>属性名: "+field.getName());
}
System.out.println("===================================================");
// 只能获取本类中的方法 私有(不局限public)
// Method[] declaredMethods = aClass.getDeclaredMethods();
//不仅可以获取到本类中的public的方法 也会拿到父类public的方法
Method[] declaredMethods = aClass.getMethods();
for (Method method : declaredMethods) {
System.out.println(method);
}
System.out.println("===================================================");
// Constructor[] constructors = aClass.getConstructors();
// 拿到所有的构造器
Constructor[] constructors = aClass.getDeclaredConstructors();
for (Constructor c : constructors) {
System.out.println(c);
}
System.out.println("===================================================");
// 拿父类
Class superclass = aClass.getSuperclass();
System.out.println(superclass);
System.out.println("===================================================");
// 拿接口
Class[] interfaces = aClass.getInterfaces();
for (Class anInterface : interfaces) {
System.out.println(anInterface);
}
}
}
class Cat implements Comparable{
private String name;
double height;
public String color;
private void show(){
System.out.println("this is show()");
}
@Override
public int compareTo(Object o) {
return 0;
}
}
获取Class对象的四种方法
package com.z.review;
public class Test1 {
public static void main(String[] args) throws ClassNotFoundException {
// 1. 类名.class
Class aClass = Person.class;
// 2. 对象名.getClass();
Person person = new Person();
Class aClass1 = person.getClass();
// 3. 通过类的加载器 再去获取class对象
Class aClass2 = aClass.getClassLoader().getClass();
// 4. 通过Class类的静态方法forName(类的全路径名)
Class aClass3 = Class.forName("com.z.review.Person");
}
}
class Person{}
使用反射创建对象
package com.z.createobject;
import java.util.Scanner;
/*
使用反射去创建对象
优点:
1. 灵活
2,可以在运行时再去确定要创建对象的类型
缺点:难以理解
*/
public class CreateTest {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
// 使用反射创建对象
// 1. 获取对应的Class对象
Scanner scanner = new Scanner(System.in);
System.out.println("请输入你要创建对象的全类名");
String next = scanner.next();
Class aClass = Class.forName(next);
// 2. 创建对象 调用了对应类的无参构造器
Object o = aClass.newInstance();
System.out.println(o);
}
}
class Student{
String name = "张三";
public Student() {
}
public Student(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
'}';
}
}
class Person{
String name = "张三";
int age;
public Person() {
}
private Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
- 调用有参构造器(一个参数) 完成对成员的初始化
// 调用有参构造器(一个参数) 完成对成员的初始化
// 1. 获取Class对象
Class clazz = Class.forName("com.z.createobject.Student");
// 2. 执行构造器
// 获取一个参数的构造器 方法是参数的Class
Constructor constructor = clazz.getConstructor(String.class);
// 3. 执行构造器
Object instance = constructor.newInstance("lisi");
// 4. 输出结果
System.out.println(instance);
- 调用有参构造器(多个参数) 完成对成员的初始化
// 调用有参构造器(多个参数) 完成对成员的初始化
// 1. 获取Class对象
Class clazz1 = Class.forName("com.z.createobject.Person");
// 2. 执行构造器
// 获取的构造器是非public 要是用getDeclaredConstructor
Constructor c = clazz1.getDeclaredConstructor(String.class,int.class);
// 设置私有的构造器可以访问
c.setAccessible(true);
// 3. 执行构造器
Object instance1 = c.newInstance("lisi",18);
// 4. 输出结果
System.out.println(instance1);
使用反射操作属性
package com.z.field;
import java.lang.reflect.Field;
public class TestField {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException {
// 1. 获取对应的Class对象
Class aClass = Class.forName("com.z.field.Person");
// 2. 获取对应的属性
/* 获取公共属性
Field[] fields = aClass.getFields();
for (Field field : fields) {
System.out.println(field);
}*/
// 获取公共属性
Field sex = aClass.getField("sex");
// 获取静态属性
Field country = aClass.getField("country");
// 获取私有属性
Field name = aClass.getDeclaredField("name");
name.setAccessible(true);//设置私有属性可见
// 3. 创建对象
// 调用无参构造器创建对象
Object instance = aClass.newInstance();
// 3.1 修改属性值
name.set(instance,"张三");
// 4. 获取属性值
Object o = sex.get(instance);
// 静态变量 可以不用创建对象 直接使用
Object o1 = country.get(null);
Object value = name.get(instance);
System.out.println(o);
System.out.println(o1);
System.out.println(value);
}
}
class Person{
public static String country = "China";
private String name = "李白";
double height = 1.78;
public String sex = "男";
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", height=" + height +
", sex='" + sex + '\'' +
'}';
}
}
使用反射操作方法
- 静态的方法可以不用创建对象直接调用
- 非静态方法必须创建对象调用
- 私有方法要设置私有方法可见
package com.z.method;
import java.lang.reflect.Method;
public class MethodTest{
public static void main(String[] args) throws Exception {
// 1. 获取Class对象
Class aClass = Class.forName("com.z.method.Person");
// 2. 获取指定方法
Method show = aClass.getDeclaredMethod("show");
Method test = aClass.getDeclaredMethod("test", int.class, int.class);
Method showMessage = aClass.getDeclaredMethod("ShowMessage");
showMessage.setAccessible(true);//设置私有可见
// 3. 创建对象
Object instance = aClass.newInstance();
// 4. 执行方法
// show.invoke(instance);
show.invoke(null);//show 是静态方法属于类的,可以不用传递对象
test.invoke(instance,10,20);
showMessage.invoke(instance);
}
}
class Person {
public static String country = "China";
private String name = "李白";
double height = 1.78;
public String sex = "男";
private void ShowMessage() {
System.out.println("this is private ShowMessage()");
}
public void test(int a, int b) {
System.out.println("a+b的和为:" + (a + b));
}
public static void show() {
System.out.println("this is show()");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", height=" + height +
", sex='" + sex + '\'' +
'}';
}
}
使用反射获取注解
package com.z.ann;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)//指注解可以存活到运行时
public @interface MyAnn {
String value() default "haha";
}
package com.z.ann;
@MyAnn(value = "李白")//如未赋值则为默认值haha
public class Person {}
package com.z.ann;
import java.lang.annotation.Annotation;
public class TestAnn {
public static void main(String[] args) throws Exception {
// 1. 获取Class对象
Class aClass = Class.forName("com.z.ann.Person");
/*获取所有的注解
Annotation[] annotations = aClass.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}*/
Annotation annotation = aClass.getAnnotation(MyAnn.class);
System.out.println(annotation);
}
}
使用反射突破泛型限制
package com.z.list;
import com.z.ann.Person;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
public class ListTest {
public static void main(String[] args) throws Exception{
ArrayList<Integer> list = new ArrayList<>();
list.add(10);
// list.add(new Date());
Class aClass = list.getClass();
Method addMethod = aClass.getDeclaredMethod("add", Object.class);
// Date Person 都不属于Integer类型
addMethod.invoke(list,new Date());
addMethod.invoke(list,new Person());
System.out.println(list);
}
}
使用反射创建数组
package com.z.arr;
import java.lang.reflect.Array;
public class TestArr {
public static void main(String[] args) {
// 创建了一个数组, 长度是5
Object o = Array.newInstance(String.class, 5);
Array.set(o,0,"李白");
Array.set(o,1,"杜甫");
Object o1 = Array.get(o, 1);
System.out.println(o1);//杜甫
Object o2 = Array.get(o, 2);
System.out.println(o2);//null
}
}