TwentyFiveDay-java 反射机制,注解
资源绑定器,便于获取属性配置文件中的内容
使用一下这种方式的时候,属性配置文件xxx.properties必须放在类路径下
ResourceBundle bundle=ResourceBundle.getBundle("类路径下的文件名")
//再写路径的时候。路径后面的扩展名不能写(tempfile03中写了user=username)
ResourceBundle bundle =ResourceBundle.getBundle("tempfile03");
String name=bundle.getString("user");
System.out.println(name);//username
2、类加载器(了解)
1>、什么是类加载器?
专门负责加载类的命令/工具
2>、类加载器的种类
启动类加载器,扩展类加载器,应用类加载器
3>、假设有这样一段代码
String s="asd";
代码在开始执行之前,会将所需要的类全部加载到JVM中。通过类加载器加载,看到以上代码类加载器会找String.class文件,找到就加载,那么是怎样加载的呢?
a、首先通过"启动类加载器"加载。
注意:启动类加载器专门加载jre下的rt.jar,jdk11以后都找不到jre文件了,rt.jar中都是JDK最核心的类库。
b、如果通过启动类加载器加载不到,就会用扩展类加载器加载jre下lib中的ext
c、如果扩展类加载器加载不到,则会通过应用类加载器,会专门加载classpath中的jar包(class文件)
4>、java为了保证类加载安全,使用了双亲委派机制,优先从启动类加载器加载,成为”父“,”父“无法加载到,再从扩展类加载器加载,称”母“,双亲委派,如果都加载不到,才会考虑从应用类加载器中加载,直到加载到为止。
3、使用反射机制获取Field
public static void main(String[] args) {
try {
//获取属性之前,需要获取类
Class cname = Class.forName("TwentyFiveDay.StudentClass");
//获取类名
String name = cname.getName();
System.out.println(name);//TwentyFiveDay.StudentClass
//获取简易类名
String sname=cname.getSimpleName();
System.out.println(sname);//StudentClass
//获得类的属性名
Field[] fields = cname.getDeclaredFields();
//测一下fields的长度
System.out.println(fields.length);//4
for (Field field : fields) {
//遍历输出类属性的修饰符 field.getModifiers()返回的是整型数字,代表的是修饰符的编号
int i=field.getModifiers();
//Modifier.toString(int i)方法把修饰符编号转换成对应的修饰符
String modifier= Modifier.toString(i);
System.out.println(modifier);
//遍历输出类属性的类型 field.getType()返回的是class类型的
System.out.println(field.getType().getSimpleName()+" ");
//遍历输出类的属性名
System.out.println(field.getName()+" ");//sno sname sclass age
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
4、使用反射机制给属性赋值,获取属性的值
public static void main(String[] args) throws Exception{
//使用new对象的方式
StudentClass studentClass=new StudentClass();
studentClass.age=12;
System.out.println(studentClass.age);
//使用反射机制获取对象,并给对象的属性赋值
//第一步获取StudentClass类
Class student=Class.forName("TwentyFiveDay.StudentClass");
//第二步给类创建一个对象
Object stu=student.newInstance();//底层调用无参构造方法创建对象
//第三步获取stu对象的其中一个公有属性
Field sno = student.getDeclaredField("sno");
//给sno赋值 .set(对象,值)方法
sno.set(stu,123);
//获取stu属性sno的值
Object o = sno.get(stu);
System.out.println(o);
//获取私有属性
Field sname = student.getDeclaredField("sname");
//私有属性的获取必须打破封装 这个是反射机制的缺点,打破封装外部也可以访问,不安全
sname.setAccessible(true);
//赋值
sname.set(stu,"jack");
//获取
System.out.println(sname.get(stu));
}
5、通过反射机制调用方法
public static void main(String[] args) throws Exception{
//new对象来调用方法
userServiceClass user=new userServiceClass();
boolean result=user.UserRegister("adim","123");
System.out.println(result?"登录成功":"登陆失败");//登录成功
//使用反射机制来调用方法
//第一步获取userServiceClass类
Class userService=Class.forName("TwentyFiveDay.userServiceClass");
//第二步创建对象
Object users=userService.newInstance();
//第三步获取方法
Method Register=userService.getDeclaredMethod("UserRegister", String.class, String.class);
//第四步调用方法
Object o = Register.invoke(users, "adim", "123");
System.out.println(o);//true
}
6、通过反射机制实例化对象
public static void main(String[] args) throws Exception{
//new对象来调用有参构造方法
AnimalClass animalClass=new AnimalClass();
AnimalClass animalClass1=new AnimalClass(001,"erha",2);
System.out.println(animalClass1);//AnimalClass{no=1, name='erha', age=2}
//通过反射机制来调用有参构造方法
//第一步获取AnimalClass类
Class animal=Class.forName("TwentyFiveDay.AnimalClass");
//第二步调用无参构造创建对象
Object animalObj=animal.newInstance();
//调用有参构造的步骤一:获取有参构造方法名
Constructor constructor = animal.getDeclaredConstructor(int.class, String.class, int.class);
//第二步:创建对象
Object bosi = constructor.newInstance(01, "bosi", 2);
System.out.println(bosi);//AnimalClass{no=1, name='bosi', age=2}
}
7、通过反射机制获取父类及接口
public static void main(String[] args) throws Exception{
//第一步获取这个类
Class string=Class.forName("java.lang.String");
//第二步获取父类
Class superclass = string.getSuperclass();
System.out.println(superclass.getName());
//第三步获取接口数组
Class[] interfaces=string.getInterfaces();
for (Class anInterface : interfaces) {
System.out.println(anInterface.getName());
}
}
8、注解
注解:又叫做注释,英文单词是:Annotation,它是引用类型,会编译为.class文件
注解可以出现在任何地方,注解上,方法上,类上,变量上,枚举,接口....
注解格式:修饰符 @interface 注解名{}
**需要掌握的Java.lang包下的注解:
@Deprecated的程序元素是程序员不鼓励使用的程序元素,通常是因为它是危险的,或者因为存在更好的替代方法。作用:表示被标注的东西已过时
@Override 表示方法声明旨在覆盖超类型中的方法声明,@Override:只能注解方法,这个注解是给编译器参考的,和运行阶段没有关系,凡是有这个注解,编译器都会进行检查,如果这个方法不是重写父类的方法,编译器报错。
**元注解:用来标注注解类型的注解
常用元注解:Target Retention
关于Target:用来标注”被标注的注解“只能出现在什么位置
@Target(ElementType.METHOD) :表示被标注的注解只能出现在方法上
关于Retention:用来标注”被标注的注解“最终保存在哪里
@Retention(RetentionPolicy.SOURCE):表示被标注的注解最终保存在java源文件中
@Retention(RetentionPolicy.CLASS):表示被标注的注解保存在class文件中
@Retention(RetentionPolicy.RUNTIME):表示被标注的注解保存在class文件中,并且可以让反射机制读取到
9、自定义注解
//自定义注解MyAnnotation
public @interface MyAnnotation {
//注解里可以写属性,看着像方法,我们称之为属性
String name();
//可以给属性赋默认值 这样在给其他方法或类注释的时候可不写
int age() default 1;
}
//自定义注解MyAnnotation01
注解里的属性类型都可以有哪些 可以是:byte,short,int,long,float,double,boolean,char,String,Class,enum类型及它们的数组形式
public @interface MyAnnotation01 {
Weather[] value();
}
//enum枚举
public enum Weather {
SNOW,SUN,RAIN,CLOUDY
}
//自定义注解MyAnnotation02
使用元注解,标注 MyAnnotation02注解只能标注类与方法
@Target({ElementType.METHOD,ElementType.TYPE})//省略了value,只允许该注解标注方法与类
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation02 {
String[] value();
}
//测试注解类AnnotationTest01
//自定义的注解,里面可以有属性,但是若不是default了值,就需要写出来如name属性,age已经设置了默认值可不写
@MyAnnotation(name="自定义注解",age=2)
public class AnnotationTest01 {
//@Override
public String toString() {
return "AnnotationTest01{}";
}
//@Deprecated//表示已过时
public static void method(){
}
}
//测试注解类A
class A{
//注解里只有value一个属性,可以省略”value=“,value属性是一个枚举数组类型,写法如下:
@MyAnnotation01({Weather.CLOUDY,Weather.RAIN})
public static void main(String[] args) {
AnnotationTest01.method();//已过时
}
}
10、使用反射机制获取注解
前提是这个注解已被Retention(RetentionPolicy.RUNTIME)注释,才可以用反射机制读取到
代码:
//创建一个类,被MyAnnotation02注释
@MyAnnotation02({"注解"})
public class AnnotationTest02 {
public static void main(String[] args) {
}
}
//通过反射机制获取AnnotationTest02上的注解
public static void main(String[] args) {
try {
//第一步获取类
Class annotation=Class.forName("TwentyFiveDay.AnnotationTest02");
//判断AnnotationTest01有没有MyAnnotation02注解(这个注解必须是反射机制可以读取的!!!)
if(annotation.isAnnotationPresent(MyAnnotation02.class)){
//获取MyAnnotation02的对象an
MyAnnotation02 an = (MyAnnotation02)annotation.getAnnotation(MyAnnotation02.class);
//获取注解对象的属性
String[] value = an.value();
System.out.println(value[0]);//注解
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
11、注解作用的练习
自定义一个ID注解,这能标注类,作用是被标注的类必须有整型id属性,若是没有则报错“此类必须有整型id属性”;
//@ID
//这个注解只能标注类
@Target(ElementType.TYPE)
//这个注解可以被反射机制读取
@Retention(RetentionPolicy.RUNTIME)
public @interface ID {
}
//user类
@ID
public class UserClass {
//int id;
String name;
}
//自定义异常类
//没有id整型属性异常
public class HasnotIDException extends RuntimeException {
public HasnotIDException() {
}
public HasnotIDException(String s){
super(s);
}
}
//规定ID注解作用类
public static void main(String[] args) throws Exception {
//获取UserClass类
Class user=Class.forName("TwentySixDay.UserClass");
//给个默认布尔型
boolean b=false;
//属性集
Field[] fields=user.getDeclaredFields();
//判断有没有@ID注释
if(user.isAnnotationPresent(ID.class)) {
//有注释,则遍历属性集
for (Field field : fields) {
//判断有没有整型id属性
if("id".equals(field.getName())&&"int".equals(field.getType().getSimpleName())){
//如果走到这,则程序正常
b=true;
}
}
}
if(!b){
throw new HasnotIDException("此类必须有整型id属性!");
}
}
浙公网安备 33010602011771号