一.简介
1.类加载
将class文件读取到内存中的过程,称为类加载
class文件的加载由ClassLoader完成-----类加载器
类加载器三种类型:
* BootStrapClassLoader:启动类加载器,用C++写,主要负责加载%JAVA_HOME%/jre/lib路径下的类
* ExtClassLoader:扩展类加载器,主要负责加载%JAVA_HOME%/jre/lib/ext路径下的类
* AppClassLoader:系统类加载器,主要负责加载classpath路径下的类(对于Eclipse来说,就是项目路径/bin)
* 类名.class.getClassLoader()获取当前类的类加载器
class文件读取内存中会被封装为一个 Class类对象
2.反射
* 对于任意一个类可以获取这个类的属性和方法
* 对于任意一个对象可以调用这个对象的属性和方法
在运行时动态的获取信息以及调用对象的方法的功能称为反射 - reflection
3.相关API
反射相关的类或接口都java.lang包
类/接口 | 作用 |
Class | 表示运行中的类和接口 |
Field | 表示类中的属性 |
Method | 方法 |
Constructor | 构造方法 |
Package | 包 |
Modifier | 修饰符 |
Parameter | 参数 |
Annotation | 注解 |
二.Class对象
1.简介
运行中的class文件通过Class对象来表示
* Class对象在类加载时由JVM自动创建,一个类对于一个Class对象
* Class类没有公共的构造方法,不能自己创建class对象,但可以获取实例
* Class是反射的核心,要操作类中的属性和方法,必须先获取Class对象
2.获取class对象三种方式
1. 调用对象的getClass()方法
2. 调用对象的class属性
3. 调用Class类中的forName()静态方法
// getClass()方法
Card card = new Card();
Class<? extends Card> class1 = card.getClass();
System.out.println(class1);
// 类名.class
Class card2=Card.class;
System.out.println(card2);
// Class.forName("包名+类名")
Class<?> card3 = Class.forName("ten_first.Card");
System.out.println(card3);
3.常用方法
Class card=Card.class;
// 获取类中的信息
System.out.println("全类名:"+card.getName());
System.out.println("简单类名:"+card.getSimpleName());
System.out.println("是否为接口:"+card.isInterface());
// 获取父类信息
Class superclass = card.getSuperclass();
System.out.println("父类名字:"+superclass.getName());
// 获取接口
Class[] interfaces = card.getInterfaces();
for (Class c : interfaces) {
System.out.println(c+" ");
}
// 获取修饰符
int modifiers = card.getModifiers();//以常量代替修饰符
System.out.println("修饰符:"+Modifier.toString(modifiers));
// 获取包
Package package1 = card.getPackage();
System.out.println("包:"+package1);
// 调用无参构造方法————通过反射的方式创建对象
Object newInstance;
try {
newInstance = card.newInstance();
System.out.println(newInstance);
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
输出:
全类名:ten_first.Card
简单类名:Card
是否为接口:false
父类名字:ten_first.Paper
interface java.io.Serializable
interface java.lang.Cloneable
修饰符:public
包:package ten_first
card [name=null, id=0]
三.反射的操作
模板操作:获取所有+获取指定单个+其他
1.操作Field(属性)
Class tea=Tea.class;
// 1.1获取当前类以及父类中所有public修饰的属性
Field[] fields = tea.getFields();
// 1.2获取当前类以及父类中所有修饰的属性
fields =tea.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName()+" "+field.getType()+" "+
Modifier.toString(field.getModifiers())+"\t");
}
// 2获取当前指定的属性
Field price = tea.getField("price");//public
Field num = tea.getDeclaredField("number");//private
// 3对于一个实例 用反射为属性赋值 属性.set(对象,值)
Tea puer = new Tea();
num.setAccessible(true);//私有需要先取消检查设置 取消修饰的作用
num.set(puer,12);
price.set(puer,1.9);
// 4属性.get(对象)=值
Object object = num.get(puer);
System.out.println(object);
Object object2 = price.get(puer);
System.out.println(object2);
2.操作Method(方法)
Class tea=Tea.class;
// 1.获取当前类和父类的方法
Method[] methods = tea.getMethods();//public
methods=tea.getDeclaredMethods();//含private
for (Method m : methods) {
System.out.println(m.getName()+"\t"+m.getReturnType()+"\t"+
m.getModifiers()+Arrays.toString(m.getParameters()));
}
// 2.指定获取方法
Method m1 = tea.getMethod("a");//public
Method m2 = tea.getDeclaredMethod("b",int.class);//private
Method m3 = tea.getMethod("b",int.class,int.class);// (参数名,参数列表)
// 3.通过反射调用方法 只能调用public的方法 除非去除限制
Tea iron = new Tea();
m3.setAccessible(true);
Object invoke = m3.invoke(iron,1,2);
System.out.println(invoke);//方法的返回值
public void a() {
}
private void b(int x) {
}
public int b(int x,int y) {
System.out.println("参数1"+x+"参数2"+y);
return x+y;
}
3.操作Constructor(构造方法)
Class tea=Tea.class;
// 1.1获取构造方法 public修饰
java.lang.reflect.Constructor[] consructor=tea.getConstructors();
// 1.2获取构造方法 所有的 包含private修饰
consructor= tea.getDeclaredConstructors();
for (java.lang.reflect.Constructor c: consructor) {
System.out.println(c);
}
// 2.获取指定的构造方法 仅public/public+private
java.lang.reflect.Constructor c1 = tea.getConstructor(int.class,int.class);
java.lang.reflect.Constructor c2 = tea.getDeclaredConstructor(int.class);
// 通过反射调用构造方法 相当于new对象
c1.setAccessible(true);//此处一个参数的构造方法是private 需要先破除限定
Object t1 = c1.newInstance("20");
// 直接通过Class对象 调用构造 #常用方法中提及
Object t2 = tea.newInstance();
四.注解
1.简介
Annotation相当于一种标识,是一种新的类型,与类,接口,枚举同一个层次
语法:@xxx,可以声明在类,属性,方法,参数等前面
用来表示一些特定的功能
2.JDK自带的注解
@override | 标记在方法前面,该方法是重写父类的方法
@SuppressWarnings | 关闭警告信息
3.自定义注解
语法:
//元注解
public @interface Test_注解 {
//抽象方法
}
public @interface MyAnnotation {
int a();
String b();
boolean[] value();
int e() default 000;
}
@MyAnnotation(a = 0, b = "ddd", value = { false })
元注解:标注在注解上的注解
注解 | 作用 |
@Target | 定义注解的作用域,可以用来标记在那些元素,通过ElementType来取值,不填,默认表示可以声明在任何元素 |
@Retention | 定义注解的声明周期 通过枚举@RetentionPolicy来取值 |
@Documented | 生成API文档时,包含该注解 |
@Inherited | 子类可以继承父类的注解 |
@Target 的取值:
* type: 类和接口
* field :属性
* method 方法
* PARAMETER 参数
* CONSTRUCTOR 构造
@Retention的取值:
* RUNTIME 注解可以保存在整个程序运行期间
* SOURCE 只放在源文件中,不参与编译,class文件没有
* CLASS 参与编译,但类加载时不能加载,程序运行时没有
4.使用自定义注解
语法: @注解名(属性名=属性值,属性名= 属性值)
在使用注解时需要为注解中的抽象方法指定返回值,称为:为注解指定属性值
属性名就是注解类中的方法名
1.返回数组c={a,b,c} 如果数组中仅一个元素 可省略大括号
2.注解中可以写抽象方法 必须无参无异常 使用时需要传入返回值(all)
3.注解中 void d();错误的 必须要有返回值
4.使用时:不需要赋值时@MyAnnotation 省略()
5.String e() default "eee" 使用default为方法指定返回值 使用注解时 不需要传入值
6.int value(); 仅方法名为value 使用-传入参数值时:可省略属性名=结构 @MyAnnotation(555)
5.注解上的反射
Class user=User.class;
// 1.获取类上的注解
Annotation[] a1 = user.getAnnotations();
// 没有显示由于@Rentenion(RentenionPolicy.SOURCE) 没有class文件
for (Annotation a : a1) {
System.out.println(a);
}
Annotation myannotation = user.getAnnotation(MyAnnotation.class);
System.out.println(myannotation);
// 2.获取属性上的注解
Field field = user.getDeclaredField("age");
Annotation[] a2 = field.getAnnotations();
// 3.获取方法上的注解
Method method = user.getMethod("way");
MyAnnotation a3 = method.getAnnotation(MyAnnotation.class);
// 4.通过反射获取注解的属性值 用注解对象.方法名
System.out.println(a3.value());
System.out.println(a3.e());//赋默认值
这是一边看视频一边学习的笔记-借用了部分老师的笔记内容-如有侵权,通知删除!
新手小白学习之路~~~