java入门篇9 --- 反射

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java入门篇9 --- 反射相关的知识,希望对你有一定的参考价值。

反射

我们自己定义的class其实是JVM在运行时动态加载的,每读到一个class,JVM就会床架一个CLASS实例,并加载到内存中

我们首先看一下Class的源码,从源码可以看出,在进行实例化时,它是一个私有方法,因此,我们写的java程序无法将其实例化,通过分析源码,我们可以确认,我们定义的每个类最终都是Class的实例,因此他们都指向数据类型class或者interface,Class里面有很多字段,因此每个Class的实例里面包含这个类所有的信息

public final class Class<T> implements java.io.Serializable,
        GenericDeclaration,
        Type,
        AnnotatedElement,
        TypeDescriptor.OfField<java.lang.Class<?>>,
        Constable {
    private Class(ClassLoader loader, Class<?> arrayComponentType) {
        // Initialize final field for classLoader.  The initialization value of non-null
        // prevents future JIT optimizations from assuming this final field is null.
        classLoader = loader;
        componentType = arrayComponentType;
  ... } }
public class HelloWorld {
    public static void main(String[] args) throws Exception {
        Class t = new Class(ClassLoader.getPlatformClassLoader(), String.class);  //java: Class(java.lang.ClassLoader,java.lang.Class<?>) 在 java.lang.Class 中是 private 访问控制
    }
}

接下来看一下我们反射调用,这个一般自己写框架时会用到

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

class Person {
    public String name;

    public Person(String name) {
        this.name = name;
    }
    public void eat(){
        System.out.println("Person eat");
    }
    public String run(String s){
        return String.format("Person is running on %s", s);
    }
    public void nothing(){
    }
}

class Student extends Person {
    private String sex;
    public int age;

    public Student(String name, String sex, int age) {
        super(name);
        this.sex = sex;
        this.age = age;
    }
    @Override
    public void eat(){
        System.out.println("Student eat");
    }
    @Override
    public String run(String s){
        return String.format("Student is running on %s", s);
    }
    private void getSex(){
        System.out.println(this.sex);
    }
    public static void ss(){
        System.out.println("static");
    }
}

