zoukankan      html  css  js  c++  java
  • 第14章_类型信息:


    1:“运行时类型识别”(RTTI, Run-Time Type Identification)是非常有用的机制,在Java运行时,RTTI维护类的相关信息
    多态(polymorphism)是基于RTTI实现的。RTTI的功能主要是由Class类实现的。
    2:每当编译了一个新类,就会产生一个Class对象(恰当的说是被保存在Class文件中)
    3:JVM使用“类加载器”将这个对象,类加载系统包含了一条类加载器链,在这条链上只有一个“原生类加载器”,原生类加载器加载的是“可信类”(java API类)。
    4:“java类动态加载”所有的类都是在第一次使用时动态的加载到jvm中的。因此java程序在运行时不是所有的类都被加载,只有需要的时候才被加载。
    5:类加载器首先判断这个类是否已经被加载了,如果没有被加载,寻找class文件并检查文件,然后这个类的class文件被加载到内存中用于创建类对象。
    6:如果想在运行期间使用类型信息,需要获取类的Class对象
    6.1:如果你已经有了一个目标类的对象,可以通过Object的方法getClass()获取Class对象的引用。
    6.2: 使用ClassName.class。过去该类的Class对象的引用。
    6.3: Class.forName("目标类的文本名"); 用于或去Class的引用。
    /*三种方式常用第三种,第一种对象都有了还要反射干什么。第二种需要导入类的包,依赖太强,不导包就抛编译错误。一般都第三种,一个字符串可以传入也可写在配置文件中等多种方法。*/
    package test;
            /**
             * 获取Class对象的三种方式
             * 1 Object ——> getClass();
             * 2 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
             * 3 通过Class类的静态方法:forName(String  className)(常用)
             *
             */
            public class Fanshe {
                public static void main(String[] args) {
                    //第一种方式获取Class对象
                    Student stu1 = new Student();//这一new 产生一个Student对象,一个Class对象。
                    Class stuClass = stu1.getClass();//获取Class对象
                    System.out.println(stuClass.getName());
    
                    //第二种方式获取Class对象
                    Class stuClass2 = Student.class;
                    System.out.println(stuClass == stuClass2);//判断第一种方式获取的Class对象和第二种方式获取的是否是同一个
    
                    //第三种方式获取Class对象
                    try {
                        Class stuClass3 = Class.forName("fanshe.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
                        System.out.println(stuClass3 == stuClass2);//判断三种方式是否获取的是同一个Class对象
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
    
                }
            }
    
    
    
    7:一种罕见的类型转换:
    Class F{}
    Class S extends F{}
    F f = new S();
    Class<S> sType = S.class();
    S s = sType.cast(f);
    8: 判断对象类型的两种方法:
    1:类名称.class.isInstance(对象);
    2:对象.instancof 类名称。
    9:如果不知道某个对象的确切类型,RTTI可以告诉你,但是有个前提:这个类型在编译时必须以知。
    10:反射的面纱:
    当通过反射与某个类型的对象打交道时:jvm会检查这个对象,看它属于哪个类。
    使用对象之前需要加载Class对象(通过网络、或者别的方式,但必须能找到Class文件)。
    11:JAVA反射机制是在运行状态中,
      对于任意一个类,都能够知道这个类的所有属性和方法
      对于任意一个对象,都能够调用它的任意一个方法和属性
      这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
      要想解剖一个类,必须先要获取到该类的字节码文件对象。
      而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

    12:“远程方法调用(RMI)”在跨网络的平台创建和运行对象。通过运行时获取类型可以实现RMI。
    13:java里的class文件加载分为两种情况
    1:第一种就是类型是编译器已知的,这种文件的.class文件在编译的时候,编译器会把.class文件打开检查,但是注意不是加载,用的时候才加载。(RTTI
    2:第二种就是我们可能是从别的地方获取到了一个引用,然后动态的把这个未知类型的引用的对象的.class文件加载进jvm虚拟机里。(反射
    14:反射API举例:
    import java.lang.reflect.*;
    public class Main {
        public static void main(String[] args) throws Exception{
            //返回A的构造方法
            Constructor c = A.class.getConstructor();
            //返回A类的所有为public 声明的构造方法
            Constructor[] cons = A.class.getConstructors();
            //返回A类所有的构造方法,包括private
            Constructor[] cons2 = A.class.getDeclaredConstructors();
            //返回A类的第一个public 方法
            Method m = A.class.getMethod("say");
            //执行
            m.invoke(A.class.newInstance(), null);
            //返回A类所有的public 方法
            Method[] ms = A.class.getMethods();
            //返回A类所有的方法,包括private
            Method[] allMs = A.class.getDeclaredMethods();
            //返回A类的public字段
            Field field = A.class.getField("i");
            System.out.println(field.get(A.class.newInstance()));
            //返回A类的static 字段
            System.out.println(field.get(null));
        }
    }
    class A{
        public int i = 1;
        public static int b = 2;
        public A(){
            System.out.println("无参构造");
        }
        private A(String s){
            System.out.println("有参构造"+s);
        }
    
        public void say(){
            System.out.println("say");
        }
    }

     关于反射的资料:

    1 反射的概述

    1.1 什么是反射

    每个.class文件被加载到内存后都是一个Class类的对象!例如Demo.class加载到内存后它是Class<Demo>类型的一个对象。

    反射就是通过Class对象获取类型相关的信息。一个Class对象就表示一个.class文件,可以通过Class对象获取这个类的构造器、方法,以及成员变量等。

    反射是Java的高级特性,在框架中大量被使用!我们必须要了解反射,不然无法学好JavaWeb相关的知识!

    1.2 反射相关类

    与反射相关的类:

    l  Class:表示类;

    l  Field:表示成员变量;

    l  Method:表示方法;

    l  Constructor:表示构造器。

    [c1] 

    2 Class类

    2.1 获取Class类

    获取Class类的三种[c2] 基本方式:

    l  通过类名称.class,对基本类型也支持;

    • Class c = int.class;
    • Class c = int[].class;
    • Class c = String.class

    l  通过对象.getClass()方法

    • Class c = obj.getClass();

    l  Class.forName()通过类名称加载类,这种方法只要有类名称就可以得到Class;

    • Class c = Class.forName(“cn.itcast.Demo”);

    2.2 Class类的常用方法

    l  String getName():获取类名称,包含包名;

    l  String getSimpleName():获取类名称,不包含包名;

    l  Class getSupperClass():获取父类的Class,例如:new Integer(100).getClass().getSupperClass()返回的是Class<Number>!但new Object().getSupperClass()返回的是null,因为Object没有父类;

    l  T newInstance():使用本类无参构造器来创建本类对象;

    l  boolean isArray():是否为数组类型;

    l  boolean isAnnotation():是否为注解类型;

    l  boolean isAnnotationPresent(Class annotationClass):当前类是否被annotationClass注解了;

    l  boolean isEnum():是否为枚举类型;

    l  boolean isInterface():是否为接口类型;

    l  boolean isPrimitive():是否为基本类型;

    l  boolean isSynthetic():是否为引用类型;

    2.3 通过反射创建对象

    public class Demo1 {

        @Test

        public void fun1() throws Exception {

           String className = "cn.itcast.User";

           Class clazz = Class.forName(className);

           User user = (User)clazz.newInstance();

           System.out.println(user);

        }

    }

     

    class User {

        private String username;

        private String password;

     

        public String getUsername() {

           return username;

        }

     

        public void setUsername(String username) {

           this.username = username;

        }

     

        public String getPassword() {

           return password;

        }

     

        public void setPassword(String password) {

           this.password = password;

        }

     

        @Override

        public String toString() {

           return "User [username=" + username + ", password=" + password + "]";

        }

    }

    User [username=null, password=null]

    3 Constructor[c3] 

    Constructor表示一个类的构造器。即构造器的反射对象!

    3.1 获取Constructor对象

      获取Construcator对象需要使用Class对象,下面API来自Class类:

    l  Constructor getConstructor(Class… parameterTypes):通过指定的参数类型获取公有构造器反射对象;

    l  Constructor[] getConstructors():获取所有公有构造器对象;

    l  Constructor getDeclaredConstructor(Class… parameterTypes):通过指定参数类型获取构造器反射对象。可以是私有构造器对象;

    l  Constructor[] getDeclaredConstructors():获取所有构造器对象。包含私有构造器;

    3.2 Construcator类常用方法

    l  String getName():获取构造器名;

    l  Class getDeclaringClass():获取构造器所属的类型;

    l  Class[] getParameterTypes():获取构造器的所有参数的类型;

    l  Class[] getExceptionTypes():获取构造器上声明的所有异常类型;

    l  T newInstance(Object… initargs):通过构造器反射对象调用构造器。

    3.3 练习:通过Construcator创建对象

    User.java

    public class User {

        private String username;

        private String password;

     

        public User() {

        }

     

        public User(String username, String password) {

           this.username = username;

           this.password = password;

        }

     

        public String getUsername() {

           return username;

        }

     

        public void setUsername(String username) {

           this.username = username;

        }

     

        public String getPassword() {

           return password;

        }

     

        public void setPassword(String password) {

           this.password = password;

        }

     

        @Override

        public String toString() {

           return "User [username=" + username + ", password=" + password + "]";

        }

    }

    Demo1.java

    public class Demo1 {

        @Test

        public void fun1() throws Exception {

           String className = "cn.itcast.User";

           Class clazz = Class.forName(className);

           Constructor c = clazz.getConstructor(String.class, String.class);[崔4] 

           User user = (User)c.newInstance("zhangSan", "123");[崔5] 

           System.out.println(user);

        }

    }

    4 Method(类的组成部分)

    Class à 类的反射对象

    Constructor à 构造器的反射对象

    Method表示方法的反射对象

    Field à 成员的反射对象

    4.1 获取Method

    获取Method需要通过Class对象,下面是Class类的API:

    l  Method getMethod(String name, Class… parameterTypes):通过方法名和方法参数类型获取方法反射对象,包含父类中声明的公有方法,但不包含所有私有方法;

    l  Method[] getMethods():获取所有公有方法,包含父类中的公有方法,但不包含任何私有方法;

    l  Method getDeclaredMethod(String name, Class… parameterTypes):通过方法名和方法参数类型获取本类中声明的方法的反射对象,包含本类中的私有方法,但不包含父类中的任何方法;

    l  Method[] getDeclaredMethods():获取本类中所有方法,包含本类中的私有方法,但不包含父类中的任何方法。

    4.2 Method常用方法

    l  String getName():获取方法名;

    l  Class getDeclaringClass():获取方法所属的类型;

    l  Class[] getParameterTypes():获取方法的所有参数的类型;

    l  Class[] getExceptionTypes():获取方法上声明的所有异常类型;

    l  Class getReturnType():获取方法的返回值类型;

    l  Object invode(Object obj, Object… args):通过方法反射对象调用方法,如果当前方法是实例方法,那么当前对象就是obj,如果当前方法是static方法,那么可以给obj传递null。args表示是方法的参数;

    4.3 练习:通过Method调用方法

      

    public class Demo1 {

        @Test

        public void fun1() throws Exception {

           String className = "cn.itcast.User";

           Class clazz = Class.forName(className);

           Constructor c = clazz.getConstructor(String.class, String.class);

           User user = (User)c.newInstance("zhangSan", "123");

          

           Method method = clazz.getMethod("toString");[崔6] 

           String result = (String)method.invoke(user);[崔7] 

           System.out.println(result);[崔8] 

        }

    }

    5 Field

      Field表示类的成员变量,可以是实例变量,也可以是静态变量。

    5.1 获取Field对象

    获取Field对象需要使用Class对象,下面是Class类的API:

    l  Field getField(String name):通过名字获取公有成员变量的反射对象,包含父类中声明的公有成员变量;

    l  Field[] getFields():获取所有公有成员变量反射对象,包含父类中声明的公有成员变量;

    l  Field getDeclaredField(String name):通过名字获取本类中某个成员变量,包含本类的private成员变量,但父类中声明的任何成员变量都不包含;

    l  Field[] getDeclaredFields():获取本类中声明的所有成员变量,包含private成员变量,但不包含父类中声明的任何成员变量;

    5.2 Field类的常用方法

    l  String getName():获取成员变量名;

    l  Class getDeclaringClass():获取成员变量的类型;

    l  Class getType():获取当前成员变量的类型;

    l  Object get(Object obj):获取obj对象的成员变量的值;

    l  void set(Object obj, Object value):设置obj对象的成员变量值为value;

    5.3 练习:通过Field读写成员

    User.java

    public class User {

        public String username;

        public String password;

     

        public User() {

        }

     

        public User(String username, String password) {

           this.username = username;

           this.password = password;

        }

     

        public String getUsername() {

            return username;

        }

     

        public void setUsername(String username) {

           this.username = username;

        }

     

        public String getPassword() {

           return password;

        }

     

        public void setPassword(String password) {

           this.password = password;

        }

     

        @Override

        public String toString() {

           return "User [username=" + username + ", password=" + password + "]";

        }

    }

    Demo1.java

    public class Demo1 {

        @Test

        public void fun1() throws Exception {

           String className = "cn.itcast.User";

           Class clazz = Class.forName(className);

           User user = new User("zhangSan", "123");

          

           Field field1 = clazz.getField("username");[崔9] 

           Field field2 = clazz.getField("password")[崔10] ;

          

           String username = (String)field1.get(user);[崔11] 

           String password = (String)field2.get(user);[崔12] 

          

           System.out.println(username + ", " + password);

          

           field1.set(user, "liSi");[崔13] 

           field2.set(user, "456");[崔14] 

          

           System.out.println(user);

        }

    }

    6  AccessibleObject

    AccessibleObject类是Constructor、Method、Field三个类的父类。AccessibleObject最为重要的方法如下:

    l  boolean isAccessible():判断当前成员是否可访问;

    l  void setAccessible[c15] (boolean flag):设置当前成员是否可访问。

    当Constructor、Method、Field为私有时,如果我们想反射操作,那么就必须先调用反射对象的setAccessible(true)方法,然后才能操作。

    User.java

    public class User {

        private String username;

        private String password;

     

        public User() {

        }

     

        public User(String username, String password) {

           this.username = username;

           this.password = password;

        }

     

        public String getUsername() {

           return username;

        }

     

        public void setUsername(String username) {

           this.username = username;

        }

     

        public String getPassword() {

           return password;

        }

     

        public void setPassword(String password) {

           this.password = password;

        }

     

        @Override

        public String toString() {

           return "User [username=" + username + ", password=" + password + "]";

        }

    }

    注意,User类的username和password成员变量为private的,这时再通过Field来反射操作这两个成员变量就必须先通过setAccessible(true)设置后才行。

    public class Demo1 {

        @Test

        public void fun1() throws Exception {

           String className = "cn.itcast.User";

           Class clazz = Class.forName(className);

           User user = new User("zhangSan", "123");

          

           Field field1 = clazz.getDeclaredField("username");

           Field field2 = clazz.getDeclaredField("password");

    [崔16]      

           field1.setAccessible(true);

           field2.setAccessible(true);

    [崔17]      

           String username = (String)field1.get(user);

           String password = (String)field2.get(user);

          

            System.out.println(username + ", " + password);

          

           field1.set(user, "liSi");

           field2.set(user, "456");

          

           System.out.println(user);

        }

    }


     [c1]与反射相关的类们,它们都不能new!!!

     [c2]

    l  类名.class

    l  对象.getClass()

    l  Class.forName(“字符串:类名”)

     [c3]它是Class的一个组成部门,所以需要先得到Class,再通过Class的方法得到Constructor

     [崔4]通过参数类型来获取构造器,即获取两个String类型参数的构造器反射对象。

     [崔5]通过构造器反射对象来调用构造器,并传递参数给构造器

     [崔6]获取名为toString,没有参数的方法

     [崔7]反射调用这个方法,给this赋值为user,没有传递参数,因为这个方法没有参数。

     [崔8]打印返回值。

     [崔9]获取名为username的成员变量

     [崔10]获取名为password的成员变量

     [崔11]获取user对象的username成员变量值,因为field1表示的就是username成员变量

     [崔12]获取user对象的password成员变量值,因为field2表示的就是password成员变量

     [崔13]设置user对象的username成员变量值为liSi

     [崔14]设置user对象的password成员变量值为456

     [c15]当设置该参数为true时,那么private的成员、方法、构造器就都可以操作了。

     [崔16]因为username和password都是私有的成员变量,所以需要使用getDeclaredField()才能获取到。

     [崔17]设置成员变量是可以访问的,对于私有变量、方法、构造器都必须先调用这个方法后才能操作,不然会抛出异常。

  • 相关阅读:
    入门activiti-------1简单运行
    JS对象、构造器函数和原型对象之间的关系
    myeclipse配背景色
    maven的pom.xml文件错误
    oracleXE简易版---使用基础
    ognl表达式注意事项
    Executors、ExecutorService、ThreadPoolExecutor
    ThreadPoolExecutor
    Phaser相位(工具的实战案例使用)
    ForkJoin
  • 原文地址:https://www.cnblogs.com/Xmingzi/p/8662872.html
Copyright © 2011-2022 走看看