java.lang.reflect.*; 这个包下
java.lang.Class;代表整个字节码,代表一个类型
java.lang.reflect.Field; 代表字节码中的属性字节码,类中的属性
java.lang.reflect.Method; 代表字节码中的方法字节码,类中的方法
java.lang.reflect.Constructor; 代表字节码中的构造方法字节码 ,类中的构造方法
第一种方法
Class c1 = Class.forName("java.lang.String"); c1代表String.class String这个类
Class c2 = Class.forName("java.lang.Integer"); c2 代表Integer这个类
Class c3 = Class.forName("java.util.Date"); c3代表Date这个类
Class c4 = Class.forName("java.lang.System"); c4代表System这个类
第二种方法
String s = "abc";
Class s2 = s.getClass(); 这里得到的s2和第一种方法中的c1,是同一个String.class文件,
class文件加载到JVM的时候,只装载一份
第三种方法
Class dd = Date.class; //根据类型的class属性获取。
Class c = Class.forName("com.abc.User");
c.newInstance();// 调用User的无参构造方法,生成对象。
OCP原则(开闭原则),对扩展开放,对修改关闭
如果只希望类的静态代码块执行,可以使用 Class.forName();,这个方法会导致类加载
类路径
在src下的都是类路径,src是类的根路径
//获取文件的绝对路径 这里的abc文件在src下面 String path = Thread.currentThread().getContextClassLoader().getResource("abc").getPath();
这里的abc在src/com/aa/bb下面
String path = Thread.currentThread().getContextClassLoader().getResource("com/aa/bb/abc").getPath();
直接以流的方式返回
Thread.currentThread().getContextClassLoader().getResourceAsStream("abc.properties");
这里的abc.properties在src下面
java.util.ResourceBundle类 快速绑定属性文件,只能绑定 .properties文件
ResourceBundle b = ResouceBundle.getBundle("这里的文件必须是properties,并且必须在类路径下");如 src/aa.properties 则写成 参数不能带properties
ResourceBundel bundel = ResouceBundle.getBundle("aa");
bunde.getString("key");
如果在src/com/bb.properties 则如下 ResouceBundle.getBundle("com/bb");
类加载器
代码在执行之前,会将所需要的类加载到jvm中,通过类加载器加载,先通过启动类加载器加载,
1.启动类加载器 ;这里加载 lib/rt.jar 里面的class,rt.java是JDK的最核心的类库,如果这里找不到,则通过 扩展类加载器 加载,扩展类加载器加载不到,则 通过 应用类加载器加载
2.扩展类加载器 这里加载 lib/ext/*.jar 里面的class
3.应用类加载器 这里加载classpath下的class
如果我们也写了一个String类,则不会加载我们的String类,
java为了保证类加载的安全,启用了双亲委派机制。
【启动类加载器】----》父加载器
【扩展类加载器】----》母加载器
Field
User{
int age; //这是一个Field对象
private String name; //这是一个Field对象
protected boolean flag; public Date bithday;
}
Class c = Class.forName("com.abc.User");
Field[] fields = c.getFields(); 获取User类中所有的public修饰的属性 数组长度为1
Field[] fs = c.getDeclaredFields(); 获取User类中所有的属性 数组长度为4
根据类名反编译得到类的属性
StringBuilder sb = new StringBuffer(); Class ccc = Class.forName("java.lang.String"); String mo = Modifier.toString(ccc.getModifiers()); //sb.append(mo); sb.append(mo + " class "); sb.append(ccc.getSimpleName() +"{\n"); for(Field field:ccc.getDeclaredFields()){ sb.append("\t"); sb.append(Modifier.toString(field.getModifiers())+" "); sb.append(field.getType().getSimpleName() + " "); sb.append(field.getName()); sb.append(";\n"); } sb.append("}"); System.out.println(sb);
给Field 赋值,取值
Class c = Class.forName("com.abc.haha");
Object obj = c.newInstance();
Field nameField = c.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(obj,"1234");
System.out.println(nameField.get(obj));
可变长参数
public static void (int arg,String ... aa);
可变长度参数只能出现在最后面,只能有一个,可变长度参数,可以当做一个数组
Method
Class c = Class.forName("java.lang.String");
Method[] methods = c.getDeclareMethods();
for(Method m : methods){
m.getName(); //方法名
m.getReturnType(); //方法返回类型
m.getModifiers();
Modifier.toString(m.getModifiers()); //方法的修饰符
Class[] cc = m.getParametersTypes(); //方法的参数,返回的是Class【】 数组
cc.getSimpleName(); }
StringBuffer sb = new StringBuffer();
Class c = Class.forName("com.abc.reflect.UserService"); sb.append("\t"); sb.append(Modifier.toString(method.getModifiers() + " "); sb.append(c.getSimpleName() for(Method method:c.getDeclaredMethods()){ System.out.println(Modifier.toString(method.getModifiers())); System.out.println(method.getReturnType()); System.out.println(method.getName()); for(Class cc:method.getParameterTypes()){ System.out.println(cc.getName()); } }
Class c = Class.forName("com.abc.reflect.UserService"); StringBuilder sb = new StringBuilder(); sb.append("\t"); sb.append(Modifier.toString(c.getModifiers())); sb.append(" class "); sb.append(c.getSimpleName()); sb.append("{\n"); for(Method method:c.getDeclaredMethods()){ sb.append("\t"); sb.append(Modifier.toString(method.getModifiers())); sb.append(" "); sb.append(method.getReturnType()); sb.append(" "); sb.append(method.getName()+"("); for(Class cc:method.getParameterTypes()){ sb.append(cc.getSimpleName()); sb.append(","); } sb.deleteCharAt(sb.length()-1); sb.append("){}\n"); } sb.append("}"); System.out.println(sb.toString());
Method m = c.getDeclaredMethod("login",String.class,String.class);
Object o = c.newInstance();
m.invoke(o,"123","abc"); //调用方法
Constructor
Class cc = Class.forName("com.laodu.Reflect.UserService"); StringBuilder sb = new StringBuilder(); sb.append(Modifier.toString(cc.getModifiers()));//获取类的修饰符 sb.append(" class "); sb.append(cc.getSimpleName()+"{\n"); for(Constructor constructor:cc.getDeclaredConstructors()){ sb.append(Modifier.toString(constructor.getModifiers())); sb.append(" "); sb.append(cc.getSimpleName()); sb.append("("); for(Class dd:constructor.getParameterTypes()){ sb.append(dd.getSimpleName()); sb.append(","); } if(constructor.getParameterCount()>0){ sb.deleteCharAt(sb.length()-1); } sb.append(");\n"); sb.append("}"); }
注解
public @interface MyAnnotation{}
元注解
@Target,用来标注被标注的注解能出现在哪个地方
@Retention(
@Retention(RetentionPolicy.SOURCE) 表示该注解只被保留到源码
@Retention(RetentionPolicy.CLASS) 该注解被保存到CLASS文件
@Retention(RetentionPolicy.RUNTIME) 该注解被保存到CLASs文件,并且可以被反射机制所读取
@Override 重写
@Deprecated 已过时 这个注解标注的元素已过时
public @interface MyAnnotation{
String name(); 如果注解有属性,则使用注解是必须给属性赋值
int age() default 100;
String value();
}
@MyAnnotaion(name="123")
class A{
}
//在注解中只有一个value属性时,使用该注解是可以省略value,在注解中有一个value属性,但是还有其他属性时,使用该注解时value不可以省略。
注解中的属性的类型
int,byte,short,long,double,float,boolean,char,enum,Class,及这些类型的数组
如 enum TTTT{
SPRING,SUMMER,WINNTER;}
public @interface MyAnno{
int value;
int[] haha; //数组使用大括号括起来
TTTT t;
TTTT[] tt;//数组使用大括号括起来
}
使用该注解的方式
@MyAnno(value=1,haha={1,2,3},t=TTTT.SPRING,tt={TTTT.SPRING,TTTT.SUMMER})
如果数组中只有一个元素时,大括号可以省略
Class c = Class.forName("com.laodu.Reflect.MyAnnotationClass"); System.out.println(c.isAnnotationPresent(MyAnnotation.class)); if(c.isAnnotationPresent(MyAnnotation.class)){//是否有Myannotation注解修饰在类上 MyAnnotation annotation = (MyAnnotation) c.getAnnotation(MyAnnotation.class);//需要强转 System.out.println(annotation.value()); //获取注解上配置的属性 } Field field = c.getDeclaredField("name"); System.out.println(field.isAnnotationPresent(MyAnnotation.class)); if(field.isAnnotationPresent(MyAnnotation.class)){//是否有Myannotation注解修饰在属性上 MyAnnotation annotation = field.getAnnotation(MyAnnotation.class); System.out.println(annotation.value()); } Method method = c.getDeclaredMethod("f"); if(method.isAnnotationPresent(MyAnnotation.class)){//是否有Myannotation注解修饰在方法上 MyAnnotation annotation = method.getAnnotation(MyAnnotation.class); System.out.println(annotation.value()); }
如果注解中只有一个value属性,则在使用注解时,可以省略value的名字
如果注解中有多个属性,则每个属性在使用时都不可以省略掉属性的名字
注解中的属性为数组时,如果数组的元素个数为1,则可以省略大括号,如果数组元素个数大于1,不能省略大括号。如
public @interface ccc{
String value() default "100";
int num();
String[] hehe;}
则在使用ccc注解时,
@ccc(value="1",num=20,hehe={"ab","ac"}) 这里的value可以省略掉,因为有default,num和hehe不能省略