JAVA反射-刘意公开课归纳总结

· 类的加载概述和加载时机

一、类的基本组成

  1. 成员变量
  2. 构造方法
  3. 成员方法

二、类的加载

  1. 加载

    将class文件读入内存,并为之创建一个Class对象。

  2. 链接

    验证 内部结构是否正确并于其他类协调一致。

    准备 为类的静态成员分配内存,并设置默认初始化值。

    解析 将二进制数据中的符号引用替换为直接引用。

  3. 初始化

    为栈、堆内存开辟空间、默认初始化、显示初始化、构造初始化。

三、类初始化时机

  1. 创建类的实例。
  2. 访问类的静态变量,或为静态变量赋值。
  3. 调用类的静态方法。
  4. 使用反射的方式强制创建某额类或接口对应的Class对象。
  5. 初始化某个类的子类。
  6. 世界使用java.exe命令运行某个主类。

· 类加载器的概述和分类

一、类加载器的职责

负责将.class文件加载到内存中,并为之生产Class对象。

二、类加载器的组成

1.Bootstrap ClassLoader 根类加载器

也称为引导类加载器,负责Java核心类的加载,比如System.String等,在JDK中JRE的lib目录下rt.jar文件中的包。

2.Extension ClassLoader 扩展类加载器。

负责加载JRE的扩展目录中的包,比如JDK中HRE的lib目录下ext目录中的包

3.System ClassLoader 系统类加载器

负责在JVM启动时加载来自java命令的class文件以及classpath环境变量所指的的jar包和类路径,也就是我们自己写或引用进来的包。

· Java反射概述

  1. 反射就是通过class文件,去使用该文件中的成员变量、构造方法、成员方法,而非通过java文件
  2. 要想这样使用,首先必须获得class文件对象,也就是Class类对象
  3. 在Class类中包含成员变量、构造方法、成员方法,而对Class类而言他们都被包含在对应的类中
    成员变量 Field
    构造方法 Constructor
    成员方法 Method
  4. 通过类的Class类对象调用方法使用其中类(Field/Constructor/Method)中的对象去调用方法就叫反射
  5. 也就是不需要使用import就可以使用该类
  6. 好处是可以通过配置文件变更具体的引用类,不需要修改代码

· 反射中的具体操作

Person类

package cn.xxx;

public class Person {
	private String name;
	int age;
	public String address;

	public Person(){}

	Person(String name){
		this.name = name;
	}

	Person(String name,int age){
		this.name = name;
		this.age = age;
	}

	public Person(String name,int age,String address){
		this.name = name;
		this.age = age;
		this.address = address;
	}

	public void show(){
		System.out.println("show");
	}

	private void method(String s){
		System.out.println(s);
	}
	
	@Override
	public void toString(){
		return "Person[name="+name+",age="+age+",address="+address+"]";
	}
}

一、获取class文件对象的三种方法

1. Objec类中的getClass()方法

	Person p1 = new Person();
	Class c1 = p1.getClass();

2. 数据类型的静态属性class

	Class c2 = Person.class;

3. Class类中的静态方法 public static Class forName(String className)

	Class c3 = Class.forName("cn.xxx.Person");

并且:

	Person p2 = new Person();
	System.out.println(p1==p2); // false
	System.out.println(c1==c2); // true
	System.out.println(c2==c3); // true

二、通过反射获取内部方法并使用

1.获取无参构造方法并使用

A.getConstructors(),但只能获取到公共的构造方法
	// 获取字节码文件对象
	Class c = Class.forName("cn.xxx.Person");
	Constructor[] cons = c.getConstructors();
	// 打印所有构造方法
	for(Constructor con : cons){
		System.out.println(con);
	}
	// public cn.xxx.Person()
	// public cn.xxx.Person(java.lang.String,int) 
B.getDeclaredConstructors(),可以获取全部构造方法
	Class c
	// 获取字节码文件对象 = Class.forName("cn.xxx.Person");
	Constructor[] cons = c.getDeclaredConstructors();
	// 打印所有构造方法
	for(Constructor con : cons){
		System.out.println(con);
	}
	// public cn.xxx.Person()
	// private cn.xxx.Person(java.lang.String)
	// cn.xxx.Person(java.lang.String,int,java.lang.String)
	// public cn.xxx.Person(java.lang.String,int) 
