Java学习-反射机制入门

1、反射机制

  我们在正常的使用过程之中只关心类产生对象,而后通过对象调用类之中的方法,可是,除了这种传统的方式外,也可以利用反射操作。

1.1、认识反射

  既然有反,那么一定存在有正,正是指通过类产生对象,而后通过对象执行操作。而反呢?通过对象找到它所在类的信息。所有的对象都支持反这一操作,因为Object类有一个方法:public final Class<?> getClass()。

1 package cn.kvikon.demo;
2 import java.util.Date;
3
4 public class TestDemo {
5     public static void main(String [] args) throws Exception {
6       Date date = new Date() ;
7       System.out.println(date.getClass()) ;
8   }
9 }

  现在的代码可以直接通过对象取得它所对应的类型,那么也就不难理解instanceof关键字的处理方式。

1.2、实例化Class类对象

  在Object类之中定义的getClass()方法,发现里面返回的类型是Class,而Class是作为一切反射操作的源头。所以首先一定要清楚如何实例化Class实例化对象,实际上此类对象有三种实例化方式:

  · 方式一:利用Object类之中的getClass()方法;

 1 package cn.kvikon.demo ;
 2
 3 import java.util.Date ;
 4
 5 public class TestDemo {
 6      public static void main(String [] args) throws Exception {
 7          Date date = new Date() ;
 8          Class<?> cls = date.getClass() ;
 9          System.out.println(cls) ;
10   }
11
12 }

  · 方式二:利用“类.class”取得;

 1 package cn.kvikon.demo ;
 2
 3 import java.util.Date ;
 4
 5 public class TestDemo {
 6      public static void main(String [] args) throws Exception {
 7           Class<?> cls = Date.class ;
 8           System.out.println(cls) ;
 9    }
10
11  }

  · 方式三:Class类内部提供了一个static方法;

    public static Class<?> forName(String className) throws ClassNotFoundException

1 package cn.kvikon.demo ;
2
3 public class TestDemo {
4    public static void main(String [] args) throws Exception {
5           Class<?> cls = Class.forName("java.util.Date") ;
6            System.out.println(cls) ;
7      }
8   }

  以上给出的三个方式最没用处的就是第一种方式了,而第二种方式是在日后学习Hibernate的时候使用,现阶段主要使用第三种方式,而第三种方式是Spring实现基础。

1.3、 利用反射实例化对象

  对象的实例化操作在之前只能够利用关键字new实现,但是从今天开始,对象实例化也可以利用反射机制进行处理,因为在Class类之中定义了一个方法:“public T newInstance() throws InstantiationException,IllegalAccessException”;

package cn.kvikon.demo ;

class Person {
    public String toString () {
       return "是个人!" ;
  }
}

  public class TestDemo {
      public static void main(String [] args) throws Exception {
            Class<?> cls = Class.forName("cn.kvikon.demo.Person") ;
            Person per = (Person) cls.newInstance() ;
            System.out.println(per) ;
    }
     }

  疑问?既然关键字new和反射都可以实例化对象,那么有什么区别呢?

  · 通过工厂设计模式来分析问题,使用关键字new。

 package cn.kvikon.demo ;
 interface Fruit {
    public void eat () ;
 }
  class Apple implements Fruit {
      public void eat () {
        System.out.println("吃苹果") ;
     }
  }
  class Factory {
      public static Fruit getInstance (String className) {
     if ("apple".equals(className)) {
          return new Apple () ;
     }
     return null ;
   }
 public class FactoryDemo {
   public static void main (String [] args) {
       Fruit fru = Factory.getInstance("apple") ;
       fru.eat() ;
     }
   }
 }

  如果说现在增加了一个Fruit接口子类,那么就需要修改Factory类。很明显这种做法很蠢,希望最适合的工厂可以不做任何修改而适应所有的子类。但是此时的代码不行,因为造成这一关键性问题的主要原因是new(造成Factory类与每一个接口子类直接耦合)。

  · 通过反射处理,反射处理的好处是主需要有“包.类名称”就可以实例化。

 1 package cn.kvikon.demo ;
 2 interface Fruit {
 3     public void eat () ;
 4 }
 5 class Apple implements Fruit {
 6     public void eat () {
 7         System.out.println("吃苹果") ;
 8     }
 9 }
10 class Orange implements Fruit {
11     public void eat () {
12         System.out.println("吃桔子") ;
13     }
14 }
15 class banana implements Fruit {
16     public void eat () {
17         System.out.println("吃香蕉") ;
18     }
19 }
20 class Factory {
21     public static Fruit getInstance (String className) {
22         Fruit fruit = null ;
23         try {
24             fruit = (fruit) Class.forName(className).newInstance () ;
25         } catch (Exception e) {
26             e.printStackTrace () ;
27     }
28         return fruit ;
29   }
30 public class FactoryDemo {
31   public static void main (String [] args) {
32       Fruit fru = Factory.getInstance("cn.kvikon.Apple") ;
33       fru.eat() ;
34     }
35   }
36 }

现在子类可以随意增加,工厂类不需要做任何的修改。

使用反射之后最大的好处就是解耦和。

