class对象_class对象存在jvm哪个区 - CSDN
精华内容
参与话题
  • Class类是我们再熟悉不过的东西,但是对于Class对象,很多人却是一脸懵逼。 Class对象到底是什么呢?今天我们就来深入了解一下它。 1.RTTI的概念 RTTI(Run-Time Type Identification),即运行时类型识别,这...

    Class类是我们再熟悉不过的东西,但是对于Class对象,很多人却是一脸懵逼。

    Class对象到底是什么呢?今天我们就来深入了解一下它。

    1.RTTI的概念

    RTTI(Run-Time Type Identification),即运行时类型识别,这个词一直是 C++ 中的概念,至于Java中出现RRTI的说法则是源于《Thinking in Java》一书,其作用是在运行时识别一个对象的类型和类的信息。

    RTTI分两种:传统的”RTTI”与反射机制。

    对于传统的“RTTI”,它假定我们在编译期已知道了所有类型(在没有反射机制创建和使用类对象时,一般都是编译期已确定其类型,如new对象时该类必须已定义好)。

    另外一种是反射机制,它允许我们在运行时发现和使用类型的信息。在Java中用来表示运行时类型信息的对应类就是Class类。


    2.Class类

    Class类也是一个实实在在的类,存在于JDK的java.lang包中,其部分源码如下:

    public final class Class<T> implements java.io.Serializable,GenericDeclaration,Type, AnnotatedElement {
        private static final int ANNOTATION= 0x00002000;
        private static final int ENUM      = 0x00004000;
        private static final int SYNTHETIC = 0x00001000;
    
        private static native void registerNatives();
        static {
            registerNatives();
        }
    
        /*
         * Private constructor. Only the Java Virtual Machine creates Class objects.(私有构造,只能由JVM创建该类)
         * This constructor is not used and prevents the default constructor being
         * generated.
         */
        private Class(ClassLoader loader) {
            // Initialize final field for classLoader.  The initialization value of non-null
            // prevents future JIT optimizations from assuming this final field is null.
            classLoader = loader;
        }
    

    对象是类的实例化,那么既然Class类是真实存在,那么自然也可以被实例化。而Class的创建的实例就是Class对象。

    3.Class对象

    上文说到Class类被创建后的对象就是Class对象,这里需要注意,Class对象表示的是自己手动编写类的类型信息。

    这是什么意思呢?比如创建一个Searchin类,那么,JVM就会创建一个Searchin对应Class类的Class对象,该Class对象则保存了Searchin类相关的类型信息。

    实际上在Java中每个类都有且只有一个Class对象。

    每当我们编写并且编译一个新创建的类就会产生一个对应Class对象并且这个Class对象会被保存在同名.class文件里。说到.class文件,大家可能很熟悉,因为Java程序编译之后就会有.class文件。事实上,编译后的字节码文件保存的就是Class对象。

    那为什么需要这样一个Class对象呢?

    是这样的,当我们new一个新对象或者引用静态成员变量时,Java虚拟机(JVM)中的类加载器子系统会将对应Class对象加载到JVM中,然后JVM再根据这个类型信息相关的Class对象创建我们需要实例对象或者提供静态变量的引用值。也就是说,Class对象对于类的实例化具有非常重要的意义。没它就没法new新对象和引用静态成员变量。

    这里需要再次重点提醒一下,上文说到“Java中每个类只有一个Class对象”,这句话是什么意思呢?

    对于手动编写的每个Class类,无论创建多少个实例对象,在JVM中都只有一个Class对象,即在内存中每个类有且只有一个相对应的Class对象。

    这里给大家画个简单的图,方便大家理解。

    4.总结

    通过上文所提及知识,我们可以得出以下几点信息:

    • Class类也是类的一种,与class关键字是不一样的。
    • 手动编写的类被编译后会产生一个Class对象,其表示的是创建的类的类型信息,该Class对象保存在同名.class的文件中(即编译后得到的字节码文件)。
    • 每个通过关键字class标识的类,在内存中有且只有一个与之对应的Class对象来描述其类型信息,无论创建多少个实例对象,其依据的都是用一个Class对象。
    • Class类只存私有构造函数,因此对应Class对象只能有JVM创建和加载
    • Class类的对象的作用是运行时提供或获得某个对象的类型信息,这点对于反射技术很重要。

     

     

     

     

    Biu~~~~~~~~~~~~~~~~~~~~宫å´éªé¾ç«è¡¨æå|é¾ç«gifå¾è¡¨æåä¸è½½å¾ç~~~~~~~~~~~~~~~~~~~~~~pia!

    参考文章:https://blog.csdn.net/javazejian/article/details/70768369

    展开全文
  • Java Class对象简介

    2018-07-28 16:45:12
    一. 反射机制概念  主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。在java中,只要给定类的名字, 那么就可以通过...

    一. 反射机制概念

      主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息。

      反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!

      类中有什么信息,利用反射机制就能可以获得什么信息,不过前提是得知道类的名字。

    二. 反射机制的作用

    1. 在运行时判断任意一个对象所属的类;
    2. 在运行时获取类的对象;
    3. 在运行时访问java对象的属性,方法,构造方法等。

    三. 反射机制的优点与缺点

    首先要搞清楚为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念。 
    静态编译:在编译时确定类型,绑定对象,即通过。 
    动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。 

    反射机制的优点:可以实现动态创建对象和编译,体现出很大的灵活性(特别是在J2EE的开发中它的灵活性就表现的十分明显)。通过反射机制我们可以获得类的各种内容,进行了反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。

      比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。 

    反射机制的缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它 满足我们的要求。这类操作总是慢于只直接执行相同的操作。

    四. 反射机制的示例

    1.通过一个对象获得完整的包名和类名

    添加一句:所有类的对象其实都是Class的实例。

    package Reflect;

    class Demo{
        //other codes...
    }

    class hello{
        public static void main(String[] args) {
            Demo demo=new Demo();
            System.out.println(demo.getClass().getName());
        }
    }
    //【运行结果】:Reflect.Demo

     

    2.实例化Class类对象

     

    package Reflect;

    class Demo{

        //other codes...

    }

    class hello{

        public static void main(String[] args) {

            Class<?> demo1=null;

            Class<?> demo2=null;

            Class<?> demo3=null;

            try{

                //一般尽量采用这种形式

                demo1=Class.forName("Reflect.Demo");

            }catch(Exception e){

                e.printStackTrace();

            }

            demo2=new Demo().getClass();

            demo3=Demo.class;

            System.out.println("类名称   "+demo1.getName());

            System.out.println("类名称   "+demo2.getName());

            System.out.println("类名称   "+demo3.getName());

        }

    }

    //【运行结果】:

    //类名称   Reflect.Demo

    //类名称   Reflect.Demo

    //类名称   Reflect.Demo

    3.通过Class实例化其他类的对象

     

    package Reflect;
    
    class Person{
    
        private String name;
        private int age;
    
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        @Override
        public String toString(){
            return "["+this.name+"  "+this.age+"]";
        }
        
    }
    
    class hello{
        public static void main(String[] args) {
            Class<?> demo=null;
            try{
                demo=Class.forName("Reflect.Person");
            }catch (Exception e) {
                e.printStackTrace();
            }
            Person per=null;
            try {
                per=(Person)demo.newInstance();
            } catch (InstantiationException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            per.setName("Rollen");
            per.setAge(20);
            System.out.println(per);
        }
    }
    //【运行结果】:
    //[Rollen  20]

    但是注意一下,当我们把Person中的默认的无参构造函数取消的时候,比如自己定义只定义一个有参数的构造函数之后,会出现错误:

    比如定义了一个构造函数:

    public Person(String name, int age) {
             this.age=age;
             this.name=name;
         }

    然后继续运行上面的程序,会出现:

     

    java.lang.InstantiationException: Reflect.Person
    at java.lang.Class.newInstance0(Class.java:340)
    at java.lang.Class.newInstance(Class.java:308)
    at Reflect.hello.main(hello.java:39)
    Exception in thread "main" java.lang.NullPointerException
    at Reflect.hello.main(hello.java:47)

    用newInstance与用new是区别的,区别在于创建对象的方式不一样,前者是使用类加载机制,那么为什么会有两种创建对象方式?这个就要从可伸缩、可扩展,可重用等软件思想上解释了。Java中工厂模式经常使用newInstance来创建对象,因此从为什么要使用工厂模式上也可以找到具体答案。
    例如:
    Class c = Class.forName(“A”);
    factory = (AInterface)c.newInstance();
    其中AInterface是A的接口,如果下面这样写,你可能会理解:
    String className = “A”;
    Class c = Class.forName(className);
    factory = (AInterface)c.newInstance();
    进一步,如果下面写,你可能会理解:
    String className = readfromXMlConfig;//从xml 配置文件中获得字符串
    Class c = Class.forName(className);factory = (AInterface)c.newInstance();
    上面代码就消灭了A类名称,优点:无论A类怎么变化,上述代码不变,甚至可以更换A的兄弟类B , C , D….等,只要他们继承Ainterface就可以。
    从jvm的角度看,我们使用new的时候,这个要new的类可以没有加载;
    但是使用newInstance时候,就必须保证:1、这个类已经加载;2、这个类已经连接了。而完成上面两个步骤的正是class的静态方法forName()方法,这个静态方法调用了启动类加载器(就是加载javaAPI的那个加载器)。
    有了上面jvm上的理解,那么我们可以这样说,newInstance实际上是把new这个方式分解为两步,即,首先调用class的加载方法加载某个类,然后实例化。
    这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了我们降耦的手段。
    
    [补充:]
    newInstance: 弱类型。低效率。只能调用无参构造。
    new: 强类型。相对高效。能调用任何public构造。
    newInstance()是实现IOC、反射、依赖倒置 等技术方法的必然选择,new 只能实现具体类的实例化,不适合于接口编程。类里面就是通过这个类的默认构造函数构建了一个对象,如果没有默认构造函数就抛出InstantiationException, 如果没有访问默认构造函数的权限就抛出IllegalAccessException

    所以大家以后再编写使用Class实例化其他类的对象的时候,一定要自己定义无参的构造函数。

    4.通过Class调用其他类中的构造函数 (也可以通过这种方式通过Class创建其他类的对象)

    package Reflect;

    import java.lang.reflect.Constructor;

    class Person{
        public Person() {   

        }
        public Person(String name){
            this.name=name;
        }
        public Person(int age){
            this.age=age;
        }
        public Person(String name, int age) {
            this.age=age;
            this.name=name;
        }
        public String getName() {
            return name;
        }
        public int getAge() {
            return age;
        }
        @Override
        public String toString(){
            return "["+this.name+"  "+this.age+"]";
        }
        private String name;
        private int age;
    }

    class hello{
        public static void main(String[] args) {
            Class<?> demo=null;
            try{
                demo=Class.forName("Reflect.Person");
            }catch (Exception e) {
                e.printStackTrace();
            }
            Person per1=null;
            Person per2=null;
            Person per3=null;
            Person per4=null;
            //取得全部的构造函数
            Constructor<?> cons[]=demo.getConstructors();
            try{
                per1=(Person)cons[0].newInstance();
                per2=(Person)cons[1].newInstance("Rollen");
                per3=(Person)cons[2].newInstance(20);
                per4=(Person)cons[3].newInstance("Rollen",20);
            }catch(Exception e){
                e.printStackTrace();
            }
            System.out.println(per1);
            System.out.println(per2);
            System.out.println(per3);
            System.out.println(per4);
        }
    }
    //【运行结果】:
    //[null  0]
    //[Rollen  0]
    //[null  20]
    //[Rollen  20]

     

     

    5.返回一个类实现的接口

     

     

    package Reflect;
    
    interface China{
        public static final String name="Rollen";
        public static  int age=20;
        public void sayChina();
        public void sayHello(String name, int age);
    }
    
    class Person implements China{
        public Person() {
    
        }
        public Person(String sex){
            this.sex=sex;
        }
        public String getSex() {
            return sex;
        }
        public void setSex(String sex) {
            this.sex = sex;
        }
        @Override
        public void sayChina(){
            System.out.println("hello ,china");
        }
        @Override
        public void sayHello(String name, int age){
            System.out.println(name+"  "+age);
        }
        private String sex;
    }
    
    class hello{
        public static void main(String[] args) {
            Class<?> demo=null;
            try{
                demo=Class.forName("Reflect.Person");
            }catch (Exception e) {
                e.printStackTrace();
            }
            //保存所有的接口
            Class<?> intes[]=demo.getInterfaces();
            for (int i = 0; i < intes.length; i++) {
                System.out.println("实现的接口   "+intes[i].getName());
            }
        }
    }
    //【运行结果】:
    //实现的接口   Reflect.China

    (以下几个例子,都会用到这个例子的Person类,所以为节省篇幅,此处不再粘贴Person的代码部分,只粘贴主类hello的代码)

    6.取得其他类中的父类

     

     

    class hello{
        public static void main(String[] args) {
            Class<?> demo=null;
            try{
                demo=Class.forName("Reflect.Person");
            }catch (Exception e) {
                e.printStackTrace();
            }
            //取得父类
            Class<?> temp=demo.getSuperclass();
            System.out.println("继承的父类为:   "+temp.getName());
        }
    }
    //【运行结果】
    //继承的父类为:   java.lang.Object

    7.获得其他类中的全部构造函数

    //这个例子需要在程序开头添加import java.lang.reflect.*;
    class hello{
        public static void main(String[] args) {
            Class<?> demo=null;
            try{
                demo=Class.forName("Reflect.Person");
            }catch (Exception e) {
                e.printStackTrace();
            }
            Constructor<?>cons[]=demo.getConstructors();
            for (int i = 0; i < cons.length; i++) {
                System.out.println("构造方法:  "+cons[i]);
            }
        }
    }
    //【运行结果】:
    //构造方法:  public Reflect.Person()
    //构造方法:  public Reflect.Person(java.lang.String)

     

    
     

     

    class hello{
        public static void main(String[] args) {
            Class<?> demo=null;
            try{
                demo=Class.forName("Reflect.Person");
            }catch (Exception e) {
                e.printStackTrace();
            }
            Constructor<?>cons[]=demo.getConstructors();
            for (int i = 0; i < cons.length; i++) {
                Class<?> p[]=cons[i].getParameterTypes();
                System.out.print("构造方法:  ");
                int mo=cons[i].getModifiers();
                System.out.print(Modifier.toString(mo)+" ");
                System.out.print(cons[i].getName());
                System.out.print("(");
                for(int j=0;j<p.length;++j){
                    System.out.print(p[j].getName()+" arg"+i);
                    if(j<p.length-1){
                        System.out.print(",");
                    }
                }
                System.out.println("){}");
            }
        }
    }
    //【运行结果】:
    //构造方法:  public Reflect.Person(){}
    //构造方法:  public Reflect.Person(java.lang.String arg1){}

     

     

    8.取得其他类的全部属性,将这些整理在一起,也就是通过class取得一个类的全部框架

     

     

    class hello {
        public static void main(String[] args) {
            Class<?> demo = null;
            try {
                demo = Class.forName("Reflect.Person");
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("===============本类属性========================");
            // 取得本类的全部属性
            Field[] field = demo.getDeclaredFields();
            for (int i = 0; i < field.length; i++) {
                // 权限修饰符
                int mo = field[i].getModifiers();
                String priv = Modifier.toString(mo);
                // 属性类型
                Class<?> type = field[i].getType();
                System.out.println(priv + " " + type.getName() + " "
                        + field[i].getName() + ";");
            }
            System.out.println("===============实现的接口或者父类的属性========================");
            // 取得实现的接口或者父类的属性
            Field[] filed1 = demo.getFields();
            for (int j = 0; j < filed1.length; j++) {
                // 权限修饰符
                int mo = filed1[j].getModifiers();
                String priv = Modifier.toString(mo);
                // 属性类型
                Class<?> type = filed1[j].getType();
                System.out.println(priv + " " + type.getName() + " "
                        + filed1[j].getName() + ";");
            }
        }
    }
    //【运行结果】:
    //===============本类属性========================
    //private java.lang.String sex;
    //===============实现的接口或者父类的属性========================
    //public static final java.lang.String name;
    //public static final int age;

    9.通过反射调用其他类中的方法

     

     

    class hello {
        public static void main(String[] args) {
            Class<?> demo = null;
            try {
                demo = Class.forName("Reflect.Person");
            } catch (Exception e) {
                e.printStackTrace();
            }
            try{
                //调用Person类中的sayChina方法
                Method method=demo.getMethod("sayChina");
                method.invoke(demo.newInstance());
                //调用Person的sayHello方法
                method=demo.getMethod("sayHello", String.class,int.class);
                method.invoke(demo.newInstance(),"Rollen",20);
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    //【运行结果】:
    //hello ,china
    //Rollen  20

    10.调用其他类的set和get方法

     

     

    class hello {
        public static void main(String[] args) {
            Class<?> demo = null;
            Object obj=null;
            try {
                demo = Class.forName("Reflect.Person");
            } catch (Exception e) {
                e.printStackTrace();
            }
            try{
             obj=demo.newInstance();
            }catch (Exception e) {
                e.printStackTrace();
            }
            setter(obj,"Sex","男",String.class);
            getter(obj,"Sex");
        }
    
        /**
         * @param obj   操作的对象
         * @param att   操作的属性
         * */
        public static void getter(Object obj, String att) {
            try {
                Method method = obj.getClass().getMethod("get" + att);
                System.out.println(method.invoke(obj));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * @param obj   操作的对象    
         * @param att   操作的属性
         * @param value 设置的值
         * @param type  参数的属性
         * */
        public static void setter(Object obj, String att, Object value,
                Class<?> type) {
            try {
                Method method = obj.getClass().getMethod("set" + att, type);
                method.invoke(obj, value);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }// end class
    //【运行结果】:
    //男

    11.通过反射操作属性

    class hello {
        public static void main(String[] args) throws Exception {
            Class<?> demo = null;
            Object obj = null;

            demo = Class.forName("Reflect.Person");
            obj = demo.newInstance();

            Field field = demo.getDeclaredField("sex");
            field.setAccessible(true);
            field.set(obj, "男");
            System.out.println(field.get(obj));
        }
    }// end class

     

     

    12.通过反射取得并修改数组的信息

     

     

    import java.lang.reflect.*;
    
    class hello{
        public static void main(String[] args) {
            int[] temp={1,2,3,4,5};
            Class<?>demo=temp.getClass().getComponentType();
            System.out.println("数组类型: "+demo.getName());
            System.out.println("数组长度  "+Array.getLength(temp));
            System.out.println("数组的第一个元素: "+Array.get(temp, 0));
            Array.set(temp, 0, 100);
            System.out.println("修改之后数组第一个元素为: "+Array.get(temp, 0));
        }
    }
    //【运行结果】:
    //数组类型: int
    //数组长度  5
    //数组的第一个元素: 1
    //修改之后数组第一个元素为: 100

    13.通过反射修改数组大小

    class hello{
        public static void main(String[] args) {
            int[] temp={1,2,3,4,5,6,7,8,9};
            int[] newTemp=(int[])arrayInc(temp,15);
            print(newTemp);
            System.out.println("=====================");
            String[] atr={"a","b","c"};
            String[] str1=(String[])arrayInc(atr,8);
            print(str1);
        }
        /**
         * 修改数组大小
         * */
        public static Object arrayInc(Object obj,int len){
            Class<?>arr=obj.getClass().getComponentType();
            Object newArr=Array.newInstance(arr, len);
            int co=Array.getLength(obj);
            System.arraycopy(obj, 0, newArr, 0, co);
            return newArr;
        }
        /**
         * 打印
         * */
        public static void print(Object obj){
            Class<?>c=obj.getClass();
            if(!c.isArray()){
                return;
            }
            System.out.println("数组长度为: "+Array.getLength(obj));
            for (int i = 0; i < Array.getLength(obj); i++) {
                System.out.print(Array.get(obj, i)+" ");
            }
        }
    }
    //【运行结果】:
    //数组长度为: 15
    //1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 =====================
    //数组长度为: 8
    //a b c null null null null null

     

     

    14.动态代理

    首先来看看如何获得类加载器:

     

     

    class test{
    
    }
    class hello{
        public static void main(String[] args) {
            test t=new test();
            System.out.println("类加载器  "+t.getClass().getClassLoader().getClass().getName());
        }
    }
    //【程序输出】:
    //类加载器  sun.misc.Launcher$AppClassLoader

    其实在java中有三种类类加载器。

    1)Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。

    2)Extension ClassLoader 用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类

    3)AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。

    如果想要完成动态代理,首先需要定义一个InvocationHandler接口的子类,已完成代理的具体操作。

     

     

    package Reflect;

    import java.lang.reflect.*;

    //定义项目接口
    interface Subject {
        public String say(String name, int age);
    }

    // 定义真实项目
    class RealSubject implements Subject {
        @Override
        public String say(String name, int age) {
            return name + "  " + age;
        }
    }

    class MyInvocationHandler implements InvocationHandler {
        private Object obj = null;

        public Object bind(Object obj) {
            this.obj = obj;
            return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
                    .getClass().getInterfaces(), this);
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            Object temp = method.invoke(this.obj, args);
            return temp;
        }
    }

    class hello {
        public static void main(String[] args) {
            MyInvocationHandler demo = new MyInvocationHandler();
            Subject sub = (Subject) demo.bind(new RealSubject());
            String info = sub.say("Rollen", 20);
            System.out.println(info);
        }
    }
    //【运行结果】:
    //Rollen  20

    类的生命周期

      在一个类编译完成之后,下一步就需要开始使用类,如果要使用一个类,肯定离不开JVM。在程序执行中JVM通过装载,链接,初始化这3个步骤完成。

      类的装载是通过类加载器完成的,加载器将.class文件的二进制文件装入JVM的方法区,并且在堆区创建描述这个类的java.lang.Class对象。用来封装数据。 但是同一个类只会被类装载器装载以前

    链接就是把二进制数据组装为可以运行的状态。

    链接分为校验,准备,解析这3个阶段:

    校验一般用来确认此二进制文件是否适合当前的JVM(版本),

    准备就是为静态成员分配内存空间,。并设置默认值

    解析指的是转换常量池中的代码作为直接引用的过程,直到所有的符号引用都可以被运行程序使用(建立完整的对应关系)。

      完成之后,类型也就完成了初始化,初始化之后类的对象就可以正常使用了,直到一个对象不再使用之后,将被垃圾回收。释放空间。当没有任何引用指向Class对象时就会被卸载,结束类的生命周期。

    五. IoC原理

    Spring中的IoC的实现原理就是工厂模式加反射机制。

    1.我们首先看一下不用反射机制时的工厂模式:

     

    /**
     * 工厂模式
     */
    interface fruit{
        public abstract void eat();
    }
    
    class Apple implements fruit{
        public void eat(){
            System.out.println("Apple");
        }
    }
    
    class Orange implements fruit{
        public void eat(){
            System.out.println("Orange");
        }
    }
    // 构造工厂类
    // 也就是说以后如果我们在添加其他的实例的时候只需要修改工厂类就行了
    class Factory{
        public static fruit getInstance(String fruitName){
            fruit f=null;
            if("Apple".equals(fruitName)){
                f=new Apple();
            }
            if("Orange".equals(fruitName)){
                f=new Orange();
            }
            return f;
        }
    }
    
    class hello{
        public static void main(String[] a){
            fruit f=Factory.getInstance("Orange");
            f.eat();
        }
    }

    当我们在添加一个子类的时候,就需要修改工厂类了。如果我们添加太多的子类的时候,改的就会很多。

    2. 利用反射机制的工厂模式:

     

    package Reflect;
    
    interface fruit{
        public abstract void eat();
    }
    
    class Apple implements fruit{
        public void eat(){
            System.out.println("Apple");
        }
    }
    
    class Orange implements fruit{
        public void eat(){
            System.out.println("Orange");
        }
    }
    
    class Factory{
        public static fruit getInstance(String ClassName){
            fruit f=null;
            try{
                f=(fruit)Class.forName(ClassName).newInstance();
            }catch (Exception e) {
                e.printStackTrace();
            }
            return f;
        }
    }
    
    class hello{
        public static void main(String[] a){
            fruit f=Factory.getInstance("Reflect.Apple");
            if(f!=null){
                f.eat();
            }
        }
    }

      现在就算我们添加任意多个子类的时候,工厂类就不需要修改。

      使用反射机制的工厂模式可以通过反射取得接口的实例,但是需要传入完整的包和类名。而且用户也无法知道一个接口有多少个可以使用的子类,所以我们通过属性文件的形式配置所需要的子类。

    3.使用反射机制并结合属性文件的工厂模式(即IoC)

    首先创建一个fruit.properties的资源文件:

    1 apple=Reflect.Apple
    2 orange=Reflect.Orange

    然后编写主类代码:

    package Reflect;

    import java.io.*;
    import java.util.*;

    interface fruit{
        public abstract void eat();
    }

    class Apple implements fruit{
        public void eat(){
            System.out.println("Apple");
        }
    }

    class Orange implements fruit{
        public void eat(){
            System.out.println("Orange");
        }
    }
    //操作属性文件类
    class init{
        public static Properties getPro() throws FileNotFoundException, IOException{
            Properties pro=new Properties();
            File f=new File("fruit.properties");
            if(f.exists()){
                pro.load(new FileInputStream(f));
            }else{
                pro.setProperty("apple", "Reflect.Apple");
                pro.setProperty("orange", "Reflect.Orange");
                pro.store(new FileOutputStream(f), "FRUIT CLASS");
            }
            return pro;
        }
    }

    class Factory{
        public static fruit getInstance(String ClassName){
            fruit f=null;
            try{
                f=(fruit)Class.forName(ClassName).newInstance();
            }catch (Exception e) {
                e.printStackTrace();
            }
            return f;
        }
    }

    class hello{
        public static void main(String[] a) throws FileNotFoundException, IOException{
            Properties pro=init.getPro();
            fruit f=Factory.getInstance(pro.getProperty("apple"));
            if(f!=null){
                f.eat();
            }
        }
    }
    //【运行结果】:Apple

    
     
    展开全文
  • Class对象

    2020-10-18 00:06:07
    Class对象 每个类都有一个Class对象,被保存在同名.class文件中,用来创建对象。 有三种方法可取的对Class对象的引用 forName(): 是Class类的static方法,为产生目标类Class对象的引用 .class: int.class ...

    Class对象

    每个类都有一个Class对象,被保存在同名.class文件中,用来创建对象。

    Class对象的创建

    有两种方法可获取对Class对象的引用

    1. public static Class<?> forName(String className) 是Class类的static方法,为产生目标类Class对象的引用
    2. class: int.class

    Class对象的初始化以及初始化延迟

    1. 加载,CLASSPATH查找字节码,并从字节码中创建Class对象
    2. 链接,验证类的字节码,为静态域分配存储空间。
    3. 初始化,初始化静态块。初始化通常被延迟到静态方法或非常数静态域的首次引用。

    示例程序

    有三点需注意:一是,由Class.forName()取得Class引用时自动进行了初始化,而用.class方法取得Class引用时,并未进行初始化;二是,对编译期常量(static final且赋常值的域)的引用不会导致初始化(static final int StaticFinal2=rand.nextInt()并不是);三是,Class.forName()需要异常检查,.class不需要。
    程序中的静态块static { ); }用来检测初始化,因为不可能取得对他们的引用,但当Class对象初始化时会初始化此static块。

    class Initiation1{
        static final int staticFinal=1;
        static final Random rand=new Random(10);
        static final int StaticFinal2=rand.nextInt();
        static {
            System.out.println("初始化1");
        }
    }
    class Initiation2{
        static int staticNonFinal=1;
        static{
            System.out.println("初始化2");
        }
    }
    class Initiation3{
        static {
            System.out.println("初始化3");
        }
    }
    class InitialtionTest{
        public static void main(String[] args) {
            int ref;
            //Initiation1
            Class initiation1=Initiation1.class;
            ref=Initiation1.staticFinal;
            ref=Initiation1.StaticFinal2;   //初始化1
    
            //Initiation2
            ref=Initiation2.staticNonFinal;  //初始化2
    
            //Initiation3
            try {
                Class initiation3 = Class.forName("Classtest.Initiation3");  //初始化3
            }catch(ClassNotFoundException e){
                System.out.println("ClassNotFoundException");
            }
        }
    }
    

    动态加载

    Java采用动态加载,各部分只有在必需时才会加载,当程序创建第一个对类静态成员的引用就会加载这个类的.class对象。创建类对象时,会首先检查这个类的Class对象是否已加载,若尚未加载,就根据类名查找.class文件,加载并验证字节码是否被破坏。一旦Class对象被载入内存,就被用来创建这个类的对象。
    Class对象仅在需要时被加载,static初始化在类加载时进行(这也是为什么只初始化一次)

    class Classdemo1{
        static {
            System.out.println("Classdemo1");
        }
    }
    
    class Classdemo2{
        static {
            System.out.println("Classdemo2");
        }
    }
    
    public class Classtest {
        public static void main(String[] args) {
            new Classdemo1();
    
            try{
                Class.forName("Classtest.Classdemo2");
            }catch (ClassNotFoundException e){
                System.out.println("Not found!");
            }
        }
    }
    //output:
    //Classdemo1
    //Classdemo2
    

    Class对象的作用

    • 表示运行时类型信息
    • 帮助执行RTTI以及反射
    • 创建类的常规对象

    运行时类型信息
    Class对象是RTTI与反射的重要组成部分,通过提供运行时信息支持RTTI与反射。
    获取Class引用的常用方法有Class.forName()和根类Object中的getClass()方法。
    示例程序第一部分战展示了Class类常用方法。
    第二部分使用向上转型,虽然Base类转型为Object obj,但是通过Object的obj.getClass()方法,仍然可以得到其确切类型,也就是说通过Class我们可以得知运行时的类型信息。有一点需注意,Class base在编译期也不知道其确切类型,但是可以通过base.newInstance()方法获得其实例。

    interface A{}
    interface B{}
    interface C{}
    class Base{}
    class Derived extends Base implements A,B,C{}
    
    public class Classtest {
        public static void printInfo(Class c){
            System.out.println("getName(): "+c.getName());
            System.out.println("isInterface(): "+c.isInterface());
            System.out.println("getSimpleName(): "+c.getSimpleName());
            System.out.println("getCanonicalName(): "+c.getCanonicalName());
            System.out.println("getInterface(): ");
            for(Class iface:c.getInterfaces())
                System.out.print(iface.getSimpleName()+" "+iface.isInterface()+" ");
            System.out.println();
        }
        public static void main(String[] args) {
            //第一部分
            Class c=null;
            try {
                c=Class.forName("Classtest.Derived");
            }catch (ClassNotFoundException e){
                System.out.println("Not found");
            }
            printInfo(c);
    
            //第二部分
            Class base=c.getSuperclass();
            Object obj=null;
            try{
                obj=base.newInstance();
            }catch (InstantiationException e){
                System.out.println("InstantiationException");
            }catch (IllegalAccessException e){
                System.out.println("IllegalAccessException");
            }
            System.out.println(obj.getClass().getSimpleName());
        }
    }
    //output:
    //getName(): Classtest.Derived
    //isInterface(): false
    //getSimpleName(): Derived
    //getCanonicalName(): Classtest.Derived
    //getInterface():
    //A true B true C true
    //getSuperclass(): Base
    //Base
    

    Class与泛型的组合

    Class对象的泛型不能向上转型,这个和不能把Interger的List赋值给Number的List一个道理。

    Class <Number>genericClass=Integer.class;  //Error!
    Class<? extends Number>genericClass=int.class;
    

    Class与泛型组合可提供编译期检查,确保传入的Class与所需要的类型相符。

    class classname<T>{
        Class<T> type;
    }
    
    展开全文
  • java中Class对象详解

    万次阅读 多人点赞 2012-12-28 16:23:27
    java中把生成Class对象和实例对象弄混了,更何况生成Class对象和生成instance都有多种方式。所以只有弄清其中的原理,才可以深入理解。首先要生成Class对象,然后再生成Instance。那Class对象的生成方式有哪些呢,...
     java中把生成Class对象和实例对象弄混了,更何况生成Class对象和生成instance都有多种方式。所以只有弄清其中的原理,才可以深入理解。首先要生成Class对象,然后再生成Instance。那Class对象的生成方式有哪些呢,以及其中是如何秘密生成的呢?
    

    Class对象的生成方式如下:

    1.Class.forName("类名字符串")  (注意:类名字符串必须是全称,包名+类名)

    2.类名.class

    3.实例对象.getClass()

    通过一段小程序,来观察一下Class对象的生成的原理。

    /**
    
     * 2012-2-6
    
     * Administrator
    
     */
    
    /**
    
     * @author: 梁焕月 
    
     * 文件名:TestClass.java 
    
     * 时间:2012-2-6上午10:01:52  
    
     */
    
    public class TestClass {
    
     
    
    public  static void main(String[] args)
    
    {
    
    try {
    
    //测试Class.forName()
    
    Class testTypeForName=Class.forName("TestClassType");        
    
    System.out.println("testForName---"+testTypeForName);
    
    //测试类名.class
    
    Class testTypeClass=TestClassType.class;
    
    System.out.println("testTypeClass---"+testTypeClass);
    
    //测试Object.getClass()
    
    TestClassType testGetClass= new TestClassType();
    
    System.out.println("testGetClass---"+testGetClass.getClass());
    
     
    
    } catch (ClassNotFoundException e) {
    
    // TODO Auto-generated catch block
    
    e.printStackTrace();
    
    }
    
     
    
    }
    
    }
    
     class TestClassType{
    
    //构造函数
    
    public TestClassType(){
    
    System.out.println("----构造函数---");
    
    }
    
    //静态的参数初始化
    
    static{
    
    System.out.println("---静态的参数初始化---");
    
    }
    
    //非静态的参数初始化
    
    {
    
    System.out.println("----非静态的参数初始化---");
    
    }        
    
    }
    

     

    测试的结果如下:

    ---静态的参数初始化---

    testForName---class TestClassType

    testTypeClass---class TestClassType

    ----非静态的参数初始化---

    ----构造函数---

    testGetClass---class TestClassType

     

    根据结果可以发现,三种生成的Class对象一样的。并且三种生成Class对象只打印一次“静态的参数初始化”。 

    我们知道,静态的方法属性初始化,是在加载类的时候初始化。而非静态方法属性初始化,是new类实例对象的时候加载。

    因此,这段程序说明,三种方式生成Class对象,其实只有一个Class对象。在生成Class对象的时候,首先判断内存中是否已经加载。

    所以,生成Class对象的过程其实是如此的:

    当我们编写一个新的java类时,JVM就会帮我们编译成class对象,存放在同名的.class文件中。在运行时,当需要生成这个类的对象,JVM就会检查此类是否已经装载内存中。若是没有装载,则把.class文件装入到内存中。若是装载,则根据class文件生成实例对象。

    展开全文
  • 简单理解,就是new,就是对类的实例化,创建这个类对应的实际对象,类只是对事物的描述,而实例化就相当于为这个描述新开辟了一块内存,可以改变这块区域里的各种属性(成员变量),当然,也可以实例化多块区域,...
  • Java中Class对象详解

    千次阅读 多人点赞 2016-09-06 18:04:14
    从某种意义上来说,java有两种对象:实例对象和Class对象。每个类的运行时的类型信息就是用Class对象表示的。它包含了与类有关的信息。其实我们的实例对象就通过Class对象来创建的。Java使用Class对象执行其RTTI...
  • 深入理解Java类型信息(Class对象)与反射机制

    万次阅读 多人点赞 2018-01-07 11:34:00
    【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) ...深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解
  • 获取Class对象 Class clazz = Class.forName("com.atguigu.java.fanshe.Person"); //2. 利用Class对象的newInstance方法创建一个类的实例 Object obj = clazz.newInstance(); 平常理解的对象和实例都是...
  • Java类型信息(Class对象)与反射机制

    千次阅读 2018-12-26 17:31:22
    RRTI的概念以及Class对象作用 RTTI(Run-Time Type Identification)运行时类型识别,对于这个词一直是 C++ 中的概念,至于Java中出现RRTI的说法则是源于《Thinking in Java》一书,其作用是在运行时识别一个对象的...
  • jQuery根据ID、CLASS、等获取对象

    万次阅读 2014-11-25 14:47:27
    jQuery根据ID、CLASS、等获取对象 Jquery是继prototype之后又一个优秀的Javascrīpt框架。它是轻量级的js库(压缩后只有21k) , 它兼容CSS3,还兼容各种浏览器 (IE 6.0+, FF 1.5+, Safari 2.0+, Opera
  • 原生Js通过class属性值获取对象

    万次阅读 2016-01-04 15:03:32
    原生Js通过class属性值获取对象 window.onload = function(){ console.log(getElementByClassName("tag").length); console.log(getElementByClassName("tag")); } function getElementByClassName(classnames){ ...
  • 说明:内容复制粘贴https://www.cnblogs.com/cunlau/p/3624878.html而来 Class对象的生成方式如下:1.类名.class 说明: JVM将使用类装载器, 将类装入内存(前提是:类还没有装入内存),不做类的初始化工作.返回Class的...
  • 有一个 对象 是Object 类型,知道了它的 Class<?> 对象,怎样将他转换成 对应的类型呢?
  • Java获取泛型的Class对象

    万次阅读 2017-11-01 15:06:02
    在做解析excel的时候,想通过泛型把解析和转java bean的过程封装起来,后面发现java里面只能获取到父类的泛型Class。这样的话,就意味着如果获取泛型Class来实例化bean...这里记录一下Java获取泛型的Class对象的demo
  • this.class.getClassLoader()怎么理解?

    万次阅读 多人点赞 2011-05-10 15:43:00
    java里面的所有的类都是Class类的对象,这个this.class是获得这个类相对于Class类的对象。后面的方法是获得这个类对象的加载器。 只有Class类才有getClassLoader()方法呀~ 可以这么想,我们平时讲述某某类,但是...
  • JAVA有三种方式可以获得Class对象 1、通过类名.class方式获得,Class cType = ClassName.class; public class Client { public static void main(String[] args) { Class cType1 = Test.class; } } class Test{ ...
  • T - 由此 Class 对象建模的类的类型。例如,String.class 的类型是 Class。如果将被建模的类未知,则使用 Class。 public final class Class extends Object implements java.io.Serializable, java.lang.r
  • javascript根据class获取对象

    千次阅读 2012-05-22 10:10:18
    jQuery根据class获取对象大家从所周知,灰常的方便。下面不多说 /* * clsName:给定类名 * tagName:给定的HTML元素,如果为任意 tagName='*' * ClassElements:返回值 */ function getElementsByClassName(clsName,...
  • 浅谈反射机制

    万次阅读 2016-09-09 14:22:58
    其实从某种意义上说,在java中有两种对象:实例对象和Class对象。实例对象就是我们平常定义的一个类的实例 public class Person {} 然后利用new关键字: public class Person { public static void main(String...
  • js-如何获取class对象

    万次阅读 2012-07-12 12:02:21
    function getClass(obj,attr){ var aArray=[];//定义一个新的空数组 var i=0; var aAll = obj.getElementsByTagName('*');//获取obj对象下面所有的节点 ... if(aAll[i].className == attr){//判断当前对象class
1 2 3 4 5 ... 20
收藏数 3,346,493
精华内容 1,338,597
关键字:

class对象