为什么叫反射?

因为我们正常情况下:
引用一个“包类” -> new一个类的对象

但是反射是:
通过一个对象的getClass()方法 -> 得到“包类”的名称

优点和缺点?

优点:
可以动态创建对象和编译,灵活

缺点:
对性能有影响。new一个对象和用反射生成对象,效率相差好几十倍。

一个类有多少个Class对象?

一个:

  1. public class TestReflection {
  2. public static void main(String[] args) throws ClassNotFoundException {
  3. // 通过反射获取Class对象
  4. Class<?> cl1 = Class.forName("org.example.User");
  5. Class<?> cl2 = Class.forName("org.example.User");
  6. Class<?> cl3 = Class.forName("org.example.User");
  7. Class<?> cl4 = Class.forName("org.example.User");
  8. System.out.println(cl1.hashCode());
  9. System.out.println(cl2.hashCode());
  10. System.out.println(cl3.hashCode());
  11. System.out.println(cl4.hashCode());
  12. }
  13. }
  14. // 结果是hashCode都是相等的,说明是同一个对象。

三种获得Class对象的方式

  1. Class.forName("包名+类名")
  1. // 根据对象来获取Class对象
  2. // 会获得Person类的Class对象
  3. person.getClass();
  1. // 直接通过类.class属性
  2. Person.class;

什么时候会初始化类?

直接new一个对象, 注意会先初始化父类,再初始化子类。

  1. Son son = new Son();

反射, 同样也是先初始化父类,再初始化子类。

  1. Class.forName("com.example.Son");

什么时候不会初始化类?

子类调用父类的静态方法或者使用父类的静态变量, 注意,子类可以调用父类的静态方法,以及访问父类的静态变量。但此时并不会初始化子类,而只会初始化父类。

  1. public class Test {
  2. public void static main(String[] args) {
  3. System.out.println(Son.b);
  4. }
  5. }
  6. class Father {
  7. static int b = 2;
  8. static {
  9. System.out.println("父类被加载");
  10. }
  11. }
  12. class Son extends Father {
  13. static {
  14. System.out.println("子类被加载");
  15. }
  16. }

new一个对象数组也不会初始化该对象:

  1. // 以下代码并不会引起类的初始化,因为只是分配以一块空间
  2. // 并没有用到Son这个类。
  3. Son[] sonArray = new Son[5];

引用常量也不会触发该类的初始化

  1. public class Test1 {
  2. public static void main(String[] args) {
  3. System.out.println(Son.a);
  4. }
  5. }
  6. class Son {
  7. public static final int a = 5;
  8. static {
  9. System.out.println("初始化Son");
  10. }
  11. }
  12. // 会输出5,但是不会输出静态代码块的内容,因为类没有初始化。

获取类的运行时结构

获取包名 + 类名

  1. Class<?> c1 = Class.forName("org.example.reflection.User");
  2. System.out.println(c1.getName());

只获取类名

  1. System.out.println(c1.getSimpleName());

获取所有属性

  1. Field[] declaredFields = c1.getDeclaredFields();
  2. for (Field f : declaredFields) {
  3. System.out.println(f);
  4. }

只获取public属性

  1. Field[] field = c1.getFields();
  2. for (Field f : field) {
  3. System.out.println(f);
  4. }

获取本类中的所有方法,包括private方法

  1. Method[] declaredMethods = c1.getDeclaredMethods();
  2. for (Method method : declaredMethods) {
  3. System.out.println(method);
  4. }
  5. ====================
  6. public java.lang.String org.example.reflection.User.getName()
  7. public void org.example.reflection.User.setName(java.lang.String)
  8. private void org.example.reflection.User.privateMethod()
  9. public void org.example.reflection.User.setAge(int)
  10. public int org.example.reflection.User.getAge()

只获取本类及其父类中的public方法

  1. System.out.println("====================");
  2. Method[] methods = c1.getMethods();
  3. for (Method method : methods) {
  4. System.out.println(method);
  5. }
  6. ====================
  7. public java.lang.String org.example.reflection.User.getName()
  8. public void org.example.reflection.User.setName(java.lang.String)
  9. public void org.example.reflection.User.setAge(int)
  10. public int org.example.reflection.User.getAge()
  11. public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
  12. public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
  13. public final void java.lang.Object.wait() throws java.lang.InterruptedException
  14. public boolean java.lang.Object.equals(java.lang.Object)
  15. public java.lang.String java.lang.Object.toString()
  16. public native int java.lang.Object.hashCode()
  17. public final native java.lang.Class java.lang.Object.getClass()
  18. public final native void java.lang.Object.notify()
  19. public final native void java.lang.Object.notifyAll()