反射,这个名字就可体现出了反射的特点,就像镜子一样。
正常情况下:
调用方法:类名.方法名();
获取变量:对象名.属性名;
但在反射下:
调用方法:方法.inoke(对象名)
获取变量 :属性.get(对象名)
两个进行比较,刚好相反,就像再照镜子,很符合反射的名字,注意在反射下,方法、属性都是对象(通过class类对象拿到),万物皆对象。
看的是韩老师的视频
下面这张图体现了计算机程序的三个阶段
计算机编译阶段 会获得一个字节码文件,然后通过类加载器,再堆生成一个 Class类对象,注意:在一个程序中一个类只会有一个Class类对象,在这个Class类对象中,无论属性还是方法都是对象,真正的一切皆对象,方法是:Method 属性是:Field 构造器是:Constructor。然后再运行阶段,通过Class类对象,创建对象,但这个对象是知道它是属于哪一个Class对象的。再
获取class对象的三种方式(另外三种不重要) class对象是有泛型的
1.在编译阶段
通过Class的forName("路径")
Class cls1=Class.forName("java.lang.Cat");
应用场景:多用于配置文件,读取全路径,加载类
2 加载阶段(加载已经完成)
类名.class
Class cls2=Cat.class;
应用场景:多用于参数传递,比如通过反射得到对应的构造器对象
3.运行阶段
对象名.getClass()
应用场景:通过已经创建好的对象,获得class类对象
4.其他方式
ClassLoder cl=对象。getClass.getClassLoder();
Class clazz4=cl.loadClass("类的全类名");
5 基本数据类型获得class
基本数据类型.class
6.基本数据类型包装类
包装类.TYPE
通过class的方法可以获得class对象中类的属性、方法、构造器的对象
设置属性值的方法
f.set(o,值)//这个o是实例化对象o
下面是Class的常用方法
可以看出获取方法的命名都是get+类型(只能是public),如果中间有declared则说明可以是私有的,否则如果不满足权限,会报异常。当然就算拿到了也用不了,这个时候就要用到爆破了
爆破
通过调用类对象(属性,方法)的setAccessible() 方法,传入一个布尔值,要爆破就设置ture,这样就使用了,相当于走了个后门,绕过了访问权限
例子:
Method move = cls.getDeclaredMethod("move");//这个方法可返回私有的方法
move.setAccessible(true);//爆破
move.invoke(o);
Field name = cls.getDeclaredField("name");//可以包括私有的
name.setAccessible(true);//爆破
System.out.println(name.get(o));
获取对象的三种方法
1.常规的使用构造器
2,使用class类对象的newInstance() 方法 但只能用无参构造器
3.先获得构造器对象,通过参数进行选择,参数是数据类型的class类对象。再使用newInstance方法,
示例
Constructor declaredConstructor = cls.getDeclaredConstructor(String.class)
//获得构造器,通过传入参数的class对象获取
Cat a = (Cat)declaredConstructor.newInstance("可爱极了");
//创建对象,一样是通过newInstance,不过直接调用是访问的无参构造器,这个可以选择
a.love();
类加载分为静态加载和动态加载
1.静待加载:编译时加载相关的类,如果没有就会报错,依赖性太强
2 动态加载:运行时即加载需要的类,如果不运行该类,即使不存在,也不会报错,降低了依赖性
1.
创建对象new 、
加载子类时,加载父类、
调用类的静态成员
这些都是属于静态加载,在编译期就会完成加载
2
使用反射
这个属于动态加载,只有执行到这个语句时才会加载,为什么可以动态加载,主要是使用反射可以自己手动获得Class类对象,当然这里也就是能使用forName()方法,因为其他两种方法分别实在类加载阶段和实例完对象后才能用的,
最后是一些代码
package com.Cat.Reflection;
import com.Cat.Cat;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
@SuppressWarnings({"all"})
public class ReflectionQuesqution {
public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//传统方法
Cat cat=new Cat();
cat.hi();
//
//2使用Properties 类,可以读写配置文件
Properties properties = new Properties();
properties.load(new FileInputStream("src\\re.properties"));
String classfullpath = properties.get("classfullpath").toString();
String method=properties.get("method").toString();
System.out.println("classfullpath="+classfullpath);
System.out.println("method="+method);
//new com.Cat.Cat.var,通过全路经,可以生成对象
//但是我们用 classfullpath却无法生成,因为那是一个字符串
//通过类加载,获取Class类型的对象cls
Class cls= Class.forName(classfullpath);
//获得class的三种方式,1.forname (编译)2.类名.class(加载) 3.对象名.getclass
//通过cls得到的对象
Object o=cls.newInstance();
System.out.println("o的运行类型是="+o.getClass());
//通过cls得到的对象的getMethod 对象
Method method1=cls.getMethod(method);//要求权限为public
//通过menthod1调用方法,使用方法对象调用用方法-
method1.invoke(o);
//方法反射:方法.invoke(对象) 传统;对象.方法()
/* Field name = cls.getField("name");//获取属性*/
Field name = cls.getDeclaredField("name");//可以包括私有的
name.setAccessible(true);//爆破
System.out.println(name.get(o));
Class<Integer> integerClass = int.class;//基本类型获得class对象
Method move = cls.getDeclaredMethod("move");//这个方法可返回私有的方法
move.setAccessible(true);//爆破,
//可以总结出,setAccessible,可以使访问到私有权限,Declared则是可以返回这个方法或属性,然后用setAccessible爆破
move.invoke(o);
//同时获取方法的命名都是get+类型,如果中间有declared则说明可以是私有的,否则如果不满足权限,会报异常
//获取构造器
Constructor declaredConstructor = cls.getDeclaredConstructor(String.class);//获得构造器,通过传入参数的class对象获取
Cat a = (Cat)declaredConstructor.newInstance("可爱极了");//创建对象,一样是通过newInstance,不过直接调用是访问的无参构造器,这个可以选择
a.love();
Class<Cat> catClass = Cat.class;//通过类名返回class对象
//获得对象的三种方式
/*
* 1.调用构造器
*
* 2.使用class对象的newInstance方法
*
*
*
* 3.通过class对象获得构造器
*
* 再使用newInstance方法,获取正式对象
*
*
*
*
* */
Class<Integer> type = Integer.TYPE;
}
//
}
package com.Cat;
public class Cat {
private String name="莲莲";
public String des;
public void hi()
{
System.out.println("我是"+name);
}
public void cry ()
{
System.out.println("莲莲最可爱了");
}
public Cat() {
}
public Cat(String desc) {
this.des = desc;
}
private void move()
{
System.out.println("莲莲你带我走把");
}
public void love()
{
System.out.println(name+des);
}
}
配置文件
classfullpath=com.Cat.Cat
method=cry