一、入门
反射机制的重要性在于:通过外部文件配置,在不修改源码情况下来控制程序,也符合设计模式的ocp原则(开闭原则:不修改源码,扩容功能)
package hspedu.reflection_question;
import hspedu.Cat;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
/**
* 反射问题的引入
*/
@SuppressWarnings({"all"})
public class ReflectionQuestion {
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
//根据配置文件re.properties指定信息,创建Cat对象并调用方法hi
//传统方式:new 对象——》调用方法
//Cat cat = new Cat();
//cat.hi();
//——》如果要调用cry()方法,那就要修改源码——》cat.cry();
//但如果用反射机制,则只需要在配置文件中修改即可——》method=cry
//使用反射
//1、使用Properties类,可以读写配置文件
Properties properties = new Properties();
properties.load(new FileInputStream("src\\re.properties"));
String classfullpath=properties.get("classfullpath").toString();
String methodName=properties.get("method").toString();
System.out.println("classfullpath"+classfullpath);
System.out.println("methodName"+methodName);
//2、创建对象,用传统的方法,行不通——》反射机制
//(1)加载类,返回Class类型的对象cls
Class cls=Class.forName(classfullpath);
//(2)通过cls得到你加载的类hspedu.Cat的对象实例
Object o=cls.newInstance();
System.out.println("o的运行类型:"+o.getClass());
//(3)通过cls得到你加载的类hspedu.Cat的methodName"hi"的方法对象
//即:在反射中,可以把方法视为对象(万物皆对象)
Method method1=cls.getMethod(methodName);
System.out.println("==========================");
//(4)通过method1调用方法:即通过方法对象来实现调用方法
method1.invoke(o);//传统方法:对象.方法();反射机制:方法.invoke(对象);
}
}
//classfullpathhspedu.Cat
//methodNamehi
//o的运行类型:class hspedu.Cat
//==========================
//hi 招财猫
配置文件:
二、反射机制:
1、反射机制允许程序在执行期间借助于ReflectionAPI取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到。
2、加载完类后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构,这个Class对象就像一面镜子,透过这个镜子看到类的结构,所以,形象地称之为:反射。
3、java反射机制可以完成(到处乱窜)
(1)在运行时判断任意一个对象所属的类
(2)在运行时构造任意一个类的对象
(3)在运行时得到任意一个类所具有的成员变量和方法
(4)在运行时调用任意一个对象的成员变量和方法
(5)生成动态代理(简单理解:代码前后不变,中间部分可动态改变)
4、
package hspedu.reflection;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
@SuppressWarnings({"all"})
public class Reflection01 {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
properties.load(new FileInputStream("src\\re.properties"));
String classfullpath=properties.get("classfullpath").toString();
String methodName=properties.get("method").toString();
Class cls=Class.forName(classfullpath);
Object o=cls.newInstance();
System.out.println("o的运行类型:"+o.getClass());
Method method1=cls.getMethod(methodName);
System.out.println("==========================");
method1.invoke(o);
//java.lang.reflect.Field: 代表类的成员变量,Field对象表示某个类的成员变量
//得到name字段
//getField不能得到私有的属性
Field nameField=cls.getField("age");
System.out.println(nameField.get(o));//传统写法:对象.成员变量;反射:成员变量对象.get(对象);
//java.lang.reflect.Constructor: 代表类的构造方法,Constructor对象表示构造器
Constructor constructor=cls.getConstructor();//()中可以指定构造器参数类型
System.out.println(constructor);//使用无参构造器:Cat()
Constructor constructor2=cls.getConstructor(String.class);//这里传入的String.class就是String的Class对象
System.out.println(constructor2);//使用有参构造器:Cat(String name)
}
}
//o的运行类型:class hspedu.Cat
//==========================
//hi 招财猫
//0
//public hspedu.Cat()
//public hspedu.Cat(java.lang.String)
5、反射的优点和缺点:
(1)优点:可以动态地创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支撑
(2)缺点:使用反射基本是解释执行,对执行速度有影响
package hspedu.reflection;
import hspedu.Cat;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 测试反射调用的性能和优化方法
*/
@SuppressWarnings({"all"})
public class Reflection02 {
public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
m1();
m2();
}
//传统方法来调用hi
public static void m1(){
Cat cat = new Cat();
long start=System.currentTimeMillis();
for(int i=0;i<900000;i++){
cat.hi();
}
long end=System.currentTimeMillis();
System.out.println("传统方法来调用hi耗时:"+(end-start));
}
//反射机制调用方法hi
public static void m2() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Class cls=Class.forName("hspedu.Cat");
Object o=cls.newInstance();
Method hi=cls.getMethod("hi");
long start=System.currentTimeMillis();
for(int i=0;i<900000;i++){
hi.invoke(o);//反射调用方法
}
long end=System.currentTimeMillis();
System.out.println("反射机制调用方法hi耗时:"+(end-start));
}
}
//传统方法来调用hi耗时:5
//反射机制调用方法hi耗时:90
6、反射调用优化-关闭访问检查:
(1)Method和Feild, Constructor对象都有setAccessible()方法
(2)setAccessible作用是启动和禁用访问安全检查的开关
(3)参数值为true表示反射的对象在使用时取消访问检查,提高反射的效率。参数值为false则表示反射的对象执行访问检查
package hspedu.reflection;
import hspedu.Cat;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 测试反射调用的性能和优化方法
*/
@SuppressWarnings({"all"})
public class Reflection02 {
public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
m1();
m2();
m3();
}
//传统方法来调用hi
public static void m1(){
Cat cat = new Cat();
long start=System.currentTimeMillis();
for(int i=0;i<900000;i++){
cat.hi();
}
long end=System.currentTimeMillis();
System.out.println("传统方法来调用hi耗时:"+(end-start));
}
//反射机制调用方法hi
public static void m2() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Class cls=Class.forName("hspedu.Cat");
Object o=cls.newInstance();
Method hi=cls.getMethod("hi");
long start=System.currentTimeMillis();
for(int i=0;i<900000;i++){
hi.invoke(o);//反射调用方法
}
long end=System.currentTimeMillis();
System.out.println("反射机制调用方法hi耗时:"+(end-start));
}
//反射调用优化+关闭访问检查
public static void m3() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Class cls=Class.forName("hspedu.Cat");
Object o=cls.newInstance();
Method hi=cls.getMethod("hi");
hi.setAccessible(true);//在反射调用方法时,取消访问检查
long start=System.currentTimeMillis();
for(int i=0;i<900000;i++){
hi.invoke(o);//反射调用方法
}
long end=System.currentTimeMillis();
System.out.println("反射调用优化+关闭访问检查 调用方法hi耗时:"+(end-start));
}
}
//传统方法来调用hi耗时:0
//反射机制调用方法hi耗时:80
//反射调用优化+关闭访问检查 调用方法hi耗时:40
三、Class类
1、Class也是类,因此也继承Object类
2、Class类对象不是new出来的,而是系统创建的
3、对于某个类的Class类对象,在内存中只有一份,因为类只加载一次
4、每个类的实例都会记得自己是由哪个Class实例所生成
5、通过Class可以完整地得到一个类的完整结构,通过一系列API
6、Class对象是存放在堆的
7、类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括方法代码,变量名,方法名,访问权限等等)
package hspedu.reflection.class_;
import hspedu.Car;
import java.lang.reflect.Field;
/**
* 演示Class类的常用方法
*/
public class Class02 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
String classAllPath="hspedu.Car";
//1、获取到Car类对应的Class对象
//<?>表示不确定的java类型
Class<?> cls=Class.forName(classAllPath);
//2、根据Class对象获取对应的类
System.out.println(cls);
System.out.println(cls.getClass());//输出cls的运行类型
//3、得到包名
System.out.println(cls.getPackage().getName());
//4、得到类名
System.out.println(cls.getName());
//5、通过Class对象创建对象实例
Car car=(Car)cls.newInstance();
System.out.println(car);//调用了car.toString();
//6、通过反射获取对象实例的属性brand
Field brand = cls.getField("brand");
System.out.println(brand.get(car));
//7、通过反射给属性赋值
brand.set(car,"奔驰");
System.out.println(brand.get(car));
//8、得到所有的属性(字段)
Field[] fields = cls.getFields();
for(Field f:fields){
System.out.println(f.getName());//得到所有属性的名称
}
}
}
//class hspedu.Car
//class java.lang.Class
//hspedu
//hspedu.Car
//Car{brand='宝马', price=500000, color='白色'}
//宝马
//奔驰
//brand
//price
//color
8、获取Class类对象
(1)前提:已知一个类的全类名,且该类在类的路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException,
实例:Class cls1=Class.forName("java.lang.Cat");
应用场景:多用于配置文件,读取类全路径,加载类
(2)前提:若已知具体的类,通过类的class获取,该方式最为安全可靠,程序性能最高,
实例:Class cls2=Cat.class;
应用场景:多用于参数传递,比如通过反射得到对应构造器对象
(3)前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象,
实例:Class clazz=对象.getClass();
应用场景:通过创建好的对象,获取Class对象
(4)其他方式:
ClassLoader cl=对象.getClass().getClassLoader();
Class clazz4=cl.loadClass("类的全类名");
(5)基本数据(int, char, boolean, float, double, byte, long, short)按如下方式得到Class类
Class cls=基本数据类型.class
(6)基本数据类型对应的包装类,可以通过.TYPE得到Class类对象
Class cls=包装类.TYPE
package hspedu.reflection.class_;
import hspedu.Car;
/**
* 演示得到Class对象的各种方式
*/
public class GetClass_ {
public static void main(String[] args) throws ClassNotFoundException {
//1、Class.forName
String classAllPath = "hspedu.Car";
Class<?> cls1 = Class.forName(classAllPath);
System.out.println(cls1);
//class hspedu.Car
//2、类名.class
Class cls2=Car.class;
System.out.println(cls2);
//class hspedu.Car
//3、对象.getClass()
Car car = new Car();
Class cls3=car.getClass();
System.out.println(cls3);
//class hspedu.Car
//4、通过类加载器[4种]来获取到类的Class对象
//(1)先得到类加载器car
ClassLoader classLoader = car.getClass().getClassLoader();
Class cls4=classLoader.loadClass(classAllPath);
System.out.println(cls4);
//class hspedu.Car
//cls1,cls2,cls3,cls4其实是同一个对象
System.out.println(cls1.hashCode());
System.out.println(cls2.hashCode());
System.out.println(cls3.hashCode());
System.out.println(cls4.hashCode());
//2129789493
//2129789493
//2129789493
//2129789493
//5、
Class<Integer> integerClass = int.class;
Class<Character> characterClass = char.class;
Class<Boolean> booleanClass = boolean.class;
System.out.println(integerClass);
//int
//6、
Class<Integer> type = Integer.TYPE;
Class<Character> type1 = Character.TYPE;
System.out.println(type);
//int
System.out.println(integerClass.hashCode());
System.out.println(type.hashCode());
//1808253012
//1808253012
}
}
9、哪些类型有Class对象
(1)外部类,成员内部类,静态内部类,局部内部类,匿名内部类
(2)inteface接口
(3)数组
(4)enum:枚举
(5)annotation: 注解
(6)基本数据类型
(7)void
package hspedu.reflection.class_;
import java.io.Serializable;
/**
* 演示哪些类型有Class对象
*/
public class AllTypeClass {
public static void main(String[] args) {
Class<String> cls1 = String.class;//外部类
Class<Serializable> cls2 = Serializable.class;//接口
Class<Integer[]> cls3 = Integer[].class;//数组
Class<float[][]> cls4 = float[][].class;//二维数组
Class<Deprecated> cls5 = Deprecated.class;//注解
Class<Thread.State> cls6 = Thread.State.class;//枚举
Class<Long> cls7 = long.class;//基本数据类型
Class<Void> cls8 = void.class;//void数据类型
Class<Class> cls9 = Class.class;
System.out.println(cls1);
System.out.println(cls2);
System.out.println(cls3);
System.out.println(cls4);
System.out.println(cls5);
System.out.println(cls6);
System.out.println(cls7);
System.out.println(cls8);
System.out.println(cls9);
}
}
//class java.lang.String
//interface java.io.Serializable
//class [Ljava.lang.Integer;
//class [[F
//interface java.lang.Deprecated
//class java.lang.Thread$State
//long
//void
//class java.lang.Class
10、类加载
(1)基本说明:反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载
1)静态加载:编译时加载相关的类,如果没有则报错,(不管你用不用,它都要存在)依赖性太强
import java.util.*
public class ClassLoad_{
public static void main(String[] args){
Scanner scanner=new Scanner(System.in);
System.out.println("请输入key:");
String key=scanner.next();
switch(key){
case "1":
Dog dog=new Dog();//静态加载
dog.cry();
break;
case "2":
System.out.println("ok");
break;
default:
System.out.println("do nothing...");
break;
}
}
}
2)动态加载:运行时加载需要的类,如果运行时不用该类,则即使不存在也不报错,降低了依赖性
import java.util.*;
import java.lang.reflect.*;
public class ClassLoad_{
public static void main(String[] args) throws Exception{
Scanner scanner=new Scanner(System.in);
System.out.println("请输入key:");
String key=scanner.next();
switch(key){
case "1":
Dog dog=new Dog();//静态加载
dog.cry();
break;
case "2":
//反射——》动态加载
Class cls=Class.forName("Person");//创建一个Class类,加载Person类 [动态加载]
Object o=cls.newInstance();//用Class类,创建一个Object类型的,实例对象
cls.getMethod("hi").invoke(o);//通过Class类来调用方法
//调用方法
System.out.println("ok");
break;
}
}
}
//因为new Dog()是静态加载,因此必须编写Dog
//Person类是动态加载,所以,没有编写Person类也不会报错,只有当动态加载该类时,才会报错
class Dog{
public void cry(){
System.out.println("汪汪叫。。。");
}
}
(2)类加载时机:
1)当创建对象时(new)——》静态加载
2)当子类被加载时,父类也加载——》静态加载
3)调用类中的静态成员时——》静态加载
4)通过反射——》动态加载
(3)类加载图
1)加载阶段:
JVM在该阶段的主要目的是将字节码从不同的数据源(可能是class文件、也可能是jar、甚至网络)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象
2)连接阶段 -- 验证:
· 目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全
· 包括:文件格式验证(是否以魔数oxcafebabe开头),元数据验证、字节码验证和符号引用验证
· 可以考虑使用-Xverify:none 参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间
3)连接阶段 -- 准备
· JVM会在该阶段对静态变量,分配内存并默认初始化(对应数据类型的默认初始值,如0、0L、null、false等),这些变量所使用的内存都将在方法区中进行分配
package hspedu.reflection.classload;
public class ClassLoad02 {
public static void main(String[] args) {
}
}
class A{
//属性-成员变量-字段
//在类加载的连接阶段-准备 属性是如何处理的
//1、n1是实例属性,不是静态变量,因此在准备阶段,是不会分配内存
//2、n2是静态变量,分配内存 n2是默认初始化0,而不是20
//3、n3是static final是常量,他和静态变量不一样,因为一旦赋值就不变 ,n3=30
public int n1=10;
public static int n2=20;
public static final int n3=30;
}
4)连接阶段 -- 解析
· 虚拟机将常量池内的符号引用替换为直接引用的过程
5)初始化(Initialization)
· 到初始化阶段,才真正开始执行类中定义的java程序代码,此阶段是执行<clinit>() 方法的过程
· <clinit>() 方法是由编译器按语句在源文件中出现的顺序,依次按顺序自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并进行合并。
· 虚拟机会保证一个类的<clinit>() 方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的<clinit>() 方法,其他线程都需要阻塞等待,直到活动线程执行<clinit>() 方法完毕
package hspedu.reflection.classload;
public class ClassLoad03 {
public static void main(String[] args) throws ClassNotFoundException {
//1、加载B类,并生成B的class对象
//2、连接num=0,静态变量,默认赋值为0
//3、初始化阶段
/*
收集:
clinit(){
System.out.println("B 静态代码块被执行");
num=300;
num=100;
}
合并:
num=100;
*/
//System.out.println(B.num);
//B 静态代码块被执行
//100
new B();
System.out.println(B.num);
//B 静态代码块被执行
//B() 构造器被执行
//100
//如果直接使用类的静态属性,也会导致类的加载
//在加载类时,是由同步机制控制
//正因为有这个机制,才能保证某个类在内存中,只有一份Class对象
/*
源码:
protected Class<?> loadClass(String name,boolean resolve) throws ClassNotFoundException{
synchronized(getClassLoadingLock(name)){
//.....
}
}
*/
B b=new B();
}
}
class B{
static{
System.out.println("B 静态代码块被执行");
num=300;
}
static int num=100;
public B(){
System.out.println("B() 构造器被执行");
}
//如果main方法里new了一个对象,那么构造器就会被引用,否则不会引用
}
四、通过反射获取类的结构信息
1、第一组:java.lang.Class类
package hspedu.reflection;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* 只要拿到Class对象,几乎就可以得到该类的所有信息(属性、方法、构造器、接口、注解)
*/
public class ReflectionUtils {
public static void main(String[] args) throws ClassNotFoundException {
//得到Class对象
Class<?> personCls=Class.forName("hspedu.reflection.Person");
//获取全类名
System.out.println(personCls.getName());
//获取简单类名
System.out.println(personCls.getSimpleName());
//获取所有public修饰的属性,包含本类以及父类的
Field[] fields = personCls.getFields();
for (Field field :fields) {
System.out.println("本类以及父类的public属性:"+field.getName());
}
//获取本类中所有的属性
Field[] declaredFields = personCls.getDeclaredFields();
for (Field declaredField :declaredFields) {
System.out.println("本类中所有属性:"+declaredField.getName());
}
//获取所有public修饰的方法,包含本类以及父类的
Method[] methods = personCls.getMethods();
for (Method method :methods) {
System.out.println("本类以及父类的public方法:"+method.getName());
}
//获取本类中所有的方法
Method[] declaredMethods = personCls.getDeclaredMethods();
for (Method declaredMethod :declaredMethods) {
System.out.println("本类中所有的方法:"+declaredMethod.getName());
}
//获取所有public修饰的构造器,包含本类以及父类的
Constructor<?>[] constructors = personCls.getConstructors();
for (Constructor<?> constructor :constructors) {
System.out.println("本类以及父类的public构造器:"+constructor.getName());
}
//获取本类中所有构造器
Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
for (Constructor<?> declaredConstructor :declaredConstructors) {
System.out.println("本类中所有构造器:"+declaredConstructor.getName());//这里只是输出名字
}
//以Package形式返回包信息
System.out.println("包信息:"+personCls.getPackage());
//以Class形式返回父类信息
Class<?> superclass = personCls.getSuperclass();
System.out.println("父类的class对象:"+superclass);
//以Class[]形式返回接口信息
Class<?>[] interfaces=personCls.getInterfaces();
for (Class<?> anInterface :interfaces) {
System.out.println("接口信息:"+anInterface);
}
//以Annotation[] 形式返回注解信息
Annotation[] annotations = personCls.getAnnotations();
for (Annotation annotation :annotations) {
System.out.println("注解信息:"+annotation);
}
}
}
class A{
//属性
public String hobby;
//构造器
public A(){
}
//方法
public void hi(){
}
}
interface IA{
}
interface IB{
}
@Deprecated
class Person extends A implements IA,IB{
//属性
public String name;
protected int age;
String job;
private double sal;
//构造器
public Person(){}
public Person(String name){}
//方法
public void m1(){
}
protected void m2(){
}
}
//hspedu.reflection.Person
//Person
//本类以及父类的public属性:name
//本类以及父类的public属性:hobby
//本类中所有属性:name
//本类中所有属性:age
//本类中所有属性:job
//本类中所有属性:sal
//本类以及父类的public方法:m1
//本类以及父类的public方法:hi
//本类以及父类的public方法:equals
//本类以及父类的public方法:toString
//本类以及父类的public方法:hashCode
//本类以及父类的public方法:getClass
//本类以及父类的public方法:notify
//本类以及父类的public方法:notifyAll
//本类以及父类的public方法:wait
//本类以及父类的public方法:wait
//本类以及父类的public方法:wait
//本类中所有的方法:m2
//本类中所有的方法:m1
//本类以及父类的public构造器:hspedu.reflection.Person
//本类以及父类的public构造器:hspedu.reflection.Person
//本类中所有构造器:hspedu.reflection.Person
//本类中所有构造器:hspedu.reflection.Person
//包信息:package hspedu.reflection
//父类的class对象:class hspedu.reflection.A
//接口信息:interface hspedu.reflection.IA
//接口信息:interface hspedu.reflection.IB
//注解信息:@java.lang.Deprecated(forRemoval=false, since="")
2、第二:java.lang.reflect.Field类
(1)getModifiers: 以 int 形式返回修饰符
[说明:默认修饰符是0,public是1,private是2,protected是4,static是8,final是16,public+static=1+8=9(组合型,则对应的值相加)]
(2)getType: 以Class形式返回类型
(3)getName: 返回属性名
package hspedu.reflection;
import org.testng.annotations.Test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* 只要拿到Class对象,几乎就可以得到该类的所有信息(属性、方法、构造器、接口、注解)
*/
public class ReflectionUtils {
public static void main(String[] args) {
}
@Test
public void api_02() throws ClassNotFoundException {
Class<?> personCls=Class.forName("hspedu.reflection.Person");
Field[] declaredFields = personCls.getDeclaredFields();
//默认修饰符是0,public是1,private是2,protected是4,static是8,final是16
for (Field declaredField :declaredFields) {
System.out.println("本类中所有属性:"+declaredField.getName()
+" 该属性的修饰符值:"+declaredField.getModifiers()
+" 该属性的类型:"+declaredField.getType());
}
}
//本类中所有属性:name 该属性的修饰符值:1 该属性的类型:class java.lang.String
//本类中所有属性:age 该属性的修饰符值:4 该属性的类型:int
//本类中所有属性:job 该属性的修饰符值:0 该属性的类型:class java.lang.String
//本类中所有属性:sal 该属性的修饰符值:2 该属性的类型:double
}
class A{
//属性
public String hobby;
//构造器
public A(){
}
//方法
public void hi(){
}
}
interface IA{
}
interface IB{
}
@Deprecated
class Person extends A implements IA,IB{
//属性
public String name;
protected int age;
String job;
private double sal;
//构造器
public Person(){}
public Person(String name){}
//方法
public void m1(){
}
protected void m2(){
}
}
3、第三组:java.lang.reflect.Method类
(1)getModifiers: 以 int 形式返回修饰符
[说明:默认修饰符是0,public是1,private是2,protected是4,static是8,final是16]
(2)getReturnType: 以Class形式获取返回类型
(3)getName: 返回方法名
(4)getParameterTypes: 以Class[ ] 返回参数类型数组
package hspedu.reflection;
import org.testng.annotations.Test;
import java.lang.reflect.Method;
public class ReflectionUtils {
public static void main(String[] args) {
}
@Test
public void api_02() throws ClassNotFoundException {
Class<?> personCls=Class.forName("hspedu.reflection.Person");
//默认修饰符是0,public是1,private是2,protected是4,static是8,final是16
Method[] declaredMethods = personCls.getDeclaredMethods();
for (Method declaredMethod :declaredMethods) {
System.out.println("本类中所有的方法:"+declaredMethod.getName()
+" 该方法的访问修饰符:"+declaredMethod.getModifiers()
+" 该方法返回的类型:"+declaredMethod.getReturnType());
//输出当前这个方法的形参数组情况
Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
for (Class<?> parameterType :parameterTypes) {
System.out.println("该方法的形参类型:"+parameterType);
}
}
}
}
class A{
//属性
public String hobby;
//构造器
public A(){
}
//方法
public void hi(){
}
}
interface IA{
}
interface IB{
}
@Deprecated
class Person extends A implements IA,IB{
//属性
public String name;
protected int age;
String job;
private double sal;
//构造器
public Person(){}
public Person(String name){}
//方法
public void m1(String name,int age,double sal){
}
protected String m2(){
return null;
}
public void m3(){
}
}
//本类中所有的方法:m2 该方法的访问修饰符:4 该方法返回的类型:class java.lang.String
//本类中所有的方法:m1 该方法的访问修饰符:1 该方法返回的类型:void
//该方法的形参类型:class java.lang.String
//该方法的形参类型:int
//该方法的形参类型:double
//本类中所有的方法:m3 该方法的访问修饰符:1 该方法返回的类型:void
4、第四组:java.lang.reflect.Constructor类
(1)getModifiers: 以 int 形式返回修饰符
(2)getName: 返回构造器名(全类名)
(3)getParameterTypes: 以Class[ ]返回参数类型数组
package hspedu.reflection;
import org.testng.annotations.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectionUtils {
public static void main(String[] args) {
}
@Test
public void api_02() throws ClassNotFoundException {
Class<?> personCls=Class.forName("hspedu.reflection.Person");
//默认修饰符是0,public是1,private是2,protected是4,static是8,final是16
Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
for (Constructor<?> declaredConstructor :declaredConstructors) {
System.out.println("本类中所有构造器:"+declaredConstructor.getName());
Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();
for (Class<?> parameterType :parameterTypes) {
System.out.println("该构造器的形参类型:"+parameterType);
}
System.out.println("========================");;
}
}
}
//本类中所有构造器:hspedu.reflection.Person
//========================
//本类中所有构造器:hspedu.reflection.Person
//该构造器的形参类型:class java.lang.String
//========================
//本类中所有构造器:hspedu.reflection.Person
//该构造器的形参类型:class java.lang.String
//该构造器的形参类型:int
//========================
class A{
//属性
public String hobby;
//构造器
public A(){
}
//方法
public void hi(){
}
}
interface IA{
}
interface IB{
}
@Deprecated
class Person extends A implements IA,IB{
//属性
public String name;
protected int age;
String job;
private double sal;
//构造器
public Person(){}
public Person(String name){}
public Person(String name,int age){}
}
五、通过反射创建对象
1、方式一:调用类中的public修饰的无参构造器
2、方式二:调用类中的指定构造器
3、Class类相关方法:
(1)newInstance: 调用类中的无参构造器,获取对应类的对象
(2)getConstructor(Class...clazz): 根据参数列表,获取对应的public构造器对象
(3)getDecalaredConstructor(Class...clazz): 根据参数列表,获取对应的所有构造器对象
4、Constructor类相关方法:
(1)setAccessible: 暴破[使用反射可以访问private构造器 / 方法 / 属性]
(2)newInstance(Object...obj): 调用构造器
package hspedu.reflection.question;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* 演示通过反射机制创建实例
*/
public class ReflectCreateInstance {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
//1、先获取到User类的Class对象
Class<?> userClass = Class.forName("hspedu.reflection.question.User");
//2、通过public的无参构造器创建实例
Object o = userClass.newInstance();
System.out.println(o);
//3、通过public的有参构造器创建实例
/*
constructor对象就是
public User(String name){
this.name=name;
}
*/
//3.1 先得到对应的构造器
Constructor<?> constructor = userClass.getConstructor(String.class);
//3.2 创建实例,并传入实参
Object hsp = constructor.newInstance("hsp");
System.out.println("hsp: "+hsp);
//4、通过非public的有参构造器创建实例
//4.1 得到private的构造器对象
Constructor<?> constructor1 = userClass.getDeclaredConstructor(int.class,String.class);
//4.2 创建实例
constructor1.setAccessible(true);//暴破[暴力破解],使用反射可以访问private构造器
Object user2 = constructor1.newInstance( 100,"张三丰");
System.out.println(user2);
}
}
//User{age=0, name='null'}
//hsp: User{age=0, name='hsp'}
//User{age=100, name='张三丰'}
class User{
private int age;
private String name;
public User(){
}
public User(String name){
this.name=name;
}
public User(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
六、通过反射访问类中的成员
1、访问属性:
(1)根据属性名获取Field对象
Field f = clazz对象.getDeclaredField(属性名);
(2)暴破:f.setAccessible(true); // f 是Field
(3)访问:
// o 表示对象
f.set(o, 值);
syso(f.get(o));
(4)注意:如果是静态属性,则set和get中的参数o,可以写成null(因为静态属性跟类相关,而不是跟对象相关)
package hspedu.reflection.question;
import java.lang.reflect.Field;
public class ReflectAccessProperty {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
//1、得到Student类对应的Class对象
Class<?> stuClass = Class.forName("hspedu.reflection.question.Student");
//2、创建对象
Object o = stuClass.newInstance();
System.out.println(o.getClass());
//class hspedu.reflection.question.Student
//3、使用反射得到age属性对象
Field age = stuClass.getField("age");//getDeclaredField可以拿到所有的属性,getField可以拿到public的属性
age.set(o,88);
System.out.println(o);//返回o对象的所有属性
System.out.println(age.get(o));//返回age属性的值
//Student{age=88, name=null}
//88
//4、使用反射操作name属性
Field name = stuClass.getDeclaredField("name");
name.setAccessible(true);//暴破,以便操作private属性
name.set(o,"螺蛳粉");//因为name是static属性,因此 o 也可以写成null
System.out.println(o);
//Student{age=88, name=螺蛳粉}
System.out.println(name.get(o));//获取属性值
System.out.println(name.get(null));//因为name是static属性
//螺蛳粉
//螺蛳粉
}
}
class Student{
public int age;
private static String name;
public Student(){
}
@Override
public String toString() {
return "Student{" +
"age=" + age +", name="+name+
'}';
}
}
2、访问方法:
(1)根据方法名和参数列表获取Method方法对象:
Method m = clazz.getDeclaredMethod(方法名, XX.class);// 得到本类的所有方法
(2)获取对象:Object o=clazz.newInstance();
(3)暴破:m.setAccessible(true);
(4)访问:Object returnValue = m.invoke(o,实参列表);//o 就是对象
(5)注意:如果是静态方法,则invode的参数o,可以写成null
马丁内斯如果是各大医院衣方法,则invode的参数,专家
package hspedu.reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectAccessMethod {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
//1、得到Boss类对应Class对象
Class<?> bossCls = Class.forName("hspedu.reflection.Boss");
//2、创建对象
Object o = bossCls.newInstance();
//3、调用public的hi方法
Method hi = bossCls.getMethod("hi",String.class);
hi.invoke(o,"酸辣粉");
//4、调用private static方法
//4.1 得到say方法对象
Method say = bossCls.getDeclaredMethod("say", int.class, String.class, char.class);
say.setAccessible(true);
System.out.println(say.invoke(o,10,"肠粉 ",'买'));
//5、在反射中,如果方法有返回值,统一返回Object,但是他运行类型和方法定义的返回类型一致
Object reVal=say.invoke(null,80,"烧烤",'买');
System.out.println(reVal);
System.out.println("reVal的运行类型:"+reVal.getClass());
}
}
//hi 酸辣粉
//10 肠粉 买
//80 烧烤 买
//reVal的运行类型:class java.lang.String
class Boss{
public int age;
private static String name;
public Boss() {
}
private static String say(int n,String s,char c){
return n+" "+s+" "+c;
}
public void hi(String s){
System.out.println("hi "+s);
}
}
//hi 酸辣粉
//100 肠粉 买
//reVal的运行类型:class java.lang.String
七、作业
1、
//我的代码:
package homework;
import java.lang.reflect.Field;
public class Homework01 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException {
Class<?> cls = Class.forName("homework.PrivateTest");
Object o = cls.newInstance();
Field name = cls.getDeclaredField("name");
name.setAccessible(true);
name.set(o,"炸串");
System.out.println(name.get(o));//炸串
System.out.println(cls.getName());//homework.PrivateTest
}
}
class PrivateTest{
private String name="hello-kitty";
public PrivateTest() {
}
public String getName(){
return name;
}
}
//老师的代码:
package homework;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Homework01 {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
//1、得到PrivateTest类对应的Class对象
Class<PrivateTest> privateTestClass = PrivateTest.class;
//2、创建对象实例
PrivateTest privateTestObj = privateTestClass.newInstance();
//3、得到name属性对象
Field name = privateTestClass.getDeclaredField("name");
//4、暴破name
name.setAccessible(true);
name.set(privateTestObj,"天龙八部");
//5、得到getName方法对象
Method getName = privateTestClass.getMethod("getName");
//就是不太明白怎么调用getName()方法
//6、直接调用getName()方法
Object invoke = getName.invoke(privateTestObj);
System.out.println("name属性值:"+invoke);
//name属性值:天龙八部
}
}
class PrivateTest{
private String name="hello-kitty";
//默认无参构造器
public String getName(){
return name;
}
}
2、
//我的代码:
package homework;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@SuppressWarnings({"all"})
public class Homework02 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, IOException {
//得到File_类的class对象
Class<?> fileClass = Class.forName("homework.File_");
//获取File_类所有的构造器
Constructor<?>[] declaredConstructors = fileClass.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println("File_类中所有构造器:" + declaredConstructor.getName());
//暴破private的属性
declaredConstructor.setAccessible(true);
//传递参数
Object o2 = declaredConstructor.newInstance("d:\\mynew.txt");
}
}
}
class File_ {
private String fileName;
public File_(String fileName) throws IOException {
this.fileName = fileName;
File file = new File(fileName);
file.createNewFile();
System.out.println("文件创建成功~");
}
}
//File_类中所有构造器:homework.File_
//文件创建成功~
//老师的代码:
package homework;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@SuppressWarnings({"all"})
public class Homework02 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//1、Class类的forName方法得到File类的class对象
Class<?> fileCls = Class.forName("java.io.File");
//2、得到所有的构造器
Constructor<?>[] declaredConstructors = fileCls.getDeclaredConstructors();
//遍历输出
for (Constructor<?> declaredConstructor :declaredConstructors) {
System.out.println("File构造器:"+declaredConstructor);
}
//3、指定地得到public java.io.File(java.lang.String)
Constructor<?> declaredConstructor = fileCls.getDeclaredConstructor(String.class);
//创建File对象
String fileAllPath="d:\\mynew.txt";
Object file = declaredConstructor.newInstance(fileAllPath);
//4、得到createNewFile的方法对象
Method createNewFile = fileCls.getMethod("createNewFile");
createNewFile.invoke(file);
//file的运行类型就是File
System.out.println(file.getClass());
System.out.println("创建文件成功"+fileAllPath);
}
}
//File构造器:public java.io.File(java.lang.String)
//File构造器:public java.io.File(java.lang.String,java.lang.String)
//File构造器:public java.io.File(java.net.URI)
//File构造器:private java.io.File(java.lang.String,java.io.File)
//File构造器:private java.io.File(java.lang.String,int)
//File构造器:public java.io.File(java.io.File,java.lang.String)
//class java.io.File
//创建文件成功d:\mynew.txt
第一次先混个眼熟,后面要用时可查API文档,慢慢熟悉