java反射详解
做项目必须熟练的技能
1. 介绍
问:反射是干什么的?
场景:根据一个配置文件的信息,创建一个类的实例。
通过反射可以实现动态加载的功能。。
1)反射允许程序执行期间通过Reflection API 获取任何类的内部信息
2)加载完类之后,堆中产生一个Class类的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息
项目框架底层就是反射,
优点:可以动态创建和使用对象,灵活
缺点:因为基本是解释执行,运行速度有影响
Class介绍:
反射示意图:
2. 反射操作
上代码:
package com.wts.reflection;
import com.wts.reflection.car.Car;
import java.lang.reflect.Field;
public class Reflection {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
String classPath = "com.wts.reflection.car.Car";
//1.获取Car类 对应的Class类
Class<?> cls = Class.forName(classPath);
//2.输出cls
System.out.println(cls);//--显示的cls对象 //class com.wts.reflection.car.Car
System.out.println(cls.getClass());//--输出cls的运行类 //class java.lang.Class
//3.得到包名
System.out.println(cls.getPackage().getName());//--包名 //com.wts.reflection.car
//4.得到类名
System.out.println(cls.getName());//--类名 //com.wts.reflection.car.Car
//5.创建实例对象
Car car = (Car) cls.newInstance();
System.out.println(car);//toString //Car{brand='宝马', price=50000, color='白色'}
//6.通过反射获取属性 brand
Field brand = cls.getField("brand");
System.out.println(brand.get(car));//*brand //宝马
//7.通过反射给属性赋值
brand.set(car, "奔驰");
System.out.println(brand.get(car));//奔驰
//8.获取所有属性
System.out.println("---------");
Field[] fields = cls.getFields();
for (Field field :
fields) {
System.out.println(field.get(car));
}
}
}
3.获取包装类的六种方式
不同阶段不同的取包装类的方式。
三个阶段上图有说到的:编译阶段,类加载阶段,运行阶段(有实例对象)
上代码:
package com.wts.reflection;
import com.wts.reflection.car.Car;
public class GetClass {
public static void main(String[] args) throws ClassNotFoundException {
String classAllPath = "com.wts.reflection.car.Car";
//1.Class.forName 程序编译阶段
Class<?> cls1 = Class.forName(classAllPath);
System.out.println(cls1);
//2.类名.class 类加载阶段 应用场景:用于参数传递
Class<Car> cls2 = Car.class;
System.out.println(cls2);
//3.对象.getClass() 应用场景:有对象实例化了
Car car = new Car();
Class cls3 = car.getClass();
System.out.println(cls3);
//4.通过类加载器获取 类的Class对象
//1)先得到类加载器car
ClassLoader classLoader = car.getClass().getClassLoader();
//2)通过类加载器得到 Class对象
Class<?> cls4 = classLoader.loadClass(classAllPath);
System.out.println(cls4);
/*---另外两种特别的*/
//5.基本数据类型得到Class类对象
Class<Integer> intClass = int.class;
System.out.println(intClass);
Class<Boolean> booleanClass = boolean.class;
System.out.println(booleanClass);
//int
//boolean
//6.基本数据类型对应的包装类得到Class类对象 --5和6会自动装箱和拆箱
Class<Integer> type = Integer.TYPE;
System.out.println(type); //int
}
}
4. 哪些类型有Class对象
5. 类加载
通过反射实现了类动态加载
静态加载和动态加载:
- 静态加载:编译时加载相关的类,如果没有,则报错。
- 动态加载:反射–>动态加载;运行时不用加载该类,(即使该类不存在),不报错(延后报错)(如下图:当输入2 后,才会报错。第一次运行不报错)
类加载的三个阶段–以及类加载后内存分布情况:
加载阶段
连接阶段–验证
连接阶段–准备
连接阶段–解析
其中3,保证了内存只加载一个类?(锁)
6. 通过反射获取类的结构性息
7. 通过反射创建对象
上代码:
package com.wts.reflection;
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.获取Class类对象
Class<?> aClass = Class.forName("com.wts.reflection.User");
//2.通过public的无参构造器创建实例
Object o = aClass.newInstance();
System.out.println(o);
//3.通过public的有参构造器创建实例
/*constructor
就是
public User(int age, String name) {
this.age = age;
this.name = name;
}
*/
Constructor constructor = aClass.getConstructor(int.class, String.class);
Object aaa = constructor.newInstance(66, "aaa");
System.out.println(aaa);
//4.通过非public的有参构造器创建实例 --暴破
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(int.class, String.class);
declaredConstructor.setAccessible(true);//通过暴力反射可以,访问私有private构造器
Object o4 = declaredConstructor.newInstance(100, "zhangsan");
System.out.println(o4);
}
}
/*User类*/
class User {
private int age = 20;
private String name = "wts";
public User() {
}
public User(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
效果:
8. 通过反射访问类中的成员
爆破反射操作类的属性
上代码:
package com.wts.reflection;
import java.lang.reflect.Field;
public class ReflectGetClassInfo {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
//1.得到Student类对应 Class对象
Class<?> aClass = Class.forName("com.wts.reflection.Student");
//2.创建对象
Object o = aClass.newInstance();
System.out.println(o);
//3.用反射,设置age的值
Field age = aClass.getField("age");
age.set(o, 10);
System.out.println(o);
System.out.println(age.get(o));
//4.用反射,设置name的值 --私有,用Declared + 爆破
Field name = aClass.getDeclaredField("name");
name.setAccessible(true);
name.set(null, "aaa"); //--因为name是静态的,在类加载的时候就存在了,
// name.set(o,"aaa");
System.out.println(o);
}
}
class Student {
public int age;
private static String name; //--静态的,在类加载的时候就有了
public Student() {
}
@Override
public String toString() {
return "Student{" +
"age=" + age
+ "\t,name=" + name +
'}';
}
}
反射访问方法
上代码:
package com.wts.reflection;
import java.lang.reflect.Method;
public class ReflectGetMethods {
public static void main(String[] args) throws Exception {
//1.获取类 -- 创建实例
Class<?> aClass = Class.forName("com.wts.reflection.Boss");
Object o = aClass.newInstance();
//2.
Method method = aClass.getMethod("hi", String.class);//带参方法
method.invoke(o, "你好");
//3.
Method say = aClass.getDeclaredMethod("say", int.class, String.class, char.class);
say.setAccessible(true);
System.out.println(say.invoke(null, 20, "aaa", '男'));//--static可以 o可以取代null
//4.返回值, 如果方法有返回值,统一返回Object,但是他运行类型和方法定义的返回类型一致(编译看左边运行看右边?)
Object invoke = say.invoke(null, 500, "bbb", '女');
System.out.println("invoke的运行类型=" + invoke.getClass());
}
}
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);
}
}
两个练习
上代码:
package com.wts.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/*反射复习练习*/
public class Reflect_review {
public static void main(String[] args) throws Exception {
/*练习1 */
//1.获取Class类,创建实例
Class<?> aClass = Class.forName("com.wts.reflection.PrivateTest");
Object o = aClass.newInstance();
//2.获取属性
Field name = aClass.getDeclaredField("name");
name.setAccessible(true);//暴力
System.out.println(name.get(o));
//改
System.out.print("反射更改属性后--");
name.set(o, "天龙八部");
System.out.println(name.get(o));
//用getname方法
Method getName = aClass.getDeclaredMethod("getName");
Object invoke = getName.invoke(o);
System.out.println(invoke);
/*练习2*/
Class<?> fileCls = Class.forName("java.io.File");
//指定构造器,‘文件全路径’
Constructor<?> declaredConstructor = fileCls.getDeclaredConstructor(String.class);
//文件的全路径
String allPath = "E:\\桌面\\csdn钢琴家\\1_CSDN代码\\1.txt";
Object file = declaredConstructor.newInstance(allPath);//创建file对象了 -- file的运行类型就是File
//得到对象方法
Method createNewFile = fileCls.getDeclaredMethod("createNewFile");
createNewFile.invoke(file);
//file的运行类型就是File
System.out.println();
System.out.println(file.getClass());
System.out.println("文件创建成功" + allPath);
}
}
class PrivateTest {
private String name = "hellokitty";
//默认无参构造器
public String getName() {
return name;
}
}