反射
什么是反射
在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法、构造函数
对于任意一个对象,都能够调用它的任意一个方法和属性;
这个动态获取的信息以及动态调用对象的方法的功能成为Java语言的反射机制。
反射有什么用
反射 当一个字节码加载到内存的时候,jvm会对字节码进行解析,然后会创建与i个Class对象把所有的信息存储到Class对象中,我们就可以对对象设置或者调用方法和属性。
在运行时构造任意一个类的对象
在运行时调用任意一个对象的方法(属性)
在运行时获取任意一个类所具有的成员变量和方法。
Class类
Class类是Java语言中定义一个特定类的实现,一个类的定义包含成员变量,成员方法,还有这个类实现的接口,以及这个类的父类。
Class类的对象用于表示当前运行的Java应用程序中的类和接口。
获取Class对象的三种方式
1、通过类名获取 类名.class 该方法无法加载类
Class<Demo1> clazz = Demo1.class;
2、通过对象获取 对象名.getClass() 该方式获取的反射类是未知的泛型类,不能指定对应泛型
Demo1 demo1 = new Demo1();
Class<?> clazz = demo1.getClass();
```java
//3、通过全类名获取 Class.forName(全类名) 该方法可以加载类,就是可以加载静态内容(重点!!!!!)
Class<?> clazz = Class.forName("com.xxx.fanshe.Demo1");
public class Demo1 implements Serializable {
private String name;
private int age;
public void eat(){
System.out.println("吃了");
}
public void waiting(){
System.out.println("等待");
}
public Demo1(String name){}
public Demo1(){}
@Override
public String toString() {
return "Demo1{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
static {
System.out.println("静态代码块");
}
{
System.out.println("构造代码");
}
}
public class TestDemo {
public static void main(String[] args) {
//反射
// 1、通过类名获取 类名.class 该方法无法加载类
// Class<Demo1> clazz = Demo1.class;
// 2、通过对象获取 对象名.getClass() 该方式获取的反射类是未知的泛型类,不能指定对应泛型
// Demo1 demo1 = new Demo1();
// Class<?> clazz = demo1.getClass();
//3、通过全类名获取 Class.forName(全类名) 该方法可以加载类,就是可以加载静态内容(重点!!!!!)
try {
Class<?> clazz = Class.forName("com.xxx.fanshe.Demo1");
//取得所有属性,包括私有属性
Field[] fields = clazz.getDeclaredFields();
//clazz.getFields() 会受到访问修饰符的影响
for (Field field: fields) {
System.out.println(field);
}
//通过属性名获取属性
Field age = clazz.getDeclaredField("age");
System.out.println(age);
//获取父类 获取父类的属性、方法
Class<?> superclass = clazz.getSuperclass();
System.out.println(superclass);
//获取接口
Class<?>[] interfaces = clazz.getInterfaces();
for (Class class1: interfaces) {
System.out.println(class1);
}
//获取方法
Method[] ms = clazz.getDeclaredMethods();
for (Method method: ms) {
System.out.println(method);
}
//获取单个方法
Method eat = clazz.getDeclaredMethod("eat");
System.out.println(eat);
//获取构造方法
Constructor<?>[] aa = clazz.getDeclaredConstructors();
for (Constructor constructor: aa) {
System.out.println(constructor);
}
//通过特定的参数类型获取对应的构造方法
Constructor<?> ca = clazz.getDeclaredConstructor(String.class);
System.out.println(ca);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
public class TestDemo2 {
public static void main(String[] args) {
try {
Demo1 demo1 = new Demo1();
Class d2= demo1.getClass();
Field age = d2.getDeclaredField("age");
age.setAccessible(true);
age.set(demo1,11);
String s = age.get(demo1).toString();
System.out.println(s);
System.out.println(demo1);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
public class A implements Serializable {
private String name;
private int age;
private void eat(){
System.out.println("吃了");
}
public void waiting(){
System.out.println("等待");
}
public A(String name){}
private A(){}
@Override
public String toString() {
return "Demo1{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
static {
System.out.println("静态代码块");
}
{
System.out.println("构造代码");
}
}
public class TestA {
public static void main(String[] args) {
try {
Class<A> zla = A.class;
Constructor<A> structor = zla.getDeclaredConstructor();
//再次设置无视修饰符
structor.setAccessible(true);
//调用该反射出来的构造方法,实例化 newInstance 调用实例化步骤
A b = structor.newInstance();
System.out.println(b);
Method eat = zla.getDeclaredMethod("eat");
eat.setAccessible(true);
//invoke通过实体类,调用该实体类的方法
eat.invoke(b);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
注解
注释是对源代码作介绍或说明的文字 注解的定义:Java文件叫做Annotation(元数据),用@interface表示,即一种描述数据的数据元注解(系统自带的注解):@interface上面按选哟注解上一些东西,包括@Retention、@Target、@Document、@inherited四种
注解的保留策略:
注解的作用目标:
@inherited注解--在注解类里面加入
注解可以被继承--实体类子类没有该注解,父类有注解,那么子类也会拥有该注解
//创建了一个注解
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
//注解会在class字节码文件中存在,在运行时可以通过反射获取到。
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
//value是注解的特殊属性,使用个注解的时候,默认不填名称直接赋值,默认的赋值是value
//注解的属性 default表示该属性的默认值,就是别的类使用这个属性的时候,不声明默认就是该值。
String value() default "你";
}
@MyAnnotation("hello")
public class Demo1 {
@MyAnnotation("lalala")
private String name;
@MyAnnotation
private void eat(){
System.out.println("hh");
}
public static void main(String[] args) {
try {
Class<Demo1> clz = Demo1.class;
//获取类的注解
MyAnnotation c = clz.getDeclaredAnnotation(MyAnnotation.class);
System.out.println(c.value());
//获取属性上的注解
Field fiel = clz.getDeclaredField("name");
MyAnnotation c2 = fiel.getDeclaredAnnotation(MyAnnotation.class);
System.out.println(c2.value());
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
@Override
public String toString() {
return super.toString();
}
}