反射:反射是Java语言的特征之一。
它允许在运行时动态加载类、获取类信息、生成对象、操作对象的属性或方法等。主要提供了以下功能:
- 在运行时判断任意一个对象所属的类;
- 在运行时构造任意一个类的对象;
- 在运行时判断任意一个类所具有的成员变量和方法;
- 在运行时调用任意一个对象的方法。甚至是private方法。
- 生成动态代理。
正常执行:先将代码编写完毕 之后又JVM去进行运行 运行期间 无法对已有对象做内部设置 调用 访问等功能
反射中绕不开的类:Class<T>
Class类表示 对 类类型的一种抽象 就是用来描述一个类对象
任何一个类在底层都会对应一个Class类
类加载机制:
由一个Java文件 到 能够运行的对象之间 JVM都做了什么
类加载机制
文件 --编译--> 字节码文件 --类加载--> 进入JVM --连接--> 验证--准备--解析--初始化-->Class
基本上所有的反射都是要通过Class对象来扩展的
Java中 如何获取Class对象?
三种方式:
- 类名.class 的方式
- 通过对象.getClass()方法
- 通过Class.forName(String) 静态方法 String 为当前类的全限定名
public class Dog<T> {
private String name = "Tom";
public int age = 18;
private boolean gender;
public List<?> t;
private Dog(){
System.out.println("DOG构造被调用");
}
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
public void play(String name){
System.out.println(this.name+"开始和"+name+"一起玩耍");
}
private String show(){
return "名字:"+name+",年龄:"+age;
}
@InitParam(name="狗子",age=4,gender=true)
public void init(){
System.out.println("名字:"+name+",年龄:"+age+",性别:"+gender);
}
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InitParam {
String name() ;
int age();
boolean gender();
}
public class Demo {
public static void main(String[] args) throws NoSuchFieldException {
// demo1();
// try {
demo9();
/* } catch (NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}*/
}
/*
* 此处有误 只能获取 成员属性 方法泛型 返回值泛型
* 不能获取类 接口 局部变量泛型
* ParameterizedType
* */
public static void demo9() throws NoSuchFieldException {
Dog<Integer> d = new Dog<>("Tom",3);
Class<? extends Dog> dc = d.getClass();
Field t = dc.getField("t");
Type type = t.getGenericType();
if(type instanceof ParameterizedType){
ParameterizedType pt = (ParameterizedType) type;
Type[] at = pt.getActualTypeArguments();
System.out.println(at[0].getTypeName());
}
}
public static void demo8()
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<Dog> dc = Dog.class;
Constructor<Dog> cc = dc.getDeclaredConstructor();
cc.setAccessible(true);
Dog dog = cc.newInstance();
Method init = dc.getMethod("init");
//从方法对象上去获取该方法的注解
InitParam ip = init.getAnnotation(InitParam.class);
int age = ip.age();
String name = ip.name();
boolean gender = ip.gender();
Field[] df = dc.getDeclaredFields();
for(Field f :df){
switch(f.getName()){
case "name" : f.setAccessible(true);f.set(dog,name);break;
case "age" : f.setAccessible(true);f.setInt(dog,age);break;
case "gender" : f.setAccessible(true);f.setBoolean(dog,gender);break;
}
}
init.invoke(dog);
}
public static void demo7()
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
/*
* 通过反射的形式来调用方法
* */
Dog dog = new Dog("小数", 2);
//通过Class对象获取到play方法指针
Class<? extends Dog> dc = dog.getClass();
Method play = dc.getMethod("play",String.class);//获取可访问方法
play.invoke(dog, "天使");//dog.play("天使")
Method show = dc.getDeclaredMethod("show");//获取所有方法
show.setAccessible(true);
Object obj = show.invoke(dog);
String result = null;
if(obj instanceof String){
result = (String)obj;
}
System.out.println(obj);
}
public static void demo6() throws NoSuchFieldException, IllegalAccessException {
/*
* 通过反射来修改 相应的属性值 或者获取一些私有属性值
* */
Dog dog = new Dog("小白", 3);
dog.play("小新");
Class<? extends Dog> dc = dog.getClass();
Field name = dc.getDeclaredField("name");//只能获取所有
name.setAccessible(true);
Field age = dc.getField("age");//只能获取能够访问到的
int a = age.getInt(dog);
//需要从某个对象中获取指定的属性值
String nstr = (String)name.get(dog);
System.out.println("姓名"+nstr+",年龄:"+a);
name.set(dog,"小花");
age.set(dog,5);
dog.play("小明");
}
public static void demo5(){
/*
* 调用【私有】构造来创建对象
* */
try {
Constructor<Dog> privateCs = Dog.class.getDeclaredConstructor();
/*
* 默认情况下 私有内容获取到但不可使用 没有访问权限
* 获取Declared对象之后 需要设置其允许访问私有内容
* */
privateCs.setAccessible(true);//表示可以访问私有对象
Dog dog = privateCs.newInstance();
dog.play("阿强");
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
public static void demo4(){
/*
* 通过反射创建 调用普通构造器 来创建对象
* 该构造器含有参数 无法通过newInstance来创建
* 可以通过Constructor对象来使用指定类的构造器
* 所有反射创建对象都是通过newInstance来创建 区别就是参数
* */
Class<Dog> dc = Dog.class;
//通过类对象来获取该类的构造器对象
try {
Constructor<Dog> cs = dc.getConstructor(String.class, int.class);
System.out.println("构造器名称:"+cs.getName());
System.out.println("访问修饰符(整形):"+cs.getModifiers());
System.out.println("构造器的toString方法:"+cs);
Dog dog = cs.newInstance("小黑", 5);
dog.play("小白");
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
public static void demo3(){
//获取Dog的class对象
//1.通过类名.class
Class<Dog> dogClass = Dog.class;
//2.通过对象.getClass()方法
// Dog dog = new Dog();
// Class<? extends Dog> aClass = dog.getClass();
//3.通过Class.forName(String) 静态方法 String 为当前类的全限定名
try {
Class<?> aClass1 = Class.forName("com.liqk.reflect.Dog");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void demo1(){
/*
* 正常使用类和对象
* */
Dog dog = new Dog("旺财", 3);
dog.play("小明");
}
public static void demo2(){
/*
* 使用反射来创建对象
* */
try {
/*可以创建Dog对象 并没有使用new关键字
* 通过Class对象的 newInstance() 方法 可以待用该对象的 无参构造器来创建对象
* 所以需要对该类 创建出一个无参构造 或者不要创建任何构造 构造器必须是public
* */
Dog dog = Dog.class.newInstance();
dog.play("小红");
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}