简单尝试:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class animal {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class name = Class.forName("com.zjl.test.reflection.cat");
Object o = name.newInstance();
Method who = name.getMethod("who");
who.invoke(o);
}
}
一、反射机制:
1.反射机制允许程序在执行期借助于Reflection
API取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到
2.加载完类之后,在堆中就产生了一个Class类型
的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,形象的称之为:反射
应用实例:
获取class类的四种方法:
public class GetClass_ {
public static void main(String[] args) throws ClassNotFoundException {
//1. Class.forName
String classAllPath = "com.hspedu.Car"; //通过读取配置文件获取
Class<?> cls1 = Class.forName(classAllPath);
System.out.println(cls1);
//2. 类名.class , 应用场景: 用于参数传递
Class cls2 = Car.class;
System.out.println(cls2);
//3. 对象.getClass(), 应用场景,有对象实例
Car car = new Car();
Class cls3 = car.getClass();
System.out.println(cls3);
//4. 通过类加载器【4种】来获取到类的Class对象
//(1)先得到类加载器 car
ClassLoader classLoader = car.getClass().getClassLoader();
//(2)通过类加载器得到Class对象
Class cls4 = classLoader.loadClass(classAllPath);
System.out.println(cls4);
//cls1 , cls2 , cls3 , cls4 其实是同一个对象
System.out.println(cls1.hashCode());
System.out.println(cls2.hashCode());
System.out.println(cls3.hashCode());
System.out.println(cls4.hashCode());
//5. 基本数据(int, char,boolean,float,double,byte,long,short) 按如下方式得到Class类对象
Class<Integer> integerClass = int.class;
Class<Character> characterClass = char.class;
Class<Boolean> booleanClass = boolean.class;
System.out.println(integerClass);//int
//6. 基本数据类型对应的包装类,可以通过 .TYPE 得到Class类对象
Class<Integer> type1 = Integer.TYPE;
Class<Character> type2 = Character.TYPE; //其它包装类BOOLEAN, DOUBLE, LONG,BYTE等待
System.out.println(type1);
//两个类型是相同的:
System.out.println(integerClass.hashCode());//?
System.out.println(type1.hashCode());//?
}
}
二、类加载
基本说明:
反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载。
1.静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
2动态加载:运行时加载需要的类,如果运行时不用该类,则不报错,降低了依赖性
3.举例说明
类加载时机:
1.当创建对象时(new) //静态加载
2.当子类被加载时,父类也加载 //静态加载
3.调用类中的静态成员时 //静态加载
4.通过反射 //动态加载
类加载:
类加载各阶段完成任务:
加载阶段:
JVM在该阶段的主要目的是将字节码从不同的数据源(可能是 class 文件、也可能是jar包,甚至网络)转化为二进制字节流加载到内存中,并生成一个代表该类的
java.lang.Class对象
连接阶段-验证:
连接阶段-准备:
变量的准备简介:
连接阶段-解析:
1.虚拟机将常量池内的符号引用替换为直接引用的过程。
初始化(Initiaalization):
1.到初始化阶段,才真正开始执行类中定义的Java程序代码,此阶段是执行
2.
静态变量的赋值动作和静态代码块中的语句,并进行合并。
3.虚拟机会保证一个类的
多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的
通过反射获取类的结构信息:
java.lang.class类:
1. getName:获取全类名
2. getSimpleName:获取简单类名
3. getFields:获取所有public修饰的属性,包含本类以及父类的
4. getDeclaredFields:获取本类中所有属性
5. getMethods:获取所有public修饰的方法,包含本类以及父类的
6. getDeclaredMethods:获取本类中所有方法
7. getConstructors: 获取所有public修饰的构造器,本类
8. getDeclaredConstructors:获取本类中所有构造器
9. getPackage:以Package形式返回包信息
10.getSuperClass:以Class形式返回父类信息
11.getlnterfaces:以Class[形式返回接口信息
12.getAnnotations:以Annotation[]形式返回注解信息
java.lang.reflect.Field类:
1. getModifiers:以int形式返回修饰符
[说明:默认修饰符是0,public是1,private是2,protected是4,static是8,final是16], public(1) + static (8) = 9
2.getType:以Class形式返回类型
3.getName:返回属性名
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[返回参数类型数组
java.lang.reflect.Constructor类:
1.getModifiers: 以int形式返回修饰符
2.getName:返回构造器名(全类名)
3.getParameterTypes:以Class[]返回参数类型数组
三、通过反射实现类加载:
访问构造器:
1、方法一:调用类中的public修饰的无参构造器
2、方式二:调用类中指定构造器
3. Class类相关方法
newlnstance:调用类中的无参构造器,获取对应类的对象
getConstructor(Class…clazz):根据参数列表,获取对应的public构造器对象getDecalaredConstructor(Class…clazz):根据参数列表,获取对应的所有构造器对象
4. Constructor类相关方法
setAccessible:暴破
newlnstance(Object…obj):调用构造器
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ReflectCreateInstance {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//1、获取User的class对象
Class> aClass = Class.forName("com.zjl.test.reflection.User");
//2、通过public的无参构造器创建实例
Object o = aClass.newInstance();
System.out.println(o);
//3、通过public的有参构造器创建实例
//得到构造器对象
Constructor> constructor = aClass.getConstructor(String.class);
//创建实例,并传入参数
Object who = constructor.newInstance("who");
System.out.println(who);
//4.通过非public的有参构造器创建实例
//得到一个private的构造器对象
Constructor> declaredConstructor = aClass.getDeclaredConstructor(int.class, String.class);
//对该构造器进行暴破,使得可以通过反射语句访问private的构造器,方法,属性
declaredConstructor.setAccessible(true);
//创建一个private对象的实例并赋值
Object o1 = declaredConstructor.newInstance(20, "Where");
System.out.println(o1);
}
}
class User{
private int age = 10;
private String name = "hello";
public User(){
}
public User(String name) {
this.name = name;
}
private User(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\\'' +
'}';
}
}
访问类中的属性成员:
1.根据属性名获取Field对象
Field f =clazz对象.getDeclaredField(属性名);
2.暴破:f.setAccessible(true);1/f 是Field
3.访问
f.set(o,值);1/ o表示对象
syso(f.get(o))://o表示对象
4.注意:如果是静态属性,则set和get中的参数o,可以写成null
通过反射访问类中的方法成员:
1.根据方法名和参数列表获取Method方法对象:Method m =
clazz.getDeclaredMethod(方法名,XX.class);
2.获取对象:Object o=clazz.newlnstance);
3.暴破:m.setAccessible(true);
4.访问:Object returnValue = m.invoke(o,实参列表);
5.注意:如果是静态方法,则invoke的参数o,可以写成null!
手机扫一扫
移动阅读更方便
你可能感兴趣的文章