反射
反射
链接:www.kuangstudy.com
1.2 java 反射的优缺点
优点: 可以实现动态创建对象和编译,体现出很大的灵活性
缺点: 对性能有影响,使用反射基本上是一种结实操作,我们可以告诉JVM,我们希望做什么并且他满足我们的要求,这类操作总是鳗鱼直接执行相同的操作
2.反射的主要API
java.lang.class : 代表一个类
java.lang.reflect.Method: 代表类的方法
java.lang.reflect.Field : 代表类的成员变量
java.lang.reflect.Constructor : 代表类的构造器
2.1 获得反射对象
package com.yx.fanshe;
//什么叫反射
public class TestFanshe{
public static void main(String[] args) throws ClassNotFoundException {
//通过反射获取类的class对象
Class c1 = Class.forName("com.yx.fanshe.User");
System.out.println(c1);
Class c2 = Class.forName("com.yx.fanshe.User");
Class c3 = Class.forName("com.yx.fanshe.User");
Class c4 = Class.forName("com.yx.fanshe.User");
//一个类在内存中 只有一个class对象
//一个类被加载后,整个类都会封装在class对象中
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
System.out.println(c4.hashCode());
}
}
//实体类
class User{
private String name;
private int id;
private int age;
public User() {
}
public User(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
2.2 得到class的几种方式
package com.yx.fanshe;
//测试class类的创建方式
public class HuoQuFangShi {
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Student();
System.out.println("这个人是:"+ person.name);
//方式一: 通过对象获得
Class c1 = person.getClass();
//方式二: forname获得
Class c2 = Class.forName("com.yx.fanshe.Student");
System.out.println(c2);
System.out.println(c1.hashCode());
System.out.println(c2.hashCode());
//方式三: 通过类名.class获得
Class c3 = Student.class;
System.out.println(c3.hashCode());
//获得父类的类型
Class c5 = c1.getSuperclass();
System.out.println(c5);
}
}
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="老师";
}
}
2.3 所有类型的class对象
package com.yx.fanshe;
import java.lang.annotation.ElementType;
//所有类型的class
public class AllClasss {
public static void main(String[] args) {
Class c1 = Object.class; //类
Class c2 = Comparable.class; //接口
Class c3 = String[].class; //一维数组
Class c4 = int[][].class; //二维数组
Class c5 = Override.class; //注解
Class c6 = ElementType.class; //枚举
Class c7 = Integer.class; //基本数据类型
Class c8 = void.class; //void
Class c9 = Class.class; //Class
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);
System.out.println(c5);
System.out.println(c6);
System.out.println(c7);
System.out.println(c8);
System.out.println(c9);
}
}
2.4 什么时候会发生类初始化
2.6 类加载器
package com.yx.fanshe;
public class TestClassLoader {
public static void main(String[] args) throws ClassNotFoundException {
//获取系统的类加载器
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
System.out.println(classLoader);
//获取系统类加载器的父类加载器 --> 扩展类加载器
ClassLoader parent = classLoader.getParent();
System.out.println(parent);
//获得扩展类加载器的父类加载器 -->根加载器()
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);
//获取当前类是哪个加载器加载的
ClassLoader what = Class.forName("com.yx.fanshe.TestClassLoader").getClassLoader();
System.out.println(what);
System.out.println("=================================================================================");
//测试jdl内置的类是谁加载的
ClassLoader loader = Class.forName("java.lang.Object").getClassLoader();
System.out.println(loader);
//如何获得系统类加载器可以加载的路径
String property = System.getProperty("java.class.path");
System.out.println(property);
//双亲委派机制
//想自己写 java.lang.string (不生效)---> 先看用户类加载器 ---> 扩展类加载器 ---> 根加载器 顺着包往上找
}
}
2.7 获得类运行时的结构
package com.yx.fanshe;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class YunXingJieGou {
public static void main(String[] args) throws Exception {
Class c1 = Class.forName("com.yx.fanshe.User");
//通过反射
/*User user = new User();
c1 = user.getClass();*/
//获得类的名字
System.out.println(c1.getName()); //获得包名+类名
System.out.println(c1.getSimpleName()); //获得类名
System.out.println("=--=-=-=-=----------------======================-=-=-----------=-=-=-");
//获得类的属性
/* 只能找到 public 的属性
Field[] fields = c1.getFields();
for (Field field : fields) {
System.out.println(field);
}*/
//可以找到全部的属性
Field[] fields = c1.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
//通过指定的属性获得
Field name = c1.getDeclaredField("name");
System.out.println(name);
//获得类的方法
System.out.println("----------------获得类的方法------------------------");
获得本类和父类的所有方法
Method[] method = c1.getMethods();
for (Method method1 : method) {
System.out.println("正常的: "+method1);
}
//获得本类的所有方法
Method[] methods = c1.getDeclaredMethods();
for (Method methods1 : method) {
System.out.println("getDeclaredMethods : "+methods1);
}
//获取指定的方法
Method getName = c1.getMethod("getName");
Method setName = c1.getMethod("setName", String.class);
System.out.println(getName);
System.out.println(setName);
System.out.println("======================获取指定构造器======================");
//获取指定构造器
Constructor[] constructors = c1.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
Constructor[] declaredConstructors = c1.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
//通过参数获取指定构造器
Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class,int.class);
System.out.println(declaredConstructor);
}
}
2.8 动态创建对象执行方法
package com.yx.fanshe;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class DongTaiChuangJian {
public static void main(String[] args) throws Exception {
//获得class对象
Class c1 = Class.forName("com.yx.fanshe.User");
/* //构造一个对象
User user = (User) c1.newInstance(); //本质上是调用了无参构造器
System.out.println(user);*/
/* //通过构造器创建对象
Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
User user2 = (User) declaredConstructor.newInstance("yx", 1, 21);
System.out.println(user2);*/
/*//通过反射构造方法
User user3 = (User) c1.newInstance();
Method setName = c1.getDeclaredMethod("setName", String.class);
setName.invoke(user3,"yx");
System.out.println(user3.getName());*/
User user4 = (User) c1.newInstance();
Field name = c1.getDeclaredField("name");
//不能直接操作私有属性,我们需要关闭程序的安全检测,属性或者方法的setAccessible(true);
name.setAccessible(true);
name.set(user4,"yx");
System.out.println(user4.getName());
}
}
2.9 性能对比分析
package com.yx.fanshe;
import java.lang.reflect.Method;
//分析性能测试
public class TestXingNeng {
//普通方法
public static void test1(){
User user = new User();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
user.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方法执行10亿次: "+(endTime-startTime)+" ms");
}
//发射方法调用
public static void test2() throws Exception {
User user = new User();
Class c1 = user.getClass();
Method getName = c1.getDeclaredMethod("getName");
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射方法执行10亿次: "+(endTime-startTime)+" ms");
}
//反射方式调用 关闭检测
public static void test3() throws Exception {
User user = new User();
Class c1 = user.getClass();
Method getName = c1.getDeclaredMethod("getName");
getName.setAccessible(true);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println("关闭后,反射方法执行10亿次: "+(endTime-startTime)+" ms");
}
public static void main(String[] args) throws Exception {
test1();
test2();
test3();
}
}