public class HelloWorld {
    public static void main(String[] args) throws Exception {
        // 获取string的Class实例
        Class c1 = String.class;
        Class c2 = "h".getClass();
        Class c3 = Class.forName("java.lang.String");
        // 因为Class实例是JVM中唯一的,都是String.class,因此可以使用 == 来进行比较
        System.out.println(c1 == c2);  // true  从结果分析,我们更可以断定,实例是唯一的
        System.out.println(c1 == c3);  // true
        // 我们以前用过 instanceof 来判断是否是可以向上转型
        Integer n = Integer.valueOf(1);
        System.out.println(n instanceof Number);  // true  因为Integer是Number的子类
        // System.out.println(n.getClass()  == Number.class);   // Error:(14, 42) java: 不可比较的类型: java.lang.Class<capture#1, 共 ? extends java.lang.Integer>和java.lang.Class<java.lang.Number>
        System.out.println("".getClass().getName());  // java.lang.String
        System.out.println("".getClass().getSimpleName()); // String
        System.out.println("".getClass().isInterface());  // false
        System.out.println("".getClass().isPrimitive());  // false
        System.out.println("".getClass().isArray());  // false
        Class stud = Student.class;
        // 获取字段,可以使用getField来获取指定字段,但是对于private字段,无法获取,需要使用getDeclaredField
        System.out.println(stud.getField("age"));  // public int Student.age
        System.out.println(stud.getField("name"));  // public java.lang.String Person.name
        System.out.println(stud.getDeclaredField("sex"));  // private java.lang.String Student.sex
        // System.out.println(stud.getField("sex"));  // Exception in thread "main" java.lang.NoSuchFieldException: sex
        // 使用getFields,来获取全部非privte字段
        Field[] f = stud.getFields();
        System.out.println("----");
        for (Field ff : f) {
            System.out.println(ff);
        }  // public int Student.age   public java.lang.String Person.name
        System.out.println("----");
        // 使用getDeclaredFields,来获取当前类全部字段
        Field[] f1 = stud.getDeclaredFields();
        for (Field ff1 : f1) {
            System.out.println(ff1);
        }  // private java.lang.String Student.sex  public int Student.age
        Field f2 = stud.getField("age");
        Field f3 = stud.getDeclaredField("sex");
        System.out.println(f2.getName());  // age 获取这个字段的名称
        System.out.println(f3.getName());  // name 获取这个字段的名称
        System.out.println(f2.getType());  // int 获取这个字段的类型
        System.out.println(f3.getType());  // class java.lang.String 获取这个字段的类型
        System.out.println(f2.getModifiers());  // 1  获取这个字段的修饰符 该字段修饰符是public,不同的int值代表不同
        System.out.println(f3.getModifiers());  // 2  获取这个字段的修饰符
        int ff2 = f2.getModifiers();
        System.out.println(Modifier.isFinal(ff2));  // false
        System.out.println(Modifier.isPrivate(ff2)); // false
        System.out.println(Modifier.isPublic(ff2));  // false
        // 获取字段的值
        Student s = new Student("ming", "male", 25);
        Class st = s.getClass();
        Field f4 = st.getDeclaredField("sex");
//        Object v = f4.get(s);  // java.lang.IllegalAccessException: class HelloWorld cannot access a member of class Student with modifiers "private" 被阻止
        f4.setAccessible(true);  // 对于private字段,使用setAccessible(true),但是仍然有可能会报IllegalAccessException错误
        Object v = f4.get(s);
        System.out.println(v);  // male 获取字段的值
        // 重置字段的值
        Field f5 = st.getField("name");
        f5.set(s, "ning");
        f5.setAccessible(true);  // 对于private,都需要设置这个
        f4.set(s, "female");
        System.out.println(s.name);  // ning
        System.out.println(f4.get(s));  // female
        // 获取方法
        Class ss = Student.class;
        System.out.println(ss.getMethod("run", String.class)); // public java.lang.String Student.run(java.lang.String)
        System.out.println(ss.getMethod("eat"));  // public void Student.eat()
        // System.out.println(ss.getMethod("getSex"));  // 无法获取私有方法,java.lang.NoSuchMethodException: Student.getSex()
         System.out.println(ss.getDeclaredMethod("getSex"));  // private void Student.getSex()
        Method[] sm = ss.getMethods();
        Method[] sm1 = ss.getDeclaredMethods();
        System.out.println("---");
        for(Method smm : sm){
            System.out.println(smm);
        } //public java.lang.String Student.run(java.lang.String) public void Student.eat() public void Person.nothing() public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
//        public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
//        public final void java.lang.Object.wait() throws java.lang.InterruptedException
//        public boolean java.lang.Object.equals(java.lang.Object)
//        public java.lang.String java.lang.Object.toString()
//        public native int java.lang.Object.hashCode()
//        public final native java.lang.Class java.lang.Object.getClass()
//        public final native void java.lang.Object.notify()
//        public final native void java.lang.Object.notifyAll()
        System.out.println("---");
        // 无法获取父类的方法
        for(Method smm : sm1){
            System.out.println(smm);
        } // public java.lang.String Student.run(java.lang.String) public void Student.eat() private void Student.getSex()

        Method smm = ss.getMethod("run", String.class);
        Method smm1 = ss.getMethod("eat");
        // 获取方法名
        System.out.println(smm.getName());  // run
        System.out.println(smm1.getName());  // eat
        // 获取返回类型
        System.out.println(smm.getReturnType());  // class java.lang.String
        System.out.println(smm1.getReturnType());  // void
        // 获取参数数量
        System.out.println(smm.getParameterCount());  // 1
        System.out.println(smm1.getParameterCount()); // 0

        // 方法的调用
        System.out.println(smm.invoke(s, "floor")); // Student is running on floor
        smm1.invoke(s);  // Student eat
//         Method smm2 = ss.getMethod("getSex"); // java.lang.IllegalArgumentException: object is not an instance of declaring class
        Method smm2 = ss.getDeclaredMethod("getSex");
        smm2.setAccessible(true);  // 如果不设置这个会报错,私有属性必须设置
        smm2.invoke(s); // female
        // 多态
        Method p = Person.class.getMethod("eat");
        p.invoke(s);  // Student eat 虽然方法是person的,但传入的实例属于Student,因此但因Student方法
        // 调用静态方法
        Method ssm = Student.class.getMethod("ss");
        ssm.invoke(null);  // static

        // 获取构造方法
        Constructor pp = Person.class.getConstructor(String.class);
        Person ppp = (Person) pp.newInstance("ming");
        System.out.println(ppp.name);  // ming

        // 获取继承关系
        Class s5 = Student.class;
        System.out.println(s5.getSuperclass());  // class Person
        System.out.println(s5.getSuperclass().getSuperclass()); // class java.lang.Object
        // 获取interface 值返回直接实现的
        Class[] s5i = s5.getInterfaces();
        System.out.println("---");
        for(Class s5s : s5i){
            System.out.println(s5s);
        }  //
        System.out.println("---");
        Class[] i5 = Integer.class.getInterfaces();
        for(Class i5s : i5){
            System.out.println(i5s);
        }  // interface java.lang.Comparable interface java.lang.constant.Constable interface java.lang.constant.ConstantDesc
    }

}

以上是关于java入门篇9 --- 反射的主要内容,如果未能解决你的问题,请参考以下文章

反射机制入门

反射机制入门

反射机制入门

java 反射代码片段

Java入门提高篇Day13 Java中的反射机制

一篇入门 -- Scala 反射