2021-11-08反射java

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不能省略


版权声明:本文为weixin_44681177原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。