1.4、 使用反射操作类的结构

  类的结构就三部分:构造方法、普通方法、属性,而这些操作有了反射,一切都可以轻松面对。

  (1) 调用构造

    · 构造方法是在类实例化的时候默认调用的,一个类之中可以提供有多个构造方法。而且一个类如果没有定义任何一个构造方法的话,则会自动生成一个无参的,什么都不做的构造方法。

    在Class类之中定义了如下取得构造方法的操作:

      · 取得全部构造:public Constructor<?>[] getConstructors () throws SecurityException ;

      · 取得指定构造:public Constructor<T> getConstructor(Class<?> ... parameterTypes) throws NoSuchMethodException,SecurytyException 。

 1   package cn.kvikon.demo ;
 2   class Person {
 3      private String name ;
 4      private int age ;
 5     public Person (String name, int age) {
 6         this.name = name ;
 7         this.age = age ;
 8   }
 9     public String toString () {
10         return "姓名: "  + this.name + ",年龄:" + this.age  ;
11    }
12  }
13  public class FactoryDemo {
14    public static void main (String [] args) {
15         Class<?> cls = Class.forName ("cn.kvikon.demo.Person") ;
16         Person per = (Person) cls.newInstance () ;
17         System.out.println (per) ;
18      }
19    }
20  }

以上错误提示:Exception in thread "main" java.lang.InstantiationException: cn.kvikon.demo.Person

  在使用Class类对象反射实例化对象的时候,类之中必须提供有无参构造,如果不提供就出错了。那么如果说现在类中就没有无参构造的话,那么就必须利用反射找到指定的构造方法明确传入所需要的参数才可以实例化对象,这就要通过Constructor类完成了。

 1   package cn.kvikon.demo ;
 2
 3   import java.lang.reflect.Constructor ;
 4
 5   class Person {
 6      private String name ;
 7      private int age ;
 8     public Person (String name, int age) {
 9         this.name = name ;
10         this.age = age ;
11   }
12     public String toString () {
13         return "姓名: "  + this.name + ",年龄:" + this.age  ;
14    }
15  }
16  public class FactoryDemo {
17    public static void main (String [] args) {
18         Class<?> cls = Class.forName ("cn.kvikon.demo.Person") ;
19         // 根据构造方法的参数类型找到一个指定的构造
20         Constructor<?> cons = cls.getConstructor (String.class, int.class) ;
21         Person per = (Person) cons.newInstance("张三" , 20) ;
22         System.out.println (per) ;
23      }
24    }
25  }

  如果为了统一的话,还是保留有无参构造会比较好。

  (2) 调用方法

    除了使用对象调用类中的方法之外,也可以利用反射完成,在Class类里面定义了如下方法:

      ·  取得全部方法:public Method[] getMethods() throws SecurityException ;

      ·  取得指定方法:public Method getMethod(String name, Class<?> ... parameterTypes) throws NoSuchMethodException, SecurityException。

    不管是否使用反射,如果要调用类中的方法请一定要保证有实例化对象。

 范例:通过反射调用类中的setter、getter方法

 1   package cn.kvikon.demo ;
 2
 3   import java.lang.reflect.Constructor ;
 4
 5   class Person {
 6      private String name ;
 7      public void setName (String name) {
 8          this.name = name ;
 9   }
10      public String getName () {
11         return name ;
12   }
13  }
14  public class FactoryDemo {
15    public static void main (String [] args) {
16         String attribute = "name" ;   //  操作的是类中的name属性
17         Class<?> cls = Class.forName ("cn.kvikon.demo.Person") ;
18         Object obj = cls.newInstance () ;     //  实例化对象
19         Method setMethod = cls.getMethod ("set" +  initcap (attribute) , String.class) ;
20         setMethod.invoke (obj , "张三") ;    // 对象.setName ("张三") ;
21         Method getMethod = cls.getMethod ("get" + initcap (attribute) ) ;
22         System.out.println (getMethod.invoke (obj)) ;  // 对象.getName ()
23    }
24         public static String initcap (String str) {
25         return str.substring (0,1).toUpperCase ().concat (Str.substring(1).toLowerCase ()) ;
26     }
27  }

  (3) 调用属性

     类之中的属性一定是使用private封装的,但是由于其也是组成的部分,所以也可以反射操作,通过Class类对象取得;

    ·  取得定义的全部属性:public Field[] getDeclareFields() throws SecuriryException ;

    ·  取得指定的属性: public Field getDeclareFields(String name) throws NoSuchFieldException, SecurityException .

    · 设置属性内容: public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException

    · 取得属性内容: public Object get(Object obj) throws IllegalArgumentException, IllegalAccessException

范例:操作属性

package cn.kvikon.demo ;

import java.lang.reflect.Method ;

class Person {
      private String name ;
   }
  }
  public class TestDemo {
  public static void main (String [] args)  throws Exception{
         Class<?> cls = Class.forName ("cn.kvikon.demo.Person") ;
         Object obj = cls.newInstance () ;  // 实例化对象
         System.out.println (per) ;
         Field nameField = cls.getDeclaredField ("name") ;   //  取得name属性
         nameField.setAccessible (true) ;   // 取消封装
         nameField.set (obj , "张三") ;    //   对象.name = "张三" ;
         System.out.println(nameField.get(obj)) ;
    }
  }

  但是所有的属性一定要通过setter、getter设置和取得,以上的代码只是针对于Field操作做一个说明。

