反射
反射是程序在运行时能够获取自身的信息。
优点
运行时确定类型,绑定对象。动态编译最大发挥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
}
}
得到构造方法和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));
}
}