反射目录
获得Class类的实例的多种方法
方法:Method
字段:Field
构造器:Constructor
public class test1 {
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Student();
System.out.println("这个人是"+person.name);
//方法一:通过对象获得
Class a1 = person.getClass();
System.out.println(a1.hashCode());
//方法二:forName获得 一般都用这个方法
Class a2 = Class.forName("com.hxz.test.Student");
System.out.println(a2.hashCode());
//方法三:通过类名.class获得
Class a3 = Student.class;
System.out.println(a3.hashCode());
//获得父类类型
Class a4 = a1.getSuperclass();
System.out.println(a4);
}
}
class Person{
public String name;
public Person(){
}
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
class Student extends Person{
public Student() {
this.name="学生";
}
}
class Teacher extends Person{
public Teacher() {
this.name="老师";
}
}
ClassLoader类理解
这个涉及到JVM了
可以先看https://blog.csdn.net/u014634338/article/details/81434327
类的初始化
类的主动引用(一定会发生类的初始化)
当虚拟机启动,先初始化main方法所在的类
public static void main(String[] args) { }
new一个类的对象
Person person = new Student();
调用类的静态成员(除了final常量)和静态方法
static
使用java.lang.reflect包的方法对类进行反射调用
Class a2 = Class.forName("com.hxz.test.Student");
当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类
B继承A调用B的方法时会先加载B再加载A
类的被动引用(不会发生类的初始化)
当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化
子类调用父类方法,只会加载父类方法
System.out.println(son.dad);
通过数组定义类引用,不会触发此类的初始化
Son[] array =new Son[5];
这样是不会加载初始化的
引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)
比如在子类定义一个
static final int a = 1;
这时在main函数里 System.out.println(son.a);
只会加载main函数,并不会加载子类和父类
获取类的运行结构
这些大部分还是会被用到的
public class test2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class a1 = Class.forName("com.hxz.test.User");
System.out.println(a1.getName());
//获得类名
System.out.println(a1.getSimpleName());
//获得类的属性
System.out.println( "==================================");
//只能找到public属性
Field[] fields = a1.getFields();
//找到全部的属性
fields = a1.getDeclaredFields();
for (Field field : fields) {
System.out.println( field);
}
//获得指定属性的值
Field name = a1.getDeclaredField("name") ;
System.out.println(name) ;
//获得类的方法
System.out.println( "==================================");
//获得本类及其父类的所有方法,除了private
Method[] methods = a1.getMethods();
for (Method method : methods) {
System.out.println("正常的 "+method);
}
//获得本类的所有方法,包括私有的
methods = a1.getDeclaredMethods();
for (Method method : methods) {
System.out.println("getDeclaredMethods "+method);
}
//获得指定方法
//重载
Method getName = a1.getMethod("getName", null);
Method setName = a1.getMethod("setName", String.class);
System.out.println(getName);
System.out.println(setName);
//获得构造器
System.out.println( "==================================");
//只能获得public方法
Constructor[] constructors = a1.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
//能获得全类的方法
Constructor[] declaredConstructors = a1.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
//获得指定构造器
Constructor declaredConstructor = a1.getDeclaredConstructor( int.class, String.class, int.class);
System.out.println(declaredConstructor);
}
}
class User {
private int id;
private String name;
private int age;
public User(){
}
public User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private void siyou(){
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
动态创建对象执行方法
//动态创建对象,通过反射
public class test3 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//获得class对象
Class a1 = Class.forName("com.hxz.test.User");
//构造一个对象
User user = (User) a1.newInstance();
//这个方法默认构造的是无参构造器
System.out.println(user);
//通过构造器创建对象
//获取带参的构造器
Constructor declaredConstructor = a1.getDeclaredConstructor(int.class, String.class, int.class);
//通过获得的带参构造器创建对象,并传参
User user2 = (User) declaredConstructor.newInstance(11, "衣衣", 18);
System.out.println(user2);
//通过反射调用普通方法
User user3 = (User) a1.newInstance();
//通过反射获得一个方法
Method setName = a1.getDeclaredMethod("setName", String.class);
//invoke:激活(对象,"方法的值")
setName.invoke(user3,"衣衣");
System.out.println(user3.getName());
//通过反射操作属性
System.out.println( "==================================");
User user4 = (User) a1.newInstance();
Field name = a1.getDeclaredField("name");
//关闭安全检测,不然无法操作私有属性,没有这句话会报错,但是这样会降低程序效率
name.setAccessible(true);
name.set(user4,"衣衣2");
System.out.println(user4.getName());
}
}
性能检测
从下面知道关闭性能检测会降低性能
没关闭时,无法获取private但可以获取其他三种
这是结果
//分析性能问题
public class test4 {
//普通方式调用
public static void test1(){
User user = new User();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
user.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通执行了 " + (endTime-startTime) + "ms");
}
//反射方式调用
public static void test2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class a1 = user.getClass();
Method getName = a1.getDeclaredMethod("getName", null);
// protected Method aa = a1.getDeclaredMethod("aa", null);
// default Method bb = a1.getDeclaredMethod("bb", null);
// private Method siyou = a1.getDeclaredMethod("siyou", null);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
getName.invoke(user,null);
//aa.invoke(user,null);
//siyou.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射执行了" + (endTime-startTime) + "ms");
}
//反射方式调用 关闭检测
public static void test3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class a1 = user.getClass();
Method getName = a1.getDeclaredMethod("getName", null);
getName.setAccessible(true);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射2执行了" + (endTime-startTime) + "ms");
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
test1();
test2();
test3();
}
}
反射操作泛型
Java采用泛型擦除的机制来引入泛型,Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换问题,但是,一旦编译完成,所有和泛型有关的类型全部擦除
.
为了通过反射操作这些类型,Java新增了ParameterizedType , GenericArrayType ,TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型.
.
ParameterizedType:表示一种参数化类型,比如Collection
GenericArrayType :表示一种元素类型是参数化类型或者类型变量的数组类型
TypeVariable :是各种类型变量的公共父接口
WildcardType :代表一种通配符类型表达式
//通过反射获取泛型参数信息
public class test5 {
public void test1(Map<String,User> map, List<User> list){
System.out.println("test1");
}
public Map<String,User> test2(){
System.out.println("test2");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
//获得第一个方法
Method method = test5.class.getMethod("test1", Map.class, List.class);
//通过方法获得参数类型
Type[] genericParameterTypes = method.getGenericParameterTypes();
//循环输出
for (Type genericParameterType : genericParameterTypes) {
//输出的是类
System.out.println(genericParameterType);
//便利genericParameterType获取参数类型
if (genericParameterType instanceof ParameterizedType){
//getActualTypeArguments获得真实参数类型
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
System.out.println("--------------------------------------------");
//获得第二个方法
method = test5.class.getMethod("test2",null);
Type genericReturnType = method.getGenericReturnType();
if (genericReturnType instanceof ParameterizedType){
//getActualTypeArguments获得真实参数类型
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
}