C.getConstructor(Class<?>… parameterType),可以获取单个构造方法,但只能获取到公共的构造方法
	// 获取字节码文件对象
	Class c = Class.forName("cn.xxx.Person");
	
	Constructor con = c.getConstructor();
	System.out.println(con);
	// public cn.xxx.Person()
	
	// 实例化新的对象
	// 1. Person p = new Person();
	// 2. 使用该Constructor对象表示的构造方法的声明类的新实例,并指定的出书画参数初始化该实例
	// 	↑↑↑↑public T newInstance(Object... initargs)↑↑↑
	//
	// 通过构造方法创建对象
	Constructor con1 = c.getConstructor();
	Object obj = con.newInstance();
	System.out.println(obj);
	// Person[name=null, age=0, address=null]
	

下方<2.获取有参构造方法并使用>有实际运用

D.getDeclaredConstructor(Class<?>… parameterType),可以获取全部类型的构造方法

下方< 3.获取有私有参构造方法并使用>有实际运用

2.获取有参构造方法并使用

使用getConstructor(Class<?>… parameterType)
	// 获取字节码文件对象
	Class c = Class.forName("cn.xxx.Person");
	// 通过构造方法创建对象
	Constructor con = c.getConstructor(String.class, int.class, String.class);
	Object obj = con.newInstance("姓名",24,"地址");
	System.out.println(obj);
	// Person[name=姓名, age=24, address=地址]

3.获取有私有参构造方法并使用

使用getDeclaredConstructor(Class<?>… parameterType),可以获取全部类型的构造方法
	// 获取字节码文件对象
	Class c = Class.forName("cn.xxx.Person");
	
	// 此处会报NoSuchMethodException异常,没有该方法,原因是该方法为private类型
	Constructor con1 = c.getConstructor(String.class);

	// 所以要改用getDeclaredConstructor(Class<?>... parameterType)
	Constructor con2 = c.getDeclaredConstructor(String.class);
	
	// 但直接使用该私有发放创建对象依旧会报错--IllegalAccessException非法访问,
	Object obj1 = con.newInstance("姓名");
	
	// 所以要使用setAccessible修改对象的accessible标识
	// pubilc void setAccessible(boolean falg) :
	// 将此对象的accessible标识设置为指示的布尔值,
	// 值为true则指示反射的对象在使用时应取消Java语言访问检查,
	// 值为false则指示反射的对象应该实施Java语言访问检查
	con.setAccessible(true);
	Object obj2 = con.newInstance("姓名");

	System.out.println(obj2);
	// Person[name=姓名, age=0, address=null]

三、通过反射获取成员变量并使用

1.getFields()

同通过反射获取内部方法

2.getDeclaredFields();

同通过反射获取内部方法

3.getField(String fieldName);

同通过反射获取内部方法

4.getDeclaredField(String fieldName);

同通过反射获取内部方法

5.对成员变量进行具体操作

	// 获取字节码文件对象
	Class c = Class.forName("cn.xxx.Person");

	// 通过无参构造方法创建对象
	Constructor con = c.getConstructor();
	Object obj = con.newInstance();

	// 获取public成员变量
	// 获取address并对其赋值
	Field addressField = c.getField("address");
	// 使用public void set(Object obj,Object value)
	// 将指定对象变量上此Field对象表示的字段设置为指定的新值
	addressField .set(obj,"地址");
	// Person[name=null, age=0, address=地址]

	// 获取private成员变量
	// 获取age并对其赋值
	Field ageField = c.getDeclaredField("age");
	// 使用public void set(Object obj,Object value)
	// 将指定对象变量上此Field对象表示的字段设置为指定的新值
	ageField.setAccessible(true);
	ageField.set(obj,24);
	// Person[name=null, age=24, address=null]

四、通过反射获取成员方法并使用

1.getMethods()

同通过反射获取内部方法

2.getDeclaredMethods();

同通过反射获取内部方法

3.getMethod(String methodName);

同通过反射获取内部方法

4.getDeclaredMethod(String methodName);

同通过反射获取内部方法

5.对成员变量进行具体操作

	// 获取字节码文件对象
	Class c = Class.forName("cn.xxx.Person");

	// 通过无参构造方法创建对象
	Constructor con = c.getConstructor();
	Object obj = con.newInstance();

	// public Method getMethod(String methodName, Class<?>... parameterTypes)
	// methodName方法名,parameterTypes方法的参数class的类型
	Method m1 = c.getMethod("show");
	// public Object invoke(Object obj,Object... args)
	// 第一个参数表示对象是谁,第二参数表示调用该方法的实际参数
	m1.invoke(obj);
	// show

	Method m2 = c.getMethod("method",String.class);
	m2.setAccessible(true);
	m2.invoke(obj,"hello");
	// hello
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值