以上是反射深入操作的基础。

  总结:除了new之外,可以使用Class.forName().newInstance()实例化对象。

时间: 2024-10-10 12:54:46

Java学习-反射机制入门的相关文章

java的反射机制入门

理解Java的反射机制对学习Java框架有很大帮助,比如Spring框架的核心就是使用Java反射实现的,同时对做一些Java底层操作也会有帮助,比如字节码操作.自定义注解等. 什么是反射 Java反射说的是在运行状态中,对于任何一个类,我们都能够直到这个类有哪些方法和属性.对于任何一个对象,我们都能够对它的方法和属性进行调用.这种动态获取对象信息和调用对象方法的功能就是Java的反射机制. 反射的三种方式 反射其实就是获取类的字节码文件,也就是.class文件,那么我们就可以通过Class这个

java学习——反射机制

/* * JAVA反射机制是在运行状态中,对于任意一个类 (class文件),都能够知道这个类的所有属性和方法: * 对于任意一个对象,都能够调用它的任意一个方法和属性: * 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. * * 动态获取类中信息,就是java反射 . * 可以理解为对类的解剖. * * 要想要对字节码文件进行解剖,必须要有字节码文件对象. * 如何获取字节码文件对象呢? * */ 1. 通过Class clazz =Class.forName()找

JAVA的反射机制学习笔记(二)

上次写JAVA的反射机制学习笔记(一)的时候,还是7月22号,这些天就瞎忙活了,自己的步伐完全被打乱了~不能继续被动下去,得重新找到自己的节奏. 4.获取类的Constructor 通过反射机制得到某个类的构造器,然后调用该构造器创建该类的一个实例 Class<T>类提供了几个方法获取类的构造器. public Constructor<T> getConstructor(Class<?>... parameterTypes) 返回一个 Constructor 对象,它反

学习:java原理—反射机制

一.什么是反射:反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.这一概念的提 出很快引发了计算机科学领域关于应用反射性的研究.它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩.其中 LEAD/LEAD++ .OpenC++ .MetaXa和OpenJava等就是基于反射机制的语言.最近,反射机制也被应用到了视窗系统.操作系统和文件系统中. 反射本身并不 是一个新概念,尽管计算机科学赋予了反射概念新的含义.在计算机科

Java 中反射机制的深入研究

昨天学习了java的反射机制,今天继续深入学习一下. 一.通过反射操作数组 反射不光只能用在类中,也可用在任意的引用数据类型上.当然包括数组. 通过java.lang.reflect.Array 类 可操作数组,java.lang.reflect.Array 类 下面提供了很多方法. 例如 public static Object get(Object array,int index)throws IllegalArgumentException,ArrayIndexOutOfBoundsExc

Java 类反射机制分析

一.反射的概念及在Java中的类反射 反射主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.在计算机科学领域,反射是一类应用,它们能够自描述和自控制.这类应用通过某种机制来实现对自己行为的描述和检测,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义. 在Java中的反射机制,被称为Reflection.(大家看到这个单词,第一个想法应该就是去开发文档中搜一下了.)它允许运行中的Java程序对自身进行检查,并能直接操作程序的内部属性或方法.Reflection机制

深入理解java的反射机制

今天将从以下4方面来系统的学习一下java的反射机制: java反射是什么 java反射(Reflection)底层实现原理 java反射的简单演示 java反射的应用场景 1,java反射是什么 首先大家应该先了解两个概念,编译期和运行期,编译期就是编译器帮你把源代码翻译成机器能识别的代码,比如编译器把java代码编译成jvm识别的字节码文件,而运行期指的是将可执行文件交给操作系统去执行,JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够

java利器------反射机制

java反射的概念:java的反射机制是指在运行状态下,对于一个类来说,可以得到这个类的所有方法和属性.对于一个对象来说,可以调用这个对象的人和方法和属性. 反射机制首先会拿到该类的字节码文件(Class文件),然后反向获取这个类的所有信息.(注意:一个类型的类在运行中,只产生一个class文件) 既然反射的前置条件是获取class类,所以不得不提出获取class的方法. 获取class的几种方式: (1)Persion p=new Persion(); Class c=p.getClass()

Java中反射机制和Class.forName、实例对象.class(属性)、实例对象getClass()的区别(转)

一.Java的反射机制   每个Java程序执行前都必须经过编译.加载.连接.和初始化这几个阶段,后三个阶段如下图:  其中 i.加载是指将编译后的java类文件(也就是.class文件)中的二进制数据读入内存,并将其放在运行时数据区的方法区内,然后再堆区创建一个Java.lang.Class对象,用来封装类在方法区的数据结构.即加载后最终得到的是Class对象,并且更加值得注意的是:该Java.lang.Class对象是单实例的,无论这个类创建了多少个对象,他的Class对象时唯一的!!!!.