java基础学习笔记——反射机制


java基础学习笔记——反射机制



开始捣鼓java的反射机制了,好了.....那开始吧!

一、什么是java的反射机制

大家都知道的啦,在运行java程序的过程中,会产生以后缀名.class结尾的文件,我们称其为字节码文件。那么,当JVM拿到这些字节码文件会去干什么呢???我们想一下肯定能想得到,JVM肯定是对此文件进行了剖析。这种在程序的动态运行过程中,对于编译所产生的任意一个.class文件能够动态的知道此类的属性和方法,动态获取类的相关信息的这种机制,就叫做java的反射机制。 OK,从上面的解释可以看出,使用反射机制就可以提高应用程序的扩展性,因为程序可以在动态的运行过程中动态的分析和加载某些内容,这些内容通常是对程序功能的扩展。那么,既然java的反射机制是通过对.class文件进行剖析之后进而读取其中的相关信息的,是不是JVM或者调用者首先得想办法得到.class文件呢???首先我们建立练习文件,方便反射机制的演示。

二、建立Person类for练习反射机制

建立练习文件,代码如下:

/ * 首先我们建立一个练习反射机制的Person类。
 * 程序代码如下:
 */
public class Person {
 
        privateint age;
        privateString name;
        //有参构造函数
        publicPerson(int age, String name) {
               super();
               this.age= age;
               this.name= name;
               System.out.println("Person(int,String)run...."+this.name+":"+this.age);
        }
        //空参构造函数
        publicPerson() {
               super();
               System.out.println("Person()run....");
        }
        //公有方法
        publicvoid publicMethod() {
               System.out.println("publicMethodrun...");
        }
        //私有方法
        privatevoid privateMethod() {
               System.out.println("privateMethodrun...");
        }
        //有参方法
        publicvoid parameterMethod(String name, int age) {
               System.out.println("parameterMethodrun..." + age + name);
        }
        //静态方法
        publicstatic void staticMethod(){
               System.out.println("staticMethodrun...");
        }
        //完善类的初始化方法
        publicint getAge() {
               returnage;
        }
 
        publicvoid setAge(int age) {
               this.age= age;
        }
 
        publicString getName() {
               returnname;
        }
 
        publicvoid setName(String name) {
               this.name= name;
        }
 
        @Override
        publicString toString() {
               return"Person [age=" + age + ", name=" + name + "]";
        }
}
 

三、获取class文件的方法

public class ReflectDemo {
        /**
         * 获取字节码文件的三种方式: 1.Object类中的getClass()方法。
         * 2. 每一个类都具备静态属性,即.class。
         * 3.通过指定的类的字符串名称,使用Class类的静态方法。
         * @throws ClassNotFoundException
         */
        publicstatic void main(String[] args) throws ClassNotFoundException {
 
               getClass_1();
               getClass_2();
               getClass_3();
        }
        /*
         * 使用Class类中的public static Class<?> forName(String className)throwsClassNotFoundException方法。
         * 注意:需要抛出异常。同时,此处由于使用的是默认的包,因此,字符串类的名字直接就是类名,否则就要指定的类的全名。即加上包名。
         */
        publicstatic void getClass_3() throws ClassNotFoundException {
               Classc1 = Class.forName("Person");
               Classc2 = Class.forName("Person");
               System.out.println(c1);
               System.out.println(c2);
        }
 
        /*
         * 使用任何一个类具备的.class的静态属性。
         * 缺点是:要使用到类中的静态成员,扩展性弱。
         */
        publicstatic void getClass_2() {
               Classc1 = Person.class;
               Classc2 = Person.class;
               System.out.println(c1);
               System.out.println(c2);
        }
 
        /*
         * 使用Object类中的public final Class<?> getClass()方法。
         * 缺点是:需要创建对象。
         */
        publicstatic void getClass_1() {
               Personp1 = new Person();
               Classc1 = p1.getClass();
               Personp2 = new Person();
               Classc2 = p2.getClass();
               System.out.println(c1);
               System.out.println(c2);
 
        }
}

四、利用反射机制获取构造函数

1.了解两个异常:

    在java.lang包中,有两个与java反射机制相关的异常,分别是:

public class InstantiationException extends Exception和public class IllegalAccessException。

    这两个异常类发生的情况是:InstantiationException发生在类似于在利用某个构造函数去实例化一个对象的时候,但是类中却不存在这样的构造函数,例如在利用空参构造函数时,却没有空参构造函数。

   IllegalAccessException发生在类似于在类中是有构造函数的,但是构造函数被私有化了,访问不到,则会发生此异常。

2.反射机制获取空参数构造函数对象    

