zoukankan      html  css  js  c++  java
  • day9 反射

    package com.atguigu.java;

    import org.junit.Test;

    import java.lang.annotation.ElementType;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;


    public class ReflectionTest {


    //反射之前,对于Person的操作
    @Test
    public void test1() {

    //1.创建Person类的对象
    Person p1 = new Person("Tom", 12);

    //2.通过对象,调用其内部的属性、方法
    p1.age = 10;
    System.out.println(p1.toString());

    p1.show();

    //在Person类外部,不可以通过Person类的对象调用其内部私有结构。
    //比如:name、showNation()以及私有的构造器
    }

    //反射之后,对于Person的操作
    @Test
    public void test2() throws Exception{
    Class clazz = Person.class;          //Class 是反射的源头
    //1.通过反射,创建Person类的对象
    Constructor cons = clazz.getConstructor(String.class,int.class);
    Object obj = cons.newInstance("Tom", 12);
    Person p = (Person) obj;
    System.out.println(p.toString());
    //2.通过反射,调用对象指定的属性、方法
    //调用属性
    Field age = clazz.getDeclaredField("age");
    age.set(p,10);
    System.out.println(p.toString());

    //调用方法
    Method show = clazz.getDeclaredMethod("show");
    show.invoke(p);

    System.out.println("*******************************");

    //通过反射,可以调用Person类的私有结构的。比如:私有的构造器、方法、属性
    //调用私有的构造器
    Constructor cons1 = clazz.getDeclaredConstructor(String.class);
    cons1.setAccessible(true);
    Person p1 = (Person) cons1.newInstance("Jerry");
    System.out.println(p1);

    //调用私有的属性
    Field name = clazz.getDeclaredField("name");
    name.setAccessible(true);
    name.set(p1,"HanMeimei");
    System.out.println(p1);

    //调用私有的方法
    Method showNation = clazz.getDeclaredMethod("showNation", String.class);
    showNation.setAccessible(true);
    String nation = (String) showNation.invoke(p1,"中国");//相当于String nation = p1.showNation("中国")
    System.out.println(nation);


    }
    //疑问1:通过直接new的方式或反射的方式都可以调用公共的结构,开发中到底用那个?
    //建议:直接new的方式。
    //什么时候会使用:反射的方式。 反射的特征:动态性,对象现用现造   P638
    //疑问2:反射机制与面向对象中的封装性是不是矛盾的?如何看待两个技术?
    //不矛盾。

    /*
    关于java.lang.Class类的理解
    1.类的加载过程:
    程序经过javac.exe命令(编译命令)以后,会生成一个或多个字节码文件(.class结尾)。
    接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件
    加载到内存中。此过程就称为类的加载。加载到内存中的类,我们就称为运行时类(比如Person类),此
    运行时类,就作为Class的一个实例。            //任何类本身也是Class的对象

    2.换句话说,Class的实例就对应着一个运行时类。   Class实例就是用一个运行时类来进行赋值的。
    3.加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同的方式
    来获取此运行时类。      加载到内存中时,运行时类就在,c1-c3用的都是那一个运行时类,就是单例。
    */
    //获取Class的实例的方式(前三种方式需要掌握)
    @Test
    public void test3() throws ClassNotFoundException {
    //方式一:调用运行时类的属性:.class
    Class clazz1 = Person.class;            //写死了,无动态性体现
    System.out.println(clazz1);       //输出person类本身
    //方式二:通过运行时类的对象,调用getClass()
    Person p1 = new Person();
    Class clazz2 = p1.getClass();
    System.out.println(clazz2);

    //方式三,★用的多,能更好体现动态性:调用Class的静态方法:forName(String classPath)        反射主要体现的就是运行时的动态性,编译时不确定。
    Class clazz3 = Class.forName("com.atguigu.java.Person");       //怕找不到类报异常。throw
    // clazz3 = Class.forName("java.lang.String");
    System.out.println(clazz3);

    System.out.println(clazz1 == clazz2);                                               //判断地址值,看是否是同一个对象 获取的是内存中同一个运行时类。 so true
    System.out.println(clazz1 == clazz3);

    //方式四:使用类的加载器:ClassLoader (了解)
    ClassLoader classLoader = ReflectionTest.class.getClassLoader();
    Class clazz4 = classLoader.loadClass("com.atguigu.java.Person");
    System.out.println(clazz4);

    System.out.println(clazz1 == clazz4);                     //true

    }


    //万事万物皆对象?对象.xxx,File,URL,反射,前端、数据库操作


    //Class实例可以是哪些结构的说明(接口,数组,注解,枚举。。。。。都算,只要加载进内存后,都算Class的实例) :
    @Test
    public void test4(){
    Class c1 = Object.class;
    Class c2 = Comparable.class;
    Class c3 = String[].class;
    Class c4 = int[][].class;
    Class c5 = ElementType.class;
    Class c6 = Override.class;
    Class c7 = int.class;
    Class c8 = void.class;
    Class c9 = Class.class;

    int[] a = new int[10];
    int[] b = new int[100];
    Class c10 = a.getClass();
    Class c11 = b.getClass();
    // 只要数组的元素类型与维度一样,就是同一个Class
    System.out.println(c10 == c11);          //true,属于同一个class

    }
    }

    package com.atguigu.java;

    import org.junit.Test;

    import java.io.InputStream;
    import java.util.Properties;


    //了解类的加载器

    public class ClassLoaderTest {

    @Test
    public void test1(){
    //对于自定义类,使用系统类加载器进行加载     获取当前自定义类的加载器
    ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
    System.out.println(classLoader);
    //调用系统类加载器的getParent():获取扩展类加载器
    ClassLoader classLoader1 = classLoader.getParent();
    System.out.println(classLoader1);
    //调用扩展类加载器的getParent():无法获取引导类加载器
    //引导类加载器主要负责加载java的核心类库,无法加载自定义类的。
    ClassLoader classLoader2 = classLoader1.getParent();
    System.out.println(classLoader2);                                             //null 

    ClassLoader classLoader3 = String.class.getClassLoader();
    System.out.println(classLoader3);                                 //null 获取不到引导类的加载器

    }
    /*
    Properties:  ★★★★用来读取配置文件。

    */
    @Test
    public void test2() throws Exception {

    Properties pros = new Properties();
    //此时的文件默认在当前的module下。
    //读取配置文件的方式一:
    // FileInputStream fis = new FileInputStream("jdbc.properties");
    // FileInputStream fis = new FileInputStream("src\jdbc1.properties");
    // pros.load(fis);

    //读取配置文件的方式二:使用ClassLoader
    //配置文件默认识别为:当前module的src下
    ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
    InputStream is = classLoader.getResourceAsStream("jdbc1.properties");
    pros.load(is);                 //


    String user = pros.getProperty("user");
    String password = pros.getProperty("password");
    System.out.println("user = " + user + ",password = " + password);

    }

    }

    package com.atguigu.java;

    import org.junit.Test;

    import java.util.Random;

    /**
    * 通过反射创建对应的运行时类的对象
    *
    */
    public class NewInstanceTest {

    @Test
    public void test1() throws IllegalAccessException, InstantiationException {     //InstantiationException表示没有空参构造器,IllegalAccessException表示非法访问(私有的你要访问就抛出问题)

    Class<Person> clazz = Person.class;
    /*
    newInstance():调用此方法,创建对应的运行时类的对象。内部调用了运行时类的空参的构造器

    要想此方法正常的创建运行时类的对象,要求:
    1.运行时类必须提供空参的构造器
    2.空参的构造器的访问权限得够。通常,设置为public。


    在javabean中要求提供一个public的空参构造器。原因:
    1.便于通过反射,创建运行时类的对象
    2.便于子类继承此运行时类时,默认调用super()时,保证父类有此构造器

    */
    Person obj = clazz.newInstance(); //obj是person类的对象
    System.out.println(obj);

    }

    //体会反射的动态性 难点 。框架就用这个知识点
    @Test
    public void test2(){

    for(int i = 0;i < 100;i++){
    int num = new Random().nextInt(3);//返回的值是0,1,2
    String classPath = "";
    switch(num){
    case 0:
    classPath = "java.util.Date";
    break;
    case 1:
    classPath = "java.lang.Object";
    break;
    case 2:
    classPath = "com.atguigu.java.Person";
    break;
    }

    try {
    Object obj = getInstance(classPath);
    System.out.println(obj);
    } catch (Exception e) {
    e.printStackTrace();
    }
    }

    }

    /*
    创建一个指定类的对象。
    classPath:指定类的全类名
    */
    public Object getInstance(String classPath) throws Exception {
    Class clazz = Class.forName(classPath);
    return clazz.newInstance();
    }

    }

  • 相关阅读:
    Exchange 2013与 Office Web Apps 整合
    SharePoint2013 以其他用户登录和修改AD域用户密码 功能
    sharepoint 2010 自定义页面布局
    sharepoint 2010 记录管理 对象模型
    SharePoint2010 对象模型 关联列表
    在SharePoint Server 2010中更改“我的网站”
    xenapp 6.5 客户端插件第一次安装总是跳到官网
    如何解决在Windows Server 2008 R2 上安装证书服务重启后出现 CertificationAuthority 91错误事件
    在Win7 Hyper-v虚拟机中挂接真实机的声卡
    win8 中如何删除 共享文件夹 用户名和密码
  • 原文地址:https://www.cnblogs.com/wangyanbin2333/p/13339233.html
Copyright © 2011-2022 走看看