产生原因:运行时获取、修改数据(类信息、成员数据信息)。
Class对象分为基本类型(8种)、引用类型:(具体内容在文章末尾)
JVM会为每个对象(基础和引用类型)实例化一个java.lang.Class实例。通过这个Class对象,可以在运行时访问对象的属性和类信息、也可以创建新的对象和类。反射的实现,首先要获取Class实例。
获取Class实例的方法:
Class class = object.getClass();
枚举类型的对象获取的是枚举类的Class,数组对象获取的是数组元素的Class。
Objcet.class;
int.class.newInstance()
只能用于引用类型,需要类的完整路径:如java.lang.String
Class> class = Class.forName("java.lang.String");
Class<String> class = String.TYPE;
TYPE的定义:public static final Class<String> TYPE = (Class<String>) String[].class.getComponentType();
获取相关类的Class对象:
int modifier = class.getModifiers() ;
String modifierStr = Modifier.toString(int modifiers);
同时因为Field继承了AnnotatedElement,所以在运行时可以获取注解,获取的注解必须是RUNTIME所修饰的注解
getDeclaredConstructor(Class>... parameterTypes)获取指定的构造方法,可获取私有方法
getConstructor(Class>... parameterTypes) 获取指定的构造方法,不可获取私有方法
getDeclaredConstructors() 获取所有构造方法,可获取私有方法
getConstructor(Class>... parameterTypes) 获取所有构造方法,不可获取私有方法
获取变量:
getDeclaredField(String name);// 获取指定的变量 类自有变量 包括取私有变量,但是不能获取继承父类的
getField(String name); //获取指定的变量,可获取自身和继承自父类的public变量。
getDeclaredFields(); //获取类自有的所有变量集合,包括私有变量,不包括继承变量
getFields(); //获取自身和继承自父类的public变量的集合。
获取变量类型:
Field.getType() :返回Class对象 ,这个变量的类型
Field.getGenericType():返回Type接口 ,如果类型是泛型,getGenericType可以得到这个泛型的参数类型(T),getType()只能得到这个类型的接口类型(Object)。
设置变量的值
Class cls = object.getClass();
Field field = objcet.getField("name");
field.set(object,"new Name");
//修改变量的值时,编译器不会拆装箱操作,设置时必须设置相同的类型
Integer itg;
Class cls = object.getClass();
Field field = objcet.getField("itg");
field.set(object,new Integer(666));
//直接修改final类型的变量会报错`IllegalAccessException` 需要setAccessible(true),
//就可以访问修改了。(由于 `Field` 继承自 `AccessibleObject` , 我们可以使用
//`AccessibleObject.setAccessible()` 方法告诉安全机制,这个变量可以访问。 )
//获取的方法属性同成员变量。
getDeclaredMethod(String name,Class parameterTypes.....)
getMethod(String name,Class parameterTypes.....)
getDeclaredMethods()
getMethods()
继承于父类的方法因强制执行无法被反射,因此反射方法仅限本类方法。
反射方法得到的数据由:修饰符、返回值、参数、注解、抛出异常五点组成:
getName()); //获得单独的方法名
toGenericString()); //获得完整的方法信息(包括修饰符、返回值、路径、名称、参数、抛出值)
int modifiers = declaredMethod.getModifiers();Modifier.toString(modifiers) /获得修饰符
getReturnType(); //获得返回值
getGenericReturnType();//获得完整信息的返回值
//获得参数类型
Class>[] parameterTypes = method.getParameterTypes();
Type[] genericParameterTypes = method.getGenericParameterTypes();
//获得异常名称
Class>[] exceptionTypes = declaredMethod.getExceptionTypes();
Type[] genericExceptionTypes = declaredMethod.getGenericExceptionTypes();
//获得注解
Annotation[] annotations = declaredMethod.getAnnotations();
annotations[i].annotationType();
三种特殊的方法类型:
synthetic(合成,内部类访问权限), varagrs(参数可变), bridge(桥接,泛型相关)
反射 调用方法
invoke() ;
//java.lang.reflect.Method.invoke(Object receiver,Object... args)
//该方法抛异常:java.lang.reflect.InvocationTargetException
receiver 是方法所属于的对象,静态方法可直接传null,args传方法的参数
//当访问private属性的方法时,需要设置setAccessible(true) 否则报`IllegalAccessException`异常
相似概念:Introspection(自省):
区别:
Introspection 是在运行时获取对象的信息,Reflection是获取或者修改对象的信息
Introspection多用于 instanceof 的判断,Reflection多用来实现访问私有方法,创建对象等
总的说,Reflection是多了可进行修改信息。
Class对象的基本类型(8种)、引用类型:
基本类型:
整型:默认类型int
浮点类型:默认类型double
bool值
boolean : true/false、 默认值false
字符型
引用类型:
修饰符用来定义类、方法、变量,通常在语句首位,分为两大类:访问修饰符和非访问修饰符
default:
缺省值,不写明修饰符,在同一包内可见(类,接口,变量,方法可用)
接口中变量隐式声明为public static final,方法隐式声明为public
public:
对所有的类可见(类、接口、方法、变量可用)
java 中main方法一定为共有的
protected:
同一个包中的所有子类和其他类都可以访问(变量、方法可用,不能修饰类(外部类)和接口(及接口的变量和方法))
不同包中的子类可见(变量、方法可用,不能修饰类(外部类)和接口(及接口的变量和方法)),其他类不能访问。
不同包中的子类不能使用父类的实例对象访问其父类的protect属性的变量和方法。即:superClass.protectParameter不可见。只能subClass.protectParameter访问。
避免不相关的类访问。
private:
最严格访问级别,为了隐藏类实现的细节,保护类的数据,外部类和接口不能声明为private。
只能在同一个类内可见(变量、方法可用,不能修饰外部类和接口(及接口的变量和方法))
访问修饰符在继承中的规则:子类权限必须大于父类,具体如下:
1.父类public子类必为public.
2.父类protected子类必须protected/public.
3. 父类private子类无法继承.
abstract:
创建抽象类和抽象方法
一个类不能同时被abstract和final修饰,一个类只要包含抽象方法,就一定要声明为抽象类。抽象类可以包含抽象和非抽象的方法,也可以不包含抽象方法。
抽象方法不能被声明为static 和final,子类必须实现父类的抽象方法,除非子类也是抽象类
static:
可以直接通过类名访问static修饰的变量和方法,如StaticClass.variableName /StaticClass.methodName().
static 变量:也叫类变量,属于类所有,独立于类的实例对象(实例对象可以有多个,类变量只有一份),
只能修饰成员变量,不可修饰局部变量。
static 方法:类方法,独立于类的实例对象,方法内不能包含非静态的成员变量。
final:
final修饰的类不能被继承,方法不能被子类重写,变量为常量不可修改。
final修饰的变量必须显示初始化并且只能赋值一次。
final变量不可修改,是指的其引用不可修改,引用变量的值改变,fianl变量包含的数据是可以改变的。:
final Person p = new Person(24,name);
p.setAge(25);
final一般结合static创建常量。static final String CONSTANT_STRING = "I'M CONSTANT STRING"
final修饰的方法不可被子类修改,可以防止该方法被改动
synchronized:
说明被修饰的方法在同一个时间只能被一个线程访问,synchronized修饰符可以用应于 所有访问修饰符(public、default、private、protected)
transient:
序列化对象时,JVM会跳过transient修饰的变量。public transient String str = "I'll be ignored";
volatile
volatile修饰的成员变量在每次被线程访问时,都需要从共享内存中重新读取该成员变量的值,
当此成员变量发生变化时,会强制线程将变化值写回共享内存,因此,在任何时刻,多个线程中此成员变量的值都相同。
native
在JAVA中调用非JAVA语言写的方法(如C、C++) :native void nativeMethod(.....);
native 不可以和abstract修饰符一起使用。(native虽然在JAVA代码没有方法体,但本地方法是有实现的)
使用native主要是为了和java环境和操作系统等交互,本地方法在JAVA加载是,放在DLL文件中,方法native方法调用前,本地方法会被加载。
https://blog.csdn.net/u011240877/article/details/54604146