public class ReflectDemo {
        publicstatic void main(String[] args) throws ClassNotFoundException,
                       InstantiationException,IllegalAccessException {
               //使用字节码文件对象的方法创建实例。
               getConstructorDemo();
 
        }
        publicstatic void getConstructorDemo() throws ClassNotFoundException,
                       InstantiationException,IllegalAccessException {
               //1.获取字节码文件对象
               Stringname = "Person";
               Class<Person>c = (Class<Person>) Class.forName(name);
               //2.利用字节码文件对象使用空参数的构造函数创建对象。
                Person obj = c.newInstance();
        }
}

  3.反射机制获取有参数构造函数对象

import java.lang.reflect.Constructor;
importjava.lang.reflect.InvocationTargetException;
 
public class ReflectDemo {
        publicstatic void main(String[] args) throws ClassNotFoundException,
                       InstantiationException,IllegalAccessException,
                       NoSuchMethodException,SecurityException, IllegalArgumentException,
                       InvocationTargetException{
 
               getConstructorDemo();
 
        }
 
        publicstatic void getConstructorDemo() throws ClassNotFoundException,
                       NoSuchMethodException,SecurityException, InstantiationException,
                       IllegalAccessException,IllegalArgumentException,
                       InvocationTargetException{
               //1.获取字节码文件对象
               Stringname = "Person";
               Class<Person>c = (Class<Person>) Class.forName(name);
 
               //2.利用字节码文件对象获取其对象中的构造函数。
               Constructor con = c.getConstructor(int.class, String.class);
 
               //3.创建对象
               Personobj = (Person) con.newInstance(25, "wanxi");
        }
}

    其中,Constructor是java.lang.reflect包中的一类,并且此类带有泛型。此类的完整继承关系如下:

public final class Constructor<T> extends AccessibleObject implements GenericDeclaration, Member

    官方对此类的解释是:Constructor 提供关于类的单个构造方法的信息以及对它的访问权限。Constructor 允许在将实参与带有底层构造方法的形参的 newInstance() 匹配时进行扩展转换,但是如果发生收缩转换,则抛出IllegalArgumentException。 

五、利用反射机制获取字段

import java.lang.reflect.Field;
 
public class ReflectDemo3 {
        /**
         * @author Administrator
         * @param args
         * @throws ClassNotFoundException
         * @throws SecurityException
         * @throws NoSuchFieldException
         * @throws IllegalAccessException
         * @throws InstantiationException
         *
         */
        publicstatic void main(String[] args) throws ClassNotFoundException,
                       NoSuchFieldException,SecurityException, InstantiationException, IllegalAccessException {
               getFieldDemo();
        }
        publicstatic void getFieldDemo() throws ClassNotFoundException,
                       NoSuchFieldException,SecurityException, InstantiationException, IllegalAccessException {
               //获取字节码文件对象。
               String name = "Person";
               Class c = Class.forName(name);
               /*
                *  使用字节码文件对象的方法获取字段集合。
                *  Fieldfield =c.getField("age");利用此方法会出现错误,因为在我们的Person类中的字段是私有的,
                *  就是说getField(String str)只能获取公有的方法。
                *  而getDeclaredField(String str)可以获取私有的字段,但是只能获取本类中的字段,父类中的是获取不到的。
                */
               Field field = c.getDeclaredField("age");
               //在上述方法中,虽然我们拿到了field对象,但是由于其是私有的,因此如果我们使用get(Object obj)方法,则会出现无效的访问异常。因为有Private修饰。          
               //解决上述问题的办法:让程序在运行的时候对私有字段的方法取消权限的检查。
               field.setAccessible(true);
               //利用方法获取值,其中参数的意思是明确要获取哪个对象的age属性的值,因此首先创建对象。
               Object obj = c.newInstance();
               Object val = field.get(obj);
               System.out.println(val);
               //利用方法设置值,其中参数的意思是明确要给哪个对象的age属性设置值。
               field.set(obj,25);
               Object val1 = field.get(obj);
               System.out.println(val1);
        }
}

六、利用反射机制获取方法

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
 
public class ReflectDemo {
 
        publicstatic void main(String[] args) throws Exception {
 
               getPrivateMethodDemo();
               getAllMethodDemo();
               getSingleMethodDemo();
               getSingleParameterMethodDemo();
        }
        /*
         * 利用java的反射机制获取对象自己的所有方法,包括私有方法。
         */
        publicstatic void getPrivateMethodDemo() throws Exception {
               //获取字节码文件对象。
               Stringname = "Person";
               Classc = Class.forName(name);
               //获取对象中自己的所有方法,包括私有的方法。
               Method[]methods = c.getDeclaredMethods();
               for(Method method:methods){
                       System.out.println(method);
               }
        }
 
