zoukankan      html  css  js  c++  java
  • 反射


    反射

    反射是程序在运行时能够获取自身的信息。


    优点

    运行时确定类型,绑定对象。动态编译最大发挥java的灵活性,体现多态应用,降低程序耦合性。

    缺点

    反射其实就是一种解释操作,这种操作慢于直接执行相同操作。


    class

    class代表java类,就相当于person代表人。

    类被加载到内存中,这片内存空间就是类的字节码,不同的类字节码是不同的,一个类在内存中只有一份字节码。


    获取字节码的三种方式

    public class GetClass {
    	public static void main(String[] args)throws Exception{
    		Class c1=String.class;                          //调用某个类的class属性获取Class对象
    		Class c2=Class.forName("java.lang.String");     //使用Class类的forName(String className)静态方法
    		Class c3=new String().getClass();				//用某个对象的getClass()方法,该方法属于Object类
    	}
    }
    

    预定义Class对象

    基本java类型:int,short,long,byte,char,boolean,double,float和关键字void通过class属性也能表示为class对象。

    IsPrimitive判断对象是否是基本类型。

    IsArry判断对象是否是数组。


    public class ClassDemo {
    	public static void main(String[] args)
    	{
    		Class i1=int.class;
    		Class i2=Integer.class;
    		Class i3=Integer.TYPE;     //包装类都有一个常量TYPE,用来表示其基本数据类型的字节码
    		System.out.println(i1);
    		System.out.println(i2);
    		System.out.println(i3);
    		System.out.println(i1==i2);
    		System.out.println(i2==i3);  //证明TYPE值是int
    		
    		Class i4=String[].class;
    		Class i5=int[].class;
    		/*System.out.println(i4==i5);
    		 * 会报错,因为int[]里面的是不是一个对象,String[]里是对象*/
    		Class i6=Integer[].class;
    		System.out.println(i4==i6);
    		//这样就可以,因为Integer[]里放的是对象所以可以String[]里面的对象比赛
    		
    		System.out.println(i1.isPrimitive());
    		//判断i1是否是基本类型
    		System.out.println(i4.isArray());
    		//判断i4是否是数组类型
    	}
    }
    



    用Class类获取类的信息

    package JustTest;
    class Fu{}
    interface A{}
    interface B{}
    class Zi extends Fu implements A,B
    {
    	public class imclass{}
    	//定义一个内部类
    	public interface iminterface{}
    	//定义一个内部接口
    }
    
    
    public class ClassDemo {
    	public static void main(String[] args)
    	{
    		Class c=Zi.class;
    		
    		System.out.println(c);
    		//得到字节码
    		System.out.println(c.getPackage());
    		//得到包名
    		System.out.println(c.getName());
    		//得到全限定名
    		System.out.println(c.getSimpleName());
    		//得到类名
    		System.out.println(c.getSuperclass());
    		//得到父类
    		System.out.println(c.getSuperclass().getSimpleName());
    		//得到父类名
    		
    		Class[] c2=c.getInterfaces();
    		//因为接口可以有很多个,所以用一数组装结果
    		for(Class c1:c2)//高级for循环迭代
    		{
    			System.out.println(c1);
    		}
    		
    		Class[] c3=c.getClasses();
    		//得到内部类和内部接口
    		for(Class c4:c3)
    		{
    			System.out.println(c4);
    		}
    		
    		System.out.println(c.getModifiers());
    		//得到修饰符,如果返回1,则该类修饰符为public
    		
    	}
    }



    Class得到类构造方法(Constructor)、方法(Method)、字段(Field)



    得到构造方法和newInstance创建对象

    用newInstance方法创建该class对象的实例,此类必须有无参的构造方法

    如果构造方法被私有,在创建之前申请访问,也就是将AccessibleObject对象的setAccessible方法设为true



    package JustTest;
    import java.lang.reflect.*;
    public class GetConStructor  {
    	public static void main(String[] args)throws Exception
    	{
    		Class c=String.class;
    		Constructor[] con=c.getConstructors();
    		////前面的修饰符必须是public才可以在这个方法下获取到
    		for(Constructor cons:con)
    		{
    			System.out.println(cons);
    		}
    		
    		Constructor con2=c.getConstructor(String.class);
    		
    		//得到指定的构造函数,此函数必需是pulibc。
    		//参数是构造方法中的形参
    		String str=(String)con2.newInstance("abc");
    		//newInstance方法形参是Object,返回的也是Object,所以"abc"传到里面会向上转型
    		//赋值时必须向下转型
    		
    		System.out.println(str);
    		
    		Constructor[] c2=c.getDeclaredConstructors();
    		//暴力反射,不管是否是public 
    		for(Constructor con3:c2)
    		{
    			System.out.println("暴力反射..."+con3);
    		}
    		
    	}
    }

    步骤

    1:获取该类的字节码

    2:用Class对象getConstructor()方法获取指定的构造方法

    3:申请访问(如果构造方法为public可不用)

    4:调用Constructor的newInstance方法创建对象




    得到方法和反射调用方法

    获得Method对象后,可以用Method中的invoke方法来执行指向的方法

    invoke(Object obj,Object...args)obj表示方法的对象,args是方法的参数,如果方法是静态的那么第一个参数写null,形参亦此

    package JustTest;
    import java.lang.reflect.*;
    public class GetMethod {
    	public static void main(String[] args)throws Exception
    	{
    		String str="abcdefg";
    		Class c=String.class;
    		
    		Method[] m=c.getMethods();
    		//得到所有方法,包括父类的,但必须是被public修饰过的
    		
    		for(Method ms:m)
    		{
    			System.out.println("getMethods.."+ms);
    		}
    		Method m1=c.getMethod("replace", char.class,char.class);
    		//第一个参数是将要获取方法名,第二个参数是可变参数,是该方法的形参字节码
    		//该方法的作用是将字符串中的字符替换掉
    		str=(String)m1.invoke(str, 'a','b');
    		//invoke返回一个Object,要向下转型
    		//将a替换成b
    		System.out.println(str);
    		
    		m=c.getDeclaredMethods();
    		for(Method ms:m)
    		{
    			System.out.println("暴力获取..."+ms);
    		}
    		
    				
    	}
    }
    



    得到字段和反射下修改字段

    package JustTest;
    import java.lang.reflect.*;
    class Person
    {
    	public String name;
    	public int age;
    	private char sex;
    	Person(String name,int age,char sex)
    	{
    		this.name=name;
    		this.age=age;
    		this.sex=sex;
    	}
    }
    public class GetField {
    	public static void main(String[] args)throws Exception
    	{
    		Person p=new Person("张三",18,'m');
    		Class c=Person.class;
    		
    		Field[] fs=c.getFields();
    		//得到所有字段
    		for(Field f1:fs)
    		{
    			System.out.println("getFields..."+f1);
    		}
    		
    		Field f=c.getField("name");
    		//得到Person中的name字段
    		System.out.println(f.get(p));
    		//将p对象中的name字段值打印出来
    		f.set(p,"李四");
    		//将p对象中的name改成"李四"
    		
    		
    		Field f1=c.getDeclaredField("sex");
    		//强行指向sex字段
    		f1.setAccessible(true);
    		//设置访问权限
    		f1.set(p,'w');
    		//将私有化的sex修改
    		
    		System.out.println(f1.getChar(p));
    		
    		
    		
    		
    	}
    }
    



  • 相关阅读:
    在Linux中常用的启动引导工具:grub和lilo
    Linux的启动流程
    时间同步
    LINUX时区的设置
    Linux时间设置命令
    Linux时间介绍
    mysql特殊处理
    PHP 设计模式 笔记与总结(8)策略模式
    Java实现 LeetCode 172 阶乘后的零
    Java实现 LeetCode 172 阶乘后的零
  • 原文地址:https://www.cnblogs.com/lisisong/p/5122618.html
Copyright © 2011-2022 走看看