认识什么是反射
反射优点和缺点
优点:可以实现动态创建对象和编译,体现出很大的灵活性
缺点:对性能有影响,使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它能满足我们的需求,这些操作总时慢于直接执行相同的操作
//什么是反射
public class Test02 {
public static void main(String[] args) {
// 通过反射获取类的Class对象
try {
Class c1 = Class.forName("com.tong.reflection.User");
Class c2 = Class.forName("com.tong.reflection.User");
Class c3 = Class.forName("com.tong.reflection.User");
// 判断一个类在内存中只有一个Class类
// 一个类被加载后,类的整个结构都会被封装在Class对象中
System.out.println(c1.hashCode());
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
//实体类:pojo entity
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;
}
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;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
'}';
}
}
通过几种方式来获取Class类
//测试Class类的创建方式
public class Test03 {
public static void main(String[] args) {
Person person = new Student();
System.out.println("这个人是:"+person.name);
// 获得方式1 通过对象获得Class对象
Class c1 = person.getClass();
System.out.println(c1.hashCode());
// 获得方式2 通过forname获得
try {
Class c2 = Class.forName("com.tong.reflection.Student");
System.out.println(c2.hashCode());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 获得方式3 通过类名.class
Class<Student> c3 = Student.class;
System.out.println(c3.hashCode());
// 获得方式4 基本内置类型的包装类都有有个Type属性
Class<Integer> c4 = Integer.TYPE;
System.out.println(c4);//查看是哪个类
// 获得父类类型
Class c5 = c1.getSuperclass();
System.out.println(c5);
}
}
//创建一个人类
class Person{
public String name;
//下面就是无参构造,有参构造,tostring方法
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="老师";
}
}
所有类型的Class对象
//所有类型的Class对象
public class Test04 {
public static void main(String[] args) {
Class c1 = Object.class;//类
Class c2 = Comparable.class;//接口
Class c3 = String[].class;//数组
Class c4 = String[][].class;//二维数组
Class c5 = Override.class;//注解
Class c6 = ElementType.class;//枚举类型
Class c7 = Integer.class;//基本数据类型
Class c8 = void.class;//空类型
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);
// 只要元素类型和维度一样就是class.
int [] a = new int[10];
int [] b = new int[20];
System.out.println(a.getClass().hashCode());
System.out.println(b.getClass().hashCode());
}
}
Java内存分析
//讲解类怎么加载的
public class Test05 {
public static void main(String[] args) {
A a = new A();
System.out.println(A.m);
/*
1 加载到内存会,会产生一个类对应的class对象
2 链接,链接结束后 m=0
3 初始化
<clinit>(){
System.out.println("A类静态代码块初始化");
m = 300;
m = 100;
}
m = 100;
*/
}
}
class A{
// 静态代码块
static {
System.out.println("A类静态代码块初始化");
m = 300;
}
static int m = 100;
public A() {
System.out.println("A类的无参构造初始化");
}
}
//输出结果
A类静态代码块初始化
A类的无参构造初始化
100
分析类初始化
//测试类什么时候会初始化
public class Test06 {
static {
System.out.println("main类被加载");
}
public static void main(String[] args) {
//1 主动引用
// Son son = new Son();
/*
输出结果
main类被加载
父类被加载
子类被加载
*/
// 2 反射也会产生主动引用
// try {
// Class.forName("com.tong.reflection.Son");
// } catch (ClassNotFoundException e) {
// e.printStackTrace();
// }
// 3 不会产生类的引用的方法
// System.out.println(Son.b);
/*
输出结果
main类被加载
父类被加载
2
*/
System.out.println(Son.M);//常量在链接阶段就存入了调用了类的常量池中了,不会引起初始化
}
}
class Father{
static int b = 2;
static {
System.out.println("父类被加载");
}
}
class Son extends Father{
static {
System.out.println("子类被加载");
m = 300;
}
static int m = 100;
static final int M = 1;
}
类加载器的作用
public class Test07 {
public static void main(String[] args) {
// 获得系统类的加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
// 获取系统类加载器的父类加载器--> 扩展类加载器
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent);
// 获取扩展类加载器的父类加载器--> 根加载器(c/c++)写的
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);
/*
运行结果
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@1b6d3586
null
*/
// 测试当前类是哪个加载器加载的
try {
ClassLoader classLoader = Class.forName("com.tong.reflection.Test07").getClassLoader();
System.out.println(classLoader);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 测试JDK内部类是谁加载的
try {
ClassLoader classLoader = Class.forName("java.lang.Object").getClassLoader();
System.out.println(classLoader);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}//JDK是根加载器加载的没打印出来
// 如何获得系统类加载器可以加载的路径
System.out.println(System.getProperty("java.class.path"));
}
}
如何通过反射获取类运行时类的完整结构
//获得类的信息
public class Test08 {
public static void main(String[] args) {
try {
// 获得名字
Class c1 = Class.forName("com.tong.reflection.User");
System.out.println(c1.getName());//包名+类名
System.out.println(c1.getSimpleName());//单纯类名
System.out.println("==================================");
// 获得类的属性
Field[] fields = c1.getFields();//只能找到public属性
fields = c1.getDeclaredFields();//找到全部属性
for (Field field : fields) {
System.out.println(field);
}
//获得指定属性的值
Field name = c1.getDeclaredField("name");
System.out.println(name);
System.out.println("==================================");
// 获得类的方法
Method[] methods = c1.getMethods();//获得本类和父类全部的public全部的方法
for (Method method : methods) {
System.out.println("正常的"+method);
}
methods = c1.getDeclaredMethods();//获得本类的所有方法
for (Method method : methods) {
System.out.println("本类的"+method);
}
//获得指定方法
Method getName = c1.getMethod("getName", null);
Method setName = c1.getMethod("setName", String.class);
System.out.println(getName);
System.out.println(setName);
System.out.println("==================================");
// 获得类的构造器
Constructor[] constructors = c1.getConstructors();//获得public方法
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
constructors = c1.getDeclaredConstructors();//获得本类的全部方法
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
//获得指定的构造器
Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
System.out.println("指定构造器"+declaredConstructor);
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果
com.tong.reflection.User
User
==================================
private java.lang.String com.tong.reflection.User.name
private int com.tong.reflection.User.id
private int com.tong.reflection.User.age
private java.lang.String com.tong.reflection.User.name
==================================
正常的public java.lang.String com.tong.reflection.User.toString()
正常的public java.lang.String com.tong.reflection.User.getName()
正常的public int com.tong.reflection.User.getId()
正常的public void com.tong.reflection.User.setName(java.lang.String)
正常的public void com.tong.reflection.User.setId(int)
正常的public int com.tong.reflection.User.getAge()
正常的public void com.tong.reflection.User.setAge(int)
正常的public final void java.lang.Object.wait() throws java.lang.InterruptedException
正常的public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
正常的public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
正常的public boolean java.lang.Object.equals(java.lang.Object)
正常的public native int java.lang.Object.hashCode()
正常的public final native java.lang.Class java.lang.Object.getClass()
正常的public final native void java.lang.Object.notify()
正常的public final native void java.lang.Object.notifyAll()
本类的public java.lang.String com.tong.reflection.User.toString()
本类的public java.lang.String com.tong.reflection.User.getName()
本类的public int com.tong.reflection.User.getId()
本类的public void com.tong.reflection.User.setName(java.lang.String)
本类的public void com.tong.reflection.User.setId(int)
本类的public int com.tong.reflection.User.getAge()
本类的public void com.tong.reflection.User.setAge(int)
public java.lang.String com.tong.reflection.User.getName()
public void com.tong.reflection.User.setName(java.lang.String)
==================================
public com.tong.reflection.User()
public com.tong.reflection.User(java.lang.String,int,int)
public com.tong.reflection.User()
public com.tong.reflection.User(java.lang.String,int,int)
指定构造器public com.tong.reflection.User(java.lang.String,int,int)
动态创建对象执行方法
//通过反射动态的创建对象
public class Test09 {
public static void main(String[] args) {
try {
//获得class对象
Class c1 = Class.forName("com.tong.reflection.User");
// 构造一个对象
User user = (User )c1.newInstance();//本质上调用了类的无参构造器
System.out.println(user);
// 通过构造器创建对象
Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
User user2 =(User) constructor.newInstance("tom", 01, 22);
System.out.println(user2);
System.out.println("============================================");
// 通过反射调用方法
User user3 = (User )c1.newInstance();
//通过反射获取一个方法
Method setName = c1.getDeclaredMethod("setName", String.class);
// invoke:激活
//(对象,“方法的值”,
setName.invoke(user3,"狂神");
System.out.println(user3.getName());
System.out.println("============================================");
// 通过反射操作属性
User user4 = (User )c1.newInstance();
Field name = c1.getDeclaredField("name");
//不能直接操作私有属性,需要关闭程序的安全检测,name.setAccessible(true);
name.setAccessible(true);
name.set(user4,"狂神2");
System.out.println(user4.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果
User{name='null', id=0, age=0}
User{name='tom', id=1, age=22}
============================================
狂神
============================================
狂神2
分析性能时间
//分析性能问题
public class Test10 {
// 普通方式
public static void test01(){
User user = new User();
long starTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
user.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方法执行10亿次"+(endTime-starTime)+"ms");
}
// 反射调用
public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class c1 = user.getClass();
Method getName = c1.getMethod("getName", null);
long starTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射方法执行10亿次"+(endTime-starTime)+"ms");
}
// 反射方式调用 关闭检测
public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class c1 = user.getClass();
Method getName = c1.getMethod("getName", null);
getName.setAccessible(true);
long starTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println("关闭检测执行执行10亿次"+(endTime-starTime)+"ms");
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
test01();
test02();
test03();
}
}
运行结果
普通方法执行10亿次2ms
反射方法执行10亿次2523ms
关闭检测执行执行10亿次1096ms