        /*
         *利用java的反射机制获取对象中的所有方法。
         */
        publicstatic void getAllMethodDemo() throws Exception {
               //获取字节码文件对象。
               String name = "Person";
               Class c = Class.forName(name);
               //获取对象中的所有方法,包括父类中的方法。
               Method[] methods = c.getMethods();
               for(Method method:methods){
                       System.out.println(method);
               }             
        }
        /*
         * 获取对象中指定的空参数的方法,并且运行获取的方法。
         */
        publicstatic void getSingleMethodDemo() throws Exception {
               //获取字节码文件对象。
               String name = "Person";
               Class c = Class.forName(name);
               //获取指定的方法。
               Method method = c.getMethod("staticMethod", null);
               //创建对象,指定获取的方法是属于哪个对象的。
               Object obj = c.newInstance();
               //运行obj这个对象的方法。
               method.invoke(obj,null);
        }
        /*
         * 获取对象中指定的带参数的方法,并且运行获取的方法。
         */
        publicstatic void getSingleParameterMethodDemo() throws Exception {
               //获取字节码文件对象。
               String name = "Person";
               Class c = Class.forName(name);
               //获取指定的带参数的方法。
               Method method = c.getMethod("parameterMethod", String.class,int.class);
               //创建对象,利用有参数的构造方法进行创建,指定获取的方法是属于哪个对象的。
               Constructor constructor = c.getConstructor(int.class,String.class);
               Object obj = constructor.newInstance(30,"wanxi");
               //运行obj这个对象的方法。
               method.invoke(obj,"xiaoqiang",32);
              
        }
}

    关于反射机制的应用,经常是用来增强程序的扩展性,使用者只需要实现源程序暴露出来的接口,然后将程序的相关信息写在一个配置文件中去(经常是XML文件),然后主程序会在动态的运行过程中去读取配置文件,从而拿到新扩展的程序的相关信息,对其进行剖析(反射机制原理)加以运行即可。因此,程序不需要改动源代码即可实现自身功能的扩展。   

    



可以看出,利用java的反射机制,可以很好的解析字节码文件,从而进行程序的动态扩展性。(后续会继续完善......)



=======================================================

注: 转载注明出处: http://blog.csdn.net/xzpd1518148553

=======================================================

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
文件上传是Web开发中常见的功能之一,Java中也提供了多种方式来实现文件上传。其中,一种常用的方式是通过Apache的commons-fileupload组件来实现文件上传。 以下是实现文件上传的步骤: 1.在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.3</version> </dependency> ``` 2.在前端页面中添加文件上传表单: ```html <form method="post" enctype="multipart/form-data" action="upload"> <input type="file" name="file"> <input type="submit" value="Upload"> </form> ``` 3.在后台Java代码中处理上传文件: ```java // 创建一个DiskFileItemFactory对象,用于解析上传的文件 DiskFileItemFactory factory = new DiskFileItemFactory(); // 设置缓冲区大小,如果上传的文件大于缓冲区大小,则先将文件保存到临时文件中,再进行处理 factory.setSizeThreshold(1024 * 1024); // 创建一个ServletFileUpload对象,用于解析上传的文件 ServletFileUpload upload = new ServletFileUpload(factory); // 设置上传文件的大小限制,这里设置为10MB upload.setFileSizeMax(10 * 1024 * 1024); // 解析上传的文件,得到一个FileItem的List集合 List<FileItem> items = upload.parseRequest(request); // 遍历FileItem的List集合,处理上传的文件 for (FileItem item : items) { // 判断当前FileItem是否为上传的文件 if (!item.isFormField()) { // 获取上传文件的文件名 String fileName = item.getName(); // 创建一个File对象,用于保存上传的文件 File file = new File("D:/uploads/" + fileName); // 将上传的文件保存到指定的目录中 item.write(file); } } ``` 以上代码中,首先创建了一个DiskFileItemFactory对象,用于解析上传的文件。然后设置了缓冲区大小和上传文件的大小限制。接着创建一个ServletFileUpload对象,用于解析上传的文件。最后遍历FileItem的List集合,判断当前FileItem是否为上传的文件,如果是,则获取文件名,创建一个File对象,将上传的文件保存到指定的目录中。 4.文件上传完成后,可以给用户一个提示信息,例如: ```java response.getWriter().write("File uploaded successfully!"); ``` 以上就是使用Apache的commons-fileupload组件实现文件上传的步骤。需要注意的是,文件上传可能会带来安全隐患,因此在处理上传的文件时,需要进行严格的校验和过滤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值