JAVA Class25

学习内容:

1.反射

反射目的是在不修改代码的情况下,只需修改外部配置文件,实现调用不同类的不同方法。

(1)类的载入

当我们需要使用一个类时,我们要将这个类载入JVM,这里就要用到类载入的方法:

另外,在我们实例化一个对象是,类会自动载入,另外,实例化一个子类对象会导致父类自动载入

public class Person {
    public String name;
    private int age;
    static {//注意这个静态代码块!
        System.out.println("静态代码块");
    }
    public Person() {
        super();
    }
    public Person(String name,int age) {
        super();
        this.name = name;
        this.age = age;
    }
} 
public class TestPerson {

    @SuppressWarnings({"rawtypes","unchecked"})//忽略多类型警告
    public static void main(String[] args) {
        try {
            Class c1 = Class.forName("edu.java.reflection.Person");//包名.类名
            Class c2 = new Person().getClass();
            //上述两种方式都会初始化静态属性,且只会执行一次!
            Class c3 = Person.class;//不会初始化静态属性
            //在一个JVM中,一种类,只会有一个类对象存在。所以以上三种方式取出来的类对象,都是一样的。
            //注: 准确的讲是一个ClassLoader下,一种类,只会有一个类对象存在。通常一个JVM下,只会有一个ClassLoader。
            System.out.println(c1==c2);//true
            System.out.println(c1.equals(c2));//true
            System.out.println(c1==c3);//true
            System.out.println(c1.equals(c3));//true
  }
}

(2)构造器的获取与利用构造器实例化对象:

public class TestPerson {

    @SuppressWarnings({"rawtypes","unchecked"})
    public static void main(String[] args) {
        try {
            Class c1 = Class.forName("edu.java.reflection.Person");//包名.类名
            //获取造器数组
            Constructor[] con = c1.getConstructors();//获取所有公共的构造器
            for(Constructor s:con) {
                System.out.println(s);
            }
            //获取空参构造器
            Constructor con = c1.getConstructor();
            //空参构造器实例化对象
            Object obj = con.newInstance();
            Person p = (Person)obj;//newInstance()返回的是Object,向下强转Person*/
            //有参构造器
            Class[] v = {String.class,int.class};
            Constructor con = c1.getConstructor(v);
            Object obj = con.newInstance("张三",20);
            Person p = (Person)obj;*/
            System.out.println(p);
            Constructor[] all = c1.getDeclaredConstructors();//获取所有构造器,包括私有的
            for(Constructor con:all) {
                System.out.println(con);
            }
            Constructor con = c1.getDeclaredConstructor(String.class);//获取私有的有参构造器
            con.setAccessible(true);//取消变量权限检查,可以访问私有化变量
            Object obj = con.newInstance("李四");
            Person p = (Person)obj;
            System.out.println(p);*/
            //空参构造快速生成对象
            Object obj = c1.newInstance();
            Person p = (Person)obj;
  }
}

(3)获取字段追

public class TestPerson {

    @SuppressWarnings({"rawtypes","unchecked"})
    public static void main(String[] args) {
        try {
            Class c1 = Class.forName("edu.java.reflection.Person");//包名.类名
            Field[] f = c1.getFields();//获取所有公共字段
            for(Field i:f) {
                System.out.println(i);
            }
            Constructor con = c1.getConstructor(String.class,int.class);
            Object obj = con.newInstance("张三",20);
            Person p = (Person)obj;
            Field f = p.getClass().getField("name");//获取对象的指定字段值
            f.set(p, "李四");
            System.out.println(p);
            Field age = p.getClass().getDeclaredField("age");//获取私有变量
            age.setAccessible(true);
            age.set(p, 30);
            System.out.println(p);
        } catch(Exception e) {
            e.printStackTrace();
        }
        
    }

}

(4)通过类获取方法

public class TestPerson {

    @SuppressWarnings({"rawtypes","unchecked"})
    public static void main(String[] args) {
        try {
            Class c1 = Class.forName("edu.java.reflection.Person");//包名.类名
            Constructor con = c1.getConstructor(String.class,int.class);
            Object obj = con.newInstance("张三",20);
            Person p = (Person)obj;
            Field f = p.getClass().getField("name");//获取对象的指定字段值
            f.set(p, "李四");
            System.out.println(p);
            Field age = p.getClass().getDeclaredField("age");//获取私有变量
            age.setAccessible(true);
            age.set(p, 30);
            System.out.println(p);*/
            //获取所有方法
            Method[] all = c1.getMethods();
            for(Method mm:all) {
                System.out.println(mm);
            }
            Method m1 = c1.getMethod("eat");
            m1.invoke(p);
            Method m2 = c1.getDeclaredMethod("sleep",String.class,int.class,double.class);//获取私有带参方法
            m2.setAccessible(true);
            m2.invoke(p,p.name,30,90);
        } catch(Exception e) {
            e.printStackTrace();
        }
        
    }

}

2.泛型擦除

JAVA的泛型是”假泛型“,不进class文件,所以利用反射,我们可以突破泛型限制添加数据

public class TestPerson {

    @SuppressWarnings({"rawtypes","unchecked"})
    public static void main(String[] args) {
        try {
            //泛型擦除
            ArrayList<String> list = new ArrayList<String>();
            list.add("abc");
            Class c = list.getClass();
            Method method = c.getMethod("add", Object.class);
            method.invoke(list, 1);
            System.out.println(list);//数字1被成功添加,JAVA的泛型是”假泛型“,不进class文件
            System.out.println(list.get(0));
            System.out.println(list.get(1));//但是获取会报类型转换失败错误
        } catch(Exception e) {
            e.printStackTrace();
        }
        
    }

}

3.泛型应用

public class Test {
     @SuppressWarnings({ "rawtypes", "unchecked" })//忽略多类型警告
    public static void main(String[] args) throws Exception {
        //从spring.txt中获取类名称和方法名称
        File sp = new File("e:/java/spring/spring.txt");
        Properties sc = new  Properties();
        sc.load(new FileInputStream(sp));
        String classname = (String)sc.get("class");
        //String methodname = (String)sc.get("method");
        String methodname = sc.getProperty("method");
        //根据类名称获取类对象
        Class cl = Class.forName(classname);
         //根据方法名称,获取方法对象
        Method m = cl.getMethod(methodname);
         //获取构造器
        Constructor c = cl.getConstructor();
        //根据构造器,实例化出对象
        Object service = c.newInstance();
        //调用对象的指定方法
        m.invoke(service);
        //如果要切换类及方法,只改变外部的txt文件内容即可,代码不用改
    }

}

猜你喜欢

转载自www.cnblogs.com/whwjava/p